前面咱们聊了 Elasticsearch 的索引、搜索和分词器,今天再来聊另外一个基础内容—— Mapping。html
Mapping 在 Elasticsearch 中的地位至关于关系型数据库中的 schema,它能够用来定义索引中字段的名字、定义字段的数据类型,还能够用来作一些字段的配置。从 Elasticsearch 7.0开始,Mapping 中不在意须要定义 type 信息了,具体缘由能够看官方的解释。数据库
咱们刚刚提到 Mapping 中能够定义字段的数据类型,这多是 Mapping 最经常使用的功能了,因此咱们先来看看 Elasticsearch 都支持哪些数据类型。数组
Elasticsearch 支持的数据类型远不止这些,因为篇幅缘由,这里就不一一列举了。我找几个工做中常见的来介绍一下。bash
首先就是字符串了,Elasticsearch 中的字符串有 text 和 keyword 两种。其中 text 类型的字符串是能够被全文检索的,它会被分词器做用,session
PUT my_index { "mappings": { "properties": { "full_name": { "type": "text" } } } }
在设置字段类型为 text 时,还能够利用一些参数对这个字段进行更进一步的定制。app
index
:标记这个字段是否能被搜索,默认是 trueelasticsearch
search_analyzer
:被搜索时所使用的分词器,默认使用 setting 中设置的分词器ide
fielddata
:字段是否容许在内存中进行排序、聚合,默认是 falseui
meta
:关于字段的一些元数据code
像一些id、邮箱、域名这样的字段,咱们就须要使用 keyword 类型了。由于 keyword 类型能够支持排序、聚合,而且只能支持精确查询。
有些同窗可能会把 ID 设置为数字类型,这也是没问题的,数字类型和 keyword 各有各的好处,使用数字类型能够进行范围查找,而使用 keyword 类型则有更高的查询效率。具体用哪一种还要看使用场景。
日期类型在 Elasticsearch 中有三种表现形式
"2020-07-26"
和"2015/01/01 12:10:30"
这样的在 Elasticsearch 内部,日期类型是以 long 类型的毫秒级时间戳存储的,时区使用的是0时区。
咱们能够自定义时间格式,默认使用的是strict_date_optional_time||epoch_millis
strict_date_optional_time_nanos是通用的日期格式解析,至少要包含年份,若是要包含时间,则用T
分隔,例如yyyy-MM-dd'T'HH:mm:ss.SSSSSSZ
或 yyyy-MM-dd
。
若是想要同时支持多种日期格式,可使用format
字段
PUT my_index { "mappings": { "properties": { "date": { "type": "date", "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" } } } }
刚才咱们提到配置 Mapping 的日期格式的参数format
,Mapping 还提供了不少其余的参数。
咱们来介绍几个经常使用的字段。
首先是fields
,它可使同一个字段经过不一样的方式实现不一样的目的。
例如,咱们能够对一个字符串字段设置为text
类型,用于全文检索,同时能够利用fields
设置为keyword
类型,用于排序和聚合。
PUT my-index-000001 { "mappings": { "properties": { "city": { "type": "text", "fields": { "raw": { "type": "keyword" } } } } } }
查询时咱们就可使用city
进行全文检索,使用city.raw
进行排序和聚合。
GET my-index-000001/_search { "query": { "match": { "city": "york" } }, "sort": { "city.raw": "asc" }, "aggs": { "Cities": { "terms": { "field": "city.raw" } } } }
有些时候,咱们只想把某个字段做为数据存储来使用,并不须要用来作搜索,这时,咱们就能够将这个字段禁用掉,字段被禁用之后,它所保存的值也不受 mapping 指定的类型控制。
PUT my-index-000001 { "mappings": { "properties": { "user_id": { "type": "keyword" }, "last_updated": { "type": "date" }, "session_data": { "type": "object", "enabled": false } } } }
上面的例子中,咱们禁用掉了 session_data
这个字段,这时,你既能够往 session_data
字段中存储 JSON 格式的数据,也能够存储非 JSON 格式的数据。
除了针对于单个字段的禁用之外,咱们还能够直接禁用掉整个 mapping。咱们来从新建立一个index
PUT my-index-000002 { "mappings": { "enabled": false } }
这时,文档全部的字段都不会被索引,只是用来存储。
须要注意的是,不管是具体字段中仍是整个 mapping 的 enabled 属性都不能够被修改,由于一旦设置为 false,Elasticsearch 就不会对字段进行索引了,也不会校验数据的合法性,若是产生了脏数据之后再设置为 true,就会形成程序错误。
null 在 Elasticsearch 中是不能够被索引或搜索的,这里咱们所说的 null 并非狭义上某种语言的 null,而是全部的空值。例如全部值都是 null 的数组,总之,这里的定义就是没有值。
对于有须要搜索空值的业务怎么办呢?Elasticsearch 为咱们提供了 null_value
这个参数,它能够指定一个值,搜索时使用这个值来替代空值。
举个栗子
PUT my-index-000001 { "mappings": { "properties": { "status_code": { "type": "keyword", "null_value": "NULL" } } } }
咱们给 status_code
字段设置了 null_value
为 "NULL"
。这里须要注意, null_value
的类型必须与要查找的数据类型相同,若是在这个例子中 status_code
的类型是long,那么就不能把null_value
设置为 "NULL"
。
对于新增长的字段:
_source
中对于已有的字段,一旦已经有数据写入,就再也不支持修改字段定义
咱们在建立索引时,能够不用手动写 Mappings, Elasticsearch 会帮咱们自动识别出字段的类型。咱们称之为 Dynamic Mapping。不过有时推算的可能不是很准确。
Elasticsearch 自动识别类型是基于 JSON 的。数据类型的对应关系以下(表格来自 elastic 官网)
JSON data type | Elasticsearch data type |
---|---|
null |
No field is added. |
true or false |
boolean field |
floating point number | float field |
integer | long field |
object | object field |
array | Depends on the first non-null value in the array. |
string | Either a date field (if the value passes date detection), a double or long field (if the value passes numeric detection) or a text field, with a keyword sub-field. |
Elasticsearch 支持的字段映射的数据类型在这个文档中,除了这些,其余的类型映射都须要显示的指定了。
关于日期类型,默认是能够映射的,可是 Elasticsearch 只能识别几种格式的日期yyyy/MM/dd HH:mm:ss||yyyy/MM/dd||epoch_millis
。若是关掉了 date_detection
开关,那么就只能识别为字符串了。
PUT my-index-000001 { "mappings": { "date_detection": false } }
固然,你也能够根据须要本身指定要识别的日期格式,只须要使用 dynamic_date_formats
参数便可。
PUT my-index-000001 { "mappings": { "dynamic_date_formats": ["MM/dd/yyyy"] } }
Elasticsearch 还提供了一种把字符串型的数字识别为数字的能力,它是由 numeric_detection
开关控制的。
PUT my-index-000005 { "mappings": { "numeric_detection": true } } PUT my-index-000005/_doc/1 { "my_float": "1.0", "my_integer": "1" }
在这个例子中,my_float
会被识别为 float 类型,而 my_integer
会被识别为 long 类型。
dynamic template 容许咱们自定义 mapping ,并应用到具体索引上。dynamic template 的定义通常是这样的
"dynamic_templates": [ { "my_template_name": { ... match conditions ... "mapping": { ... } } }, ... ]
my_template_name
能够是任意字符串。
match conditions
包括match_mapping_type
, match
, match_pattern
, unmatch
, path_match
, path_unmatch
这几种。
mapping
就是指匹配到的字段应该使用怎样的 mapping。下面咱们介绍几种 match conditions
咱们先来看一个简单的例子
PUT my-index-000001 { "mappings": { "dynamic_templates": [ { "integers": { "match_mapping_type": "long", "mapping": { "type": "integer" } } }, { "strings": { "match_mapping_type": "string", "mapping": { "type": "text", "fields": { "raw": { "type": "keyword", "ignore_above": 256 } } } } } ] } }
这里咱们有两个模版,其一是使用 integer
类型来代替 long
类型,其二是将字符串类型映射为 keyword
。
这两个比较简单,match 是指匹配到模式的字段, unmatch 是表示不匹配的字段。
PUT my-index-000001 { "mappings": { "dynamic_templates": [ { "longs_as_strings": { "match_mapping_type": "string", "match": "long_*", "unmatch": "*_text", "mapping": { "type": "long" } } } ] } }
在这个例子中,咱们须要的是 long_
开头的字符串,不须要 _text
结尾的字符串字段。
除了以上三种以外,其余的就是 match_pattern
用来进行正则匹配,path_match
和 path_unmatch
则是表示字段所在路径的是否匹配。
另外 dynamic template 还支持两种变量替换,分别是 {name}
和 {dynamic_type}
。其实 name 就是字段名,dynamic_type 就是检测出的字段类型。
关于 Elasticsearch 的 mapping 咱们就先聊这些,我认为 mapping 的配置是一个须要经验的事情,当你处理的 case 愈来愈多以后,就能比较轻松的知道如何更好的配置 mapping 了。此外,mapping 的许多字段和参数文中都没有涉及,对于我而言,大部分都是用到了现查文档,不过也仍是建议你们看一看文档,起码遇到问题时能知道大概查找文档的一个方向。这样就会比身边人强很多。