文章目录
1 动态映射(dynamic mapping)
1.1 什么是动态映射
没有提前定义字段和数据类型间的映射关系, 而是直接向ES中插入数据, 此时ES将根据每个field可能对应的数据类型, 自动为其配置type及其对应的mapping, 这个过程就是动态映射(dynamic mapping).
示例:
true or false --> boolean
233 --> long
123.45 --> double
2018-10-10 --> date
"hello world" --> string/text
可以配置自定义映射, 供ES在动态映射时使用.
- 动态映射虽然方便, 可并不直观, 为了个性化自定义相关设置, 可以在添加文档之前, 先创建index和type, 并配置type对应的mapping, 以取代动态映射.
1.2 体验动态映射
-
插入如下数据:
PUT website/blog/1 { "post_date": "2018-01-01", "title": "my first blog", "content": "my first blog in the website", "author_id": 5520 } PUT website/blog/2 { "post_date": "2018-01-02", "title": "my second blog", "content": "my second blog in the website", "author_id": 5520 } PUT website/blog/3 { "post_date": "2018-01-03", "title": "my third blog", "content": "my third blog in the website", "author_id": 5520 }
-
进行如下检索测试:
GET website/blog/_search?q=2018 // 3条结果 GET website/blog/_search?q=2018-01-01 // 3条结果 GET website/blog/_search?q=post_date:2018-01-01 // 1条结果 GET website/blog/_search?q=post_date:2018 // 1条结果
-
查看ES自动建立的mapping:
GET website/_mapping/blog // 结果如下: { "website": { "mappings": { "blog": { "properties": { "author_id": { "type": "long" }, "content": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "post_date": { "type": "date" // post_date为date类型 }, "title": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } } } } } } }
1.3 搜索结果不一致的原因分析
上节中搜索结果不一致, 是因为ES自动建立mapping时, 为不同的field映射了不同的数据类型.
—— 不同数据类型在分词、搜索等行为上也是不同的.
(1) GET website/blog/_search?q=2018
ES默认将每个文档的所有field的值抽取到一个名为_all
的元字段中, 如id=1的文档的_all
的值为:
2018-01-01 my first blog my first blog in the website 5520
-
_all
字段的倒排索引结果如下:说明:
_all
字段将所有的值作为字符串索引, 所以日期被索引为年、月、日三个值.doc1 doc2 Doc3 2018 * * * 01 * * * 02 * 03 *
此项搜索中, ES是从_all
字段中检索, 3个文档中都有 2018
, 所以结果数是3.
(2) GET website/blog/?q=2018-01-01
同(1), ES也是从_all
字段中检索, 结果数同样是3.
(3) GET website/blog/_search?q=post_date:2018-01-01
此检索指定了检索条件, ES将从post_date字段中检索, 而post_date被映射为date类型, 所以将进行精确匹配.
-
post_date
字段的倒排索引结果如下:注意: date类型的字段索引的内容有其默认的固定格式, 如下:
doc1 doc2 doc3 2018-01-01 00:00:00 UTC * 2018-01-02 00:00:00 UTC * 2018-01-03 00:00:00 UTC *
可以看出, 满足条件的只有1个结果, 即doc1.
(4) GET /_search?q=post_date:2018
这是ES 5.2版本中做的一个优化, 搜索01/02等是不会出现结果的, 搜索2018会出现第一条结果.
2 开启dynamic mapping策略
2.1 约束策略
(1) true: 开启 —— 遇到陌生字段时, 进行动态映射;
(2) false: 关闭 —— 遇到陌生字段时, 忽略之;
(3) strict: 遇到陌生字段时, 报错处理.
2.2 策略示例
-
使用不同的约束策略:
PUT website { "mappings": { "user": { "dynamic": "strict", // 严格控制策略 "properties": { "name": { "type": "text" }, "address": { "type": "object", "dynamic": "true" // 开启动态映射策略 } } } } }
-
插入数据演示:
// 插入数据时多添加一个字段 PUT website/user/1 { "name": "shou feng", "content": "this is my blog", // 多添加的字段 "address": { "province": "guangdong", // 多添加的字段 "city": "guangzhou" // 多添加的字段 } } // 出错信息: { "error": { "root_cause": [ { "type": "strict_dynamic_mapping_exception", // 不允许动态添加field "reason": "mapping set to strict, dynamic introduction of [content] within [user] is not allowed" } ], "type": "strict_dynamic_mapping_exception", "reason": "mapping set to strict, dynamic introduction of [content] within [user] is not allowed" }, "status": 400 } // 添加符合的数据, 操作成功: PUT website/user/1 { "name": "shou feng", "address": { "province": "guangdong", "city": "guangzhou" } }
-
查看映射信息:
GET website/_mapping/user // 映射信息如下: { "website": { "mappings": { "user": { "dynamic": "strict", // 严格约束条件 "properties": { "address": { "dynamic": "true", // 开启动态映射策略 "properties": { "city": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "province": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } } } }, "name": { "type": "text" } } } } } }
3 定制dynamic mapping策略
3.1 date_detection - 日期识别策略
ES默认按照一定的格式识别date类型的数据, 如"yyyy-MM-dd". 存在这种情况:
① 第一次添加文档时, 某个field是类似"2018-01-01"的值, 其类型就被动态映射成了date;
② 后期再次添加文档, 该field是类似"hello world"的值, ES就会因为类型不匹配而报错.
为解决这一问题, 可以手动关闭某个type的date_detection, 如果有需要, 请指定某个field为date类型.
PUT website/_mapping/user
{
"date_detection": false
}
3.2 自定义动态映射模板 - type层面
-
在type中定义动态映射模板(dynamic mapping template):
PUT website { "mappings": { "user": { "dynamic_templates": [ { "en": { "match": "*_en", // 匹配"*_en"的field "match_mapping_type": "string", "mapping": { "type": "text", "analyzer": "english" // 使用english分词器 } } } ] } } }
-
添加数据:
PUT website/user/1 { "name": "the first register user" } PUT website/user/2 { "name_en": "the second register user" }
-
检索数据:
// 有结果: "name"没有匹配到任何动态模板, 默认使用standard分词器 GET website/user/_search { "query": { "match": {"name": "the"} } } // 无结果: "name_en"匹配到了动态模板, 使用english分词器, the是停用词, 被过滤掉了 GET website/user/_search { "query": { "match": {"name_en": "the"} } }
-
注意:
这里的
match_mapping_type
的类型支持[object, string, long, double, boolean, date, binary]
, 若使用text
将抛出如下警告信息:Deprecation: match_mapping_type [text] is invalid and will be ignored: No field type matched on [text], possible values are [object, string, long, double, boolean, date, binary]
3.3 自定义默认映射模板 - index级别
-
在index中定义默认映射模板(default mapping template):
PUT website { "mappings": { "_default_": { "_all": { "enabled": false } }, "blog": { "_all": { "enabled": true } } } }
-
默认映射模板的使用:
个人理解: 默认映射模板应该是类似于全局变量的存在, 对当前配置的索引起作用.
具体使用: 尚未尝试, 后续接触到时再补充此部分内容.
版权声明
作者: ma_shoufeng(马瘦风)
出处: CSDN 马瘦风的博客
您的支持是对博主的极大鼓励, 感谢您的阅读.
本文版权归博主所有, 欢迎转载, 但未经博主同意必须保留此段声明, 且在文章页面明显位置给出原文链接, 否则博主保留追究相关人员法律责任的权利.