不同版本的 ElasticSearch API 可能有所区别,本文基于 7.17 版本。ElasticSearch 有三个重要的概念,索引、映射、文档,本文介绍 ElasticSearch 的映射。映射是用来用来定义文档及其字段的存储方式、索引方式的手段,与关系型数据库中的表结构类似,可以从映射信息中得知索引下有哪些字段,字段的数据类型以及有哪些约束信息。
映射信息
每个索引都有唯一的 mapping type,用于决定文档将如何被索引。mapping type由下面两部分组成:
Meta-fields:
元字段用于自定义如何处理文档的相关元数据,其中有身份元数据、索引元数据、文档元数据、路由元数据以及其他类型的元数据。
- 身份元数据
一个文档除了有数据之外,它还包含了元数据(Metadata)。每创建一条数据时,都会对元数据进行写入等操作。
_index:文档所属索引 , 自动被索引,可被查询,聚合,排序使用,或者脚本里访问
_type:文档所属类型,自动被索引,可被查询,聚合,排序使用,或者脚本里访问
_id:文档的唯一标识, 建索引时候传入 ,不被索引, 可通过_uid被查询,脚本里使用,不能参与聚合或排序
_uid:由_type和_id字段组成,自动被索引 ,可被查询,聚合,排序使用,或者脚本里访问
- 索引元数据
_all: 自动组合所有的字段值,以空格分割,可以指定分器词索引,但是整个值不被存储,所以此字段仅仅能被搜索,不能获取到具体的值。
_field_names:索引了每个字段的名字,可以包含null值,可以通过exists查询或missing查询方法来校验特定的字段。
_timestamp:可以手工指定时间戳值,也可以自动生成使用now()函数,除此之外还可以设置日期的格式化,忽略确实等功能。
_ttl:对于一些有生命周期的会话,会话的数据或者验证码是具有失效时间的,在 ElasticSearch 中可以通过ttl来很方便的设置存活时间,比如1小时,或者10分钟,超时过后,这个文档会被自动删除,需要注意的是这种方式并不适合按周或按天删除历史数据,这种需求可考虑使用索引级别的管理方式(名称+时间+定时删除索引)。
- 文档元数据
_source : 一个文档的原生的json数据,不会被索引,用于获取提取字段值 ,启动此字段,索引体积会变大,如果既想使用此字段又想兼顾索引体积,可以开启索引压缩。
_size: 整个_source字段的字节数大小,可被禁用。
- 路由元数据
_parent:在同一个索引中,可以通过_parent字段来给两个不同mapping type的数据建立父子关系,在查询时可以通过has_child, has_parent等查询,来聚合join数据,需要注意的是,父子type必须不能是一样的,否则会识别失败。
_routing: 一个文档可以被路由到指定的shard上。默认情况下,会使用文档的_id字段来参与路由规则,如果此文档有关联关系,则会以上级文档的_id作为路由规则,以确保文档之间的数据必须处于同一个shard上,以提高join效率。
Fields or properties:
映射类型包含与文档相关的字段、字段类型或属性的列表。
数据类型
文本类型
- string
仅存在于早期版本的 ElasticSearch 中,自 6.x 版本开始移除支持,可使用 Text 或 Keyword 类型替代。
- text
当一个字段需要用于分词搜索时,可使用 text 类型。需要注意的是 text 字段不能用于过滤、排序,也很少用于聚合。
- keyword
当一个字段不需要分词只需要直接存储时,可使用 keyword 类型,这个类型常常被用来过滤、排序和聚合。
数字类型
- byte:有符号的8位整数, 范围: [-128 ~ 127]
- short:有符号的16位整数, 范围: [-32768 ~ 32767]
- integer:有符号的32位整数, 范围: [−2^31 ~ 2^31-1]
- long:有符号的64位整数,范围: [−2^63 ~ 2^63-1]
- float:32位单精度浮点数
- double:64位双精度浮点数
- half_float:16位半精度IEEE 754浮点类型
- scaled_float:带缩放类型的的浮点数, 比如price字段只需精确到分, 57.34缩放因子为100, 存储结果为5734
在定义字段映射的数据类型时,尽可能选择范围小的数据类型, 字段的长度越短, 索引和搜索的效率越高;优先考虑使用带缩放因子的浮点类型。
在定义数字类型的字段映射时还可以设置 coerce 强制转换参数(默认为true),开启强制转换后 ElasticSearch 会自动转换创建文档时传入的值,例:将数字字符转换为数字(在向ES添加数据时传递JSON,JSON中数字类型的值不带引号);映射类型定义为整型但传入浮点型数据则截断浮点数。
1 | # PUT http://127.0.0.1:9200/category/_mapping |
示例中定义了两个库存字段,分别开启/关闭了字段的强制类型转换,开启了强制类型转换的库存字段字符类型和数字类型的JSON均可传递(”stock_enable”: “10”),但关闭了强制类型转换的库存字段只能传递数字类型的JSON(”stock_disable”: 10) 。
1 | #PUT http://127.0.0.1:9200/category/_doc/1 |
日期类型
ElasticSearch 中的日期类型统一为 date,但日期的具体格式并未定义,需要在定义映射时一并传入指定格式,多种格式之间看使用双竖线 ||
分隔,ElasticSearch 会依次尝试直到匹配格式。如果未指定格式,则使用默认格式 strict_date_optional_time||epoch_millis
。
日期类型需要指定格式与 JSON 没有日期数据类型也有一定的关系,JSON 中的日期可以是 “2022-07-25” 或 “2022/07/25 14:10:30”,也可以是类似毫秒时间戳的长整型数字,也可以是类似秒级时间戳的整型数字。
1 | # PUT http://127.0.0.1:9200/info |
布尔类型
ElasticSearch 中的布尔类型统一为 boolean,在向索引添加文档时可以接受真假的布尔、字符串、数字类型。
真值: true, “true”, “on”, “yes”, “1”.
假值: false, “false”, “off”, “no”, “0”, “”(空字符串), 0.0, 0
二进制型
二进制类型是Base64编码字符串的二进制值, 不以默认的方式存储, 且不能被搜索,且Base64编码的二进制值不能嵌入换行符\n
, 逗号0x2c
等符号。有2个设置项:
(1) doc_values: 该字段是否需要存储到磁盘上, 方便以后用来排序、聚合或脚本查询. 接受true和false(默认);
(2) store: 该字段的值是否要和_source分开存储、检索, 意思是除了_source中, 是否要单独再存储一份. 接受true或false(默认).
范围类型
- integer_range:支持范围 [−2^31 ~ 2^31-1]
- long_range:支持范围 [−2^63 ~ 2^63-1]
- float_range:支持范围 32位单精度浮点型
- double_range:支持范围 64位双精度浮点型
- date_range:支持范围 64位整数, 毫秒计时
- ip_range:IP值的范围, 支持IPV4和IPV6, 或者这两种同时存在。如 192.168.1.0/24
数组类型
ElasticSearch 中没有专门的数组类型, 直接使用 []
定义即可。
使用数组类型时,需要注意以下几点问题:
- 数组中所有的值必须是同一种数据类型, 不支持混合数据类型的数组。
- 动态添加数据时, 数组中第一个值的类型决定整个数组的类型。
- 数组可以包含null值, 空数组
[]
会被当做没有值的字段(missing field)
对象类型
JSON 文档是分层的,因此文档可以包含内部对象, 内部对象也可以包含内部对象。
文档示例
1
2
3
4
5
6
7
8#PUT http://127.0.0.1:9200/employee/developer/1
{
"name": "aofall",
"address": {
"region": "China",
"location": {"province": "Fujian", "city": "Fuzhou"}
}
}存储方式
1
2
3
4
5
6{
"name": "aofall",
"address.region": "China",
"address.location.province": "Fujian",
"address.location.city": "Fuzhou"
}映射结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#PUT http://127.0.0.1:9200/employee
{
"mappings": {
"developer": {
"properties": {
"name": { "type": "text", "index": "true" },
"address": {
"properties": {
"region": { "type": "keyword", "index": "true" },
"location": {
"properties": {
"province": { "type": "keyword", "index": "true" },
"city": { "type": "keyword", "index": "true" }
}
}
}
}
}
}
}
}
嵌套类型
与 JSON 一样,ElasticSearch 可以嵌套组合数组和对象结构,但嵌套的数组内的对象可能会丢失关联性。
地理数据/地理形状类型
地理点类型用于存储地理位置的经纬度对
地理形状类型是多边形的复杂形状
IP类型
IP类型的字段用于存储IPv4或IPv6的地址, 本质上是一个长整型字段。
计数数据类型
token_count类型用于统计字符串中的单词数量.
本质上是一个整数型字段, 接受并分析字符串值, 然后索引字符串中单词的个数