在 ES 中所有的字段都是由映射规则所控制,这将输入的数据信息转化成对应的数据格式来进行索引或保存。配置合理的映射规则有助于维护文档,增加操作效率。在了解映射相关配置之前需要了解一下 ES 的数据类型和元字段的意义。
字段类型
- text
文本类型,十分常用的类型,通常作用于需要被全文检索的字段上。这样的字段内容会被分词器拆成词项后生成倒排索引,它不用于排序,也很少用于聚合。 - keyword
关键字类型,通常用于索引结构化的字段(通常意义明确,用于过滤),这样的字段只能被精确搜索。 - number
数字类型,这是一个概括。其中包含了byte
,short
,integer
,long
,float
,double
,half_float
,scaled_float
。除了和 Java 类似的数字类型以外,还有相对于float
精度折半的half_float
,以及将浮点数进行缩放后存储的scaled_float
。字段长度越短,空间分配越合理,搜索效率越高。注意在浮点数中+0.0
与-0.0
是不同的存在。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16# 设置某字段为 scaling_float,缩放因子 100
# 适合存储精确至小数点后两位的数字,底层对数字扩大 100 做整形存储
# 而对 API 为 float 型
PUT /<索引>
{
"mappings": {
"<类型>": {
"properties": {
"<字段名称A>": {
"type": "scaled_float",
"scaling_factor": 100
}
}
}
}
} - date
日期类型,ES 支持日期格式化后的字符串、从 epoch 开始的毫秒数(长整型)、从 epoch 开始的秒数(整形),在 ES 内部,日期都会转化为 UTC 时间并存储为从 epoch 开始的毫秒数。在开启动态映射的时候如果有新的字段被添加,默认会自动进行日期检测以判断是否该字段为日期类型(可以被关闭,将某类型的date_detection
选项设置为 false)。同时日期格式也支持自定义(通过制定字段的format
选项,默认为 *strict_date_optional_time || epoch_millis),除了 *yyyy-MM-dd HH:mm:ss 这样的个性格式,其他预置的格式枚举很多,详情查看官方文档。 - boolean
布尔类型,只接受true
和false
。 - binary
二进制类型,该类型字段仅接受 Base64 编码后的字符串,字段默认不存储(store=false)也不搜索。 - array
数组类型,其本身是其他类型。数组中的所有值必须为统一类型(可以包含 null),而空数组由于无法确定类型会被作为 missing field 对待。在动态映射时,第一个加入数组的元素会决定整个数组的数据类型。 - object
对象类型。在 JSON 中,对象是可以包含层级关系的,但是在 ES 中复合的对象会被扁平化处理,成为简单的 k-v 键值对。如果需要在建立索引时进行静态映射,mappings 支持 object 的显示映射。 - nested
嵌套对象,这是 object 类型的特例,支持 object 对象数据的独立索引和查询(ES 在使用对象类型的数组时由于扁平化处理会导致一些索引问题)。当指定了 nested 类型进行索引某个字段时,该字段会内容会作为独立的隐藏文档存在。这样支持了嵌套对象的索引,但是由于类似结构化数据的关联查询一般,nested 字段越多,搜索越复杂,所以每个索引可以使用嵌套对象被限制在 50。 - geo_point
地理坐标,用来精确存储地理经纬信息的类型,支持 4 中写入方式:- 经纬坐标字符串,如:
"40.3,116.17"
- 经纬坐标键值对,如:
{"lat": 40.3, "lon": 116.17}
- 地理位置哈希值,如:
"drm3btev3e86"
- 经纬坐标数组,如:
[40.3, 116.17]
- 经纬坐标字符串,如:
- geo_shape
地理区块,使用 GeoJSON 对区块进行编码,描述一块地理区域,支持点线面等多种特征。一下列举集中典型表达,更多使用方案参数 GeoJSON 相关文档:
GeoJSON 类型 | ES 类型 | 说明 |
---|---|---|
Point | point | 精确坐标点 |
LineString | linestring | 线条,多个点组成 |
Polygon | polygon | 封闭多边形,多个点组成 |
MultiPoint | multipoint | 多个不连续但可能关联的点 |
MultiLineString | multilinestring | 多条不关联的线 |
MultiPolygon | MultiPolygon | 多个不关联的多边形 |
GeometryCollection | geometrycollection | 集合对象集合,可以包括点线面 |
N/A | envelope | 由左上右下坐标确定的封闭矩形 |
N/A | circle | 圆心和半径确定的圆,单位米 |
在使用 geo_shape 类型之后,插入文档时指定字段必须明确 Geo 类型和数据,如:
1 | PUT /<索引>/<类型>/<编号> |
- ip
ip 类型,可以保存 ip 地址,支持 IPv4 及 IPv6,以及无类型域间选路格式 - range
范围类型,支持integer_range
,long_range
,float_range
,double_range
,date_rage
。其中日期区间以毫秒计时。在某字段使用 rage 类型之后,插入数据需要指定对应的范围,可以使用gt
、lte
等关键字描述。 - token_count
词项统计类型,其本身是一个整形。一般用来给某个属性增加附加字段并指定 token_count 来统计词项长度。词项长度取决于具体内容和指定的分词器。
元字段
元字段描述了文件本身的属性,是 ES 内置的。总的来看元字段描述了从文档属性、源文档、索引、路由等相关信息,同时也支持自定义元字段。这些元字段支持部分的查询方式和脚本。
元字段 | 元字段分类 | 意义 |
---|---|---|
_index | 文档属性 | 描述文档所属的索引 |
_type | 文档属性 | 描述文档的类型 |
_id | 文档属性 | 描述文档的编号 |
_uid | 文档属性 | 包含_type及_id |
_source | 源文档属性 | 文档原始的JSON资料 |
_size | 源文档属性 | 描述源文档的大小,需要插件 mapper-size |
_all | 索引属性 | 包含索引中全部的字段的内容,用来泛检索 |
_field_names | 索引属性 | 包含所有不存在空值的字段名 |
_parent | 路由属性 | 指定文档间的父子关系 |
_routing | 路由属性 | 用来设定文档进行路由的自定义值 |
_meta | 自定义 | 自定义的元数据 |
映射参数
在设置索引的映射时候,有一些针对索引、类型或者具体文档属性的参数可以选择性调整。语法:
1 | PUT /index_name |
以上的命令也可以简化使用 _mapping API:
1 | PUT /index_name/_mapping/type_name |
接下来是一些可配置项:
- analyzer
分词器选项,针对文档属性,调整对应字段的默认分词器,会影响文档的索引以及查询(未指定 search_analyzer 时)。 - search_ananlyzer
查询分词器选项,针对文档属性,仅查询生效,可以覆盖 analyzer 选项。 - normalizer
标准化配置,针对文档属性,用于属性值在解析前的预处理。对某属性使用的标准化配置需要在设置时配置好。 - boost
权重,针对文档属性,默认值为1
,可以手动通过该选择项改变关键字在某属性中出现时的权重。但是在映射配置中设定 boost 后如果不重新索引文档是无法改变权重的,所以更推荐在搜索时指定权重,更为灵活且效果一样。 - coerce
强制转型,针对文档属性,默认值true
,用于将类型不正确的输入数据自动转化为文档中对应的类型。 - copy_to
字段拷贝,用于自定义 _all 字段,可以将多个字段内容拷贝进指定的字段。 - doc_value
建立倒排索引时的额外的列式存储映射开关,针对文档属性,默认值true
,牺牲空间换取排序、聚合操作的速度。如果明确一些字段不需要排序或者聚合操作可以关闭。 - dynamic
新字段自动映射开关,针对类型。在插入文档时如果文档中含有没有指定配置过的属性,插入的结果会取决于该选项的设置。它有三个可选项,默认为true
:- true 对新增的字段采取自动映射
- false 忽略未映射的新字段
- strict 严格模式,如果发现新字段会抛出异常
- enable
ES 默认索引所有字段,但是某些字段没有查询、聚合等需求,可以直接使用"enable": false
来直接关闭。关闭的字段不会被索引和搜索,需要获取值时可以从 _source 中得到。 - fielddata
这是一个特殊的选项。上文可知大部分类型字段默认都会生成 doc_value 以加快排序和聚合,但是 text 类型除外,取而代之的是在 text 首次被排序、聚合或者使用脚本时生成 fielddata 数据。fielddata 是在堆内存中的记录文档和词项关系的数据,所以它非常消耗内存,默认是不开启的。因为大部分情况下对一个 text 字段做排序聚合似乎都是无意义的。 - format
针对日期字段设定格式 - ignore_above
针对 keyword 类型的属性,如果目标字段的内容长度超过设定值,将不会被索引(查询不到哦) - ignore_malformed
针对文档属性,支持不兼容数据类型的开关,打开时,如果某个字段存在不兼容数据类型,异常会被忽略,仅该属性被忽略,其他字段仍然索引,可以避免存在不规则数据时整个文档索引出错。 - include_in_all
针对文档属性,每个字段的该选择项默认为true
,即所有字段内容都会加入 _all,如果需要 _all 中不包含某字段可以设置为false
。 - index
设定某个字段是否被索引,如果关闭了当然就不能被搜索了 - index_options
针对文档属性,控制某属性被索引时保存进倒排索引表中的信息,具体取值有下:docs
默认,只保存文档编号freqs
保存文档编号和词项频率positions
保存文档编号、词项频率和词项偏移位置(用于临近搜索和短语查询)offset
保存文档编号、词项频率、词项位置、词项开始和结束字符位置。
- fields
针对文档属性,可以为某个属性增加附加的属性,以使用额外的索引方式或者 token_count。 - norms
标准化文档,针对某个文档属性,用于文档评分,会占用额外的磁盘空间,如果不需要评分可以关闭。 - null_value
空值映射,针对文档属性,通常值为null
的字段不会被索引也不能被搜索,这时候可以显式地告诉 ESnull
值需要映射成什么,如:"null_value": "NULL"
会使得某个字段的空值显式地转化为 NULL 字符串,以被索引和查询。 - position_increment_gap
一般针对某 text 数组类型属性,因为 text 类型在索引时会考虑词项的位置,而对于一个 text 数组,其中每个元素在保存的时候会有一定的 间距 ,通过这个间距(默认 100)来区分不同元素。举一个 match_phrase query 的例子:像上面了例子也可以改变字段的的间距值,比如:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15PUT /player/football/1
{"name": ["Lionel Messi", "Cristiano Ronaldo"]}
GET /player/football
{
"query": {
"match_phrase": {
"name": {
"query": "Messi Cristiano",
# 为了查询到该文档,需要
"slop": 101
}
}
}
}"position_increment_gap": 0
。 - properties
这个选项其实用的太普遍了以至于我们都忽略了。如果把 properties 看作一个配置项,那么它是针对某个类型的,用来指定属性的类型和其他配置。 - similarity
用于指定某字段会用的评分模型,ES 中预置了三种模型:- BM25 默认评分模型
- classic TF/IDF 评分模型
- boolean 布尔评分模型
- store
决定某个字段是否被存储。默认字段会被索引但是不会存储,因为 _source 中包含了源文档的数据。 - term_vector
决定词项量存储时候包含的信息:- no 默认值,不存储词向量
- yes 保存词项集合
- with_positions 保存词项和词项位置
- with_offsets 保存词项和字符偏移位置
- with_positions_offsets 保存词项、词项位置和字符偏移位置
- dynamic_templates
这也是一个特殊配置项,针对某个类型而言,配置 dynamic template 可以在字段进行自动映射时候按一定的规则确定索引字段的类型及别的配置。模板中至少需要包含一个条件,多个模板存在先后关系,最先匹配的模板会被应用。下面是一个例子:当文档中添加以 long_ 开头而不以 _text 结尾的字段时自动映射为 long 数据类型:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19PUT /index_name
{
"mappings": {
"type_name": {
"dynamic_templates": [
{
"template_name": {
"match_mapping_type": "string",
"match": "long_",
"unmatch": "_text",
"mapping": {
"type": "long"
}
}
}
]
}
}
}
以上内容涉及了字段类型、元字段性质以及配置映射时候的选项,本质是对索引管理内容的深化,除了了解 ES 本身的机制,这些内容的学习可以为学习 ES 带来更好的铺垫。
参考:
- 《从Lucene到ElasticSearch全文检索实战》 姚攀