前言
Elasticsearch 的 Mapping 对应着数据库的 schema,比数据库的 schema 灵活的是 Mapping 可以是 Dynamic 的,也就是如果不定义 Mapping 还是可以往 ES 里面插入文档的。但是数据库中如果不新建表,是不能插入数据的。
1.什么是 Mapping
Mapping 类似数据库中的 schema,定义了索引中的字段名称、数据类型(字符串、数字、布尔、日期等),还可以定义字段倒排索引的相关配置。Mapping 会把 JSON 文档映射成 Lucene 所需要的扁平格式。一个 Mapping 属于一个索引的 Type,每个文档都属于一个 Type,一个 Type 有一个 Mapping 的定义。7.0开始,不需要在 Mapping 定义中指定 Type 信息。 Mapping 中定义的字段数据类型可分为三类:简单类型、复杂类型、特殊类型。
- 简单类型:Text / Keyword、Date、Integer / Floating、Boolean、IPV4 & IPV6
- 复杂类型:对象类型/嵌套类型
- 特殊类型:geo_point & geo_shape / percolator
2.什么是 Dynamic Mapping
Elasticsearch 提供了 Dynamic Mapping 机制,使我们在写入文档的时候,如果索引不存在,会自动创建索引,无需手动定义 Mappings。ES 会自动根据文档信息,推算出字段的类型,但有时候会推算不准确,例如地理位置信息。当类型如果设置不对时,会导致一些功能无法正常运行,例如 Range 查询。可以使用 GET movies/_mappings 命令查看 Mapping。
一、类型的自动识别
数字用引号的时候,会默认当成 Text,有些一类型会推导出错,比如地理位置信息。
JSON 类型 | Elasticsearch 类型 |
---|
字符串 | 匹配日期格式成 Date;匹配数字为 float 或者 long,该选项默认关闭;设置为 Text,并且增加 keyword 子字段 | 布尔值 | boolean | 浮点数 | float | 整数 | long | 对象 | object | 数组 | 由第一个非空数值类型所决定 | 空值 | 忽略 |
二、Dynamic Mappings 设置
当 dynamic 被设置成 false 时,存在新增字段的文档写入,该文档可以被索引,但是里面新增的字段则不会被索引。当设置成 strict 时,新增时会报错。
mapping | true | false | strict |
---|
文档可索引 | YES | YES | NO | 字段可索引 | YES | NO | NO | Mapping被更新 | YES | NO | NO |
可用下面的命令设置 mapping
PUT movies
{
"mappings": {
"_doc": {
"dynamic":"false"
}
}
}
三、更改 Mapping 的字段类型
当 Elasticsearch 存在已有的 Mapping 时,不同的 Dynamic Mapping 设置,会有不同的结果。
- 新增字段:
- Dynamic 设置为 true 时,一旦有新增字段文档写入,Mapping 也同时会被更新。 - Dynamic 设置为 false,Mapping 不会被更新,新增字段的数据无法被索引,也就是查询会报错,但是新增的字段信息会出现在 _source 中。 - Dynamic 设置成 strict,文档写入的时候就会报错 - 更新字段:
- 对于已有的字段,一旦有数据写入,就不再支持修改字段的定义,这一点跟数据库的表不一样,数据库的表可以修改字段的定义。 - 如果希望改变字段类型,必须 Reindex(重建索引),当然这个代价是比较高的,特别是数据量大的情况下。至于为什么一定要重建索引,是因为 Lucene 实现的倒排索引,一旦生成后,就不允许修改了。
如果修改 Mapping 的字段类型是新增的,就看 Dynamic 的设置,只要不是 strict 就可以写入成功,设置为 false 的时候,查询不会成功。如果修改 Mapping 的字段类型是已存在的,会导致已经被索引的属性无法被搜索,除非重建索引。
3.设置 Mapping
如果要显示指定 Mapping,有两种办法,一种是参考 API,纯手写。别一种是为了减少出错的概率,可以先创建一个临时的 index,写入一些样本数据。然后通过访问 Mapping API 获取该临时文件的动态 Mapping 定义,修改后使用,创建自己的索引,删除临时的索引。
显示定义 Mapping
PUT movies
{
"mappings":{
// mapping
}
}
Mapping 定义的参数
介绍 Mapping 参数前,先介绍一下倒排索引。什么是倒排索引?先看一下正排索引 - 文档 ID 到文档内容和单词的关联,那么倒排索引 - 单词到文档ID的关联。 正排索引和倒排索引
文档ID | 文档内容 |
---|
1 | Mastering Elasticsearch | 2 | Elasticsearch Server | 3 | Elasticsearch Essentials |
Term | Count | DocumentId:Position |
---|
Elasticsearch | 3 | 1:1, 2:0, 3:0 | Mastering | 1 | 1:0 | Server | 1 | 2:1 | Essentials | 1 | 3:1 |
倒排索引包含两个部分:单词词典(Term Dictionary)、倒排列表(Posting List);
- 单词词典记录所有文档的单词,记录单词到倒排列表的关联关系,一般比较大,通过 B+ 树或哈希拉链法实现。
- 倒排列表记录了单词对应的文档集合,由倒排索引项组成。倒排索引项包括:文档 ID、词频 TF(该单词在文档中出现的次数)、位置 Position(单词在文档中分词的位置,0开始,用于语句搜索 phrase query)、偏移 Offset(记录单词的开始结束位置,用于高亮显示)
文档ID | 文档内容 |
---|
1 | Mastering Elasticsearch | 2 | Elasticsearch Server | 3 | Elasticsearch Essentials |
Doc Id | TF | Position | Offset |
---|
1 | 1 | 1 | <10,23> | 2 | 1 | 0 | <0,13> | 3 | 1 | 0 | <0,13> |
- 控制当前字段是否被索引:index - 默认为 true,如果设置成 false,该字段不可被搜索。
PUT users
{
"mappings":{
"properties":{
"firstName":{
"type":"text"
},
"lastName":{
"type":"text"
},
"mobile":{
"type":"keyword",
"index":"false"
}
}
}
}
- 控制倒排索引记录的内容:index options - docs 记录 doc id;freqs 记录 doc id 和 term frequencies(频率);positions 记录 doc id、term frequencies、term position;offsets 记录 doc id、term frequencies、term posistion、character offects。
Text 类型默认记录 postions,其他默认为 docs。记录内容越多,占用存储空间越大。PUT users
{
"mappings":{
"properties":{
"firstName":{
"type":"text"
},
"lastName":{
"type":"text"
},
"mobile":{
"type":"keyword",
"index":"false"
},
"bio":{
"type":"text",
"index_options":"offsets"
}
}
}
}
- 空值:null_value - 对空值进行搜索,只有 Keyword 类型支持设置
PUT users
{
"mappings":{
"properties":{
"firstName":{
"type":"text"
},
"lastName":{
"type":"text"
},
"mobile":{
"type":"keyword",
"null_value":"null"
}
}
}
}
// 查询
GET users/_search?q=mobile:null
- 数值拷贝:copy_to - 将字段的数值拷贝到目标字段,以满足一些特定的搜索需求。在7.0中代替 _all 属性,copy_to 的目标字段不出现在 _source 中。
PUT users
{
"mappings": {
"properties": {
"firstName": {
"type": "text",
"copy_to": "fullName"
},
"lastName": {
"type": "text",
"copy_to": "fullName"
}
}
}
}
// 查询
GET users/_search?q=fullName:(Zeng linhui)
- 数组类型:Elasticsearch 中不提供专门的数组类型,但是任何字段,都可以包含多个相同类型的数值。
PUT users/_doc/3
{
"name":"onebird",
"interests":"reading"
}
PUT users/_doc/4
{
"name":"twobirds",
"interests":["reading","music"]
}
4.多字段特性
可以增加一个 keyword 字段实现精确匹配,keyword 在索引时,不需要做特殊的分词处理。可以使用不同的 analyzer,还支持搜索和索引指定不同的 analyzer。当 Elasticsearch 自带的分词器无法满足需求时,可以自定义分词器,通过自组合不同的组件实现。
PUT products
{
"mappings": {
"properties": {
"company": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"comment": {
"type": "text",
"fields": {
"english_comment": {
"type": "text",
"analyzer": "english",
"search_analyzer": "english"
}
}
}
}
}
}
总结
合理的使用 dynamic mapping 能加快搜索速度,节省存储空间。
|