目录html
动态映射时Elasticsearch的一个重要特性: 不须要提早建立iindex、定义mapping信息和type类型, 你能够 直接向ES中插入文档数据时, ES会根据每一个新field可能的数据类型, 自动为其配置type等mapping信息, 这个过程就是动态映射(dynamic mapping).web
Elasticsearch动态映射的示例:shell
字段内容(field) | 映射的字段类型(type) |
---|---|
true | false | boolean |
1234 | long |
123.4 | float |
2018-10-10 | date |
"hello world" | text |
说明: 动态映射虽然方便, 可并不直观, 为了个性化自定义相关设置, 能够在添加文档以前, 先建立index和type, 并配置type对应的mapping, 以取代动态映射.
mapping的配置可参考博文: ES 11 - 配置Elasticsearch的映射(mapping).json
(1) 插入以下数据:bash
若是已有website索引, 先删除再执行下面的插入操做:
DELETE website
.app
PUT website/blog/1 { "blog_id": 10001, "author_id": 5520, "post_date": "2018-01-01", "title": "my first blog", "content": "my first blog in the website" } PUT website/blog/2 { "blog_id": 10002, "author_id": 5520, "post_date": "2018-01-02", "title": "my second blog", "content": "my second blog in the website" } PUT website/blog/3 { "blog_id": 10003, "author_id": 5520, "post_date": "2018-01-03", "title": "my third blog", "content": "my third blog in the website" }
(2) 进行以下检索测试:elasticsearch
注意这里结果数是3的状况.ide
GET website/blog/_search?q=2018 // 1条结果, 5.6以前的版本是3条结果 GET website/blog/_search?q=2018-01-01 // 1条结果, 5.6以前的版本是3条结果 GET website/blog/_search?q=post_date:2018 // 1条结果 GET website/blog/_search?q=post_date:2018-01-01 // 1条结果
(3) 查看ES自动创建的mapping:post
GET website/_mapping // 结果以下: { "website" : { // index是website "mappings" : { "blog" : { // type是blog "properties" : { "author_id" : { "type" : "long" }, "blog_id" : { "type" : "long" }, "content" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } }, "post_date" : { "type" : "date" // 发布日期"2018-01-01"被自动识别为date类型 }, "title" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } } } } } } }
若是使用的是较早的版本, 以5.6.x为例, [1.2]节中搜索结果会不一致, 这是由于:测试
ES自动创建mapping时, 为不一样的field映射了不一样的数据类型, 而不一样数据类型在分词、搜索等行为上也是不一样的.
官方文档指出, 从6.0+版本开始,
_all
字段的设置已经禁止使用, 建议咱们使用copy_to
实现类似的功能.—— 也就是说, 若是_all
字段被关闭, 就不会出现搜索结果不一致的状况.
(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类型, 因此将进行精确匹配.
而date类型的字段索引的内容有其默认的固定格式.
post_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.x版本中作的一个优化, 搜索
post_date:01
等是不会出现结果的, 搜索2018会出现第一条结果.
策略 | 功能说明 |
---|---|
true |
开启 —— 遇到陌生字段时, 进行动态映射 |
false |
关闭 —— 忽略遇到的陌生字段 |
strict |
遇到陌生字段时, 做报错处理 |
(1) 使用不一样的约束策略:
PUT user { "mappings": { "blog_user": { "dynamic": "strict", // 严格控制策略 "properties": { "name": { "type": "text" }, "address": { "type": "object", "dynamic": "true" // 开启动态映射策略 } } } } }
(2) 插入数据演示:
// 插入数据时多添加一个字段 PUT user/blog_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 [blog_user] is not allowed" } ], "type": "strict_dynamic_mapping_exception", "reason": "mapping set to strict, dynamic introduction of [content] within [blog_user] is not allowed" }, "status": 400 }
添加符合约束的数据, 操做就能成功:
PUT user/blog_user/1 { "name": "shou feng", "address": { "province": "guangdong", "city": "guangzhou" } }
(3) 查看映射信息:
GET user/_mapping // 映射信息以下: { "user" : { "mappings" : { "blog_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" } } } } } }
对于date类型的数据, Elasticsearch有其默认的识别策略, 好比"yyyy-MM-dd". 存在这种状况:
① 第一次添加文档时, 某个field是相似"2018-01-01"的值, 其类型就被动态映射成了date;
② 后期再次添加文档, 该field是相似"hello world"的值, ES就会由于类型不匹配而报错.
为解决这一问题, 能够手动关闭某个type的date_detection; 若是不须要关闭, 建议手动指定这个field为date类型.
关闭示例以下:
PUT user/_mapping/blog_user { "date_detection": false }
(1) 在type中定义动态映射模板(dynamic mapping template) —— 把全部的string类型映射成text和keyword类型:
先删除已有的
user
索引:DELETE user
, 再执行下述命令:
PUT user { "mappings": { "blog_user": { "dynamic_templates": [ { "en": { "match": "*_en", // 匹配"*_en"的field "match_mapping_type": "string", "mapping": { "type": "text", // 把全部的string类型, 映射成text类型 "analyzer": "english", // 使用english分词器 "fields": { "raw": { "type": "keyword", "ignore_above": 256 } } } } } ] } } }
(2) 添加数据:
PUT user/blog_user/1 { "name": "the first register user" } PUT user/blog_user/2 { "name_en": "the second register user" }
(3) 检索数据:
// 有结果: "name"没有匹配到任何动态模板, 默认使用standard分词器 GET user/_search { "query": { "match": {"name": "the"} } } // 无结果: "name_en"匹配到了动态模板, 使用english分词器, the是停用词, 被过滤掉了 GET user/_search { "query": { "match": {"name_en": "the"} } }
说明:
这里的
match_mapping_type
的类型支持[object, string, long, double, boolean, date, binary]
, 若使用text
将抛出以下错误信息:{ "error": { "root_cause": [ { "type": "mapper_parsing_exception", "reason": "Failed to parse mapping [blog_user]: No field type matched on [text], possible values are [object, string, long, double, boolean, date, binary]" } ], "type": "mapper_parsing_exception", "reason": "Failed to parse mapping [blog_user]: No field type matched on [text], possible values are [object, string, long, double, boolean, date, binary]", "caused_by": { "type": "illegal_argument_exception", "reason": "No field type matched on [text], possible values are [object, string, long, double, boolean, date, binary]" } }, "status": 400 }在6.0以前的版本, 将抛出以下过时的警告信息:
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]
_default mapping
- 默认映射模板是相似于全局变量的存在, 对当前配置的索引发做用.
默认映射模板在Elasticsearch 6.x版本中已经再也不支持, 由于6.0版本开始, 每一个索引只能有一个类型, 所以默认模板没有存在的意义了.
下面的演示过程, 是在6.0以前的版本上的测试.
(1) 在index中定义默认映射模板(default mapping template):
先删除已有的
user
索引:DELETE user
, 再执行下述命令:
PUT user { "mappings": { "_default_": { "_all": { "enabled": false } }, "blog_user": { "_all": { "enabled": true } } } }
(2) 动态映射能够与索引模板(Index Templates)配合使用.
不管是自动建立Index, 仍是手动显示建立Index, 索引模板均可以用来配置新索引的默认mappings(映射), settings(配置项)和aliases(别名). 具体使用方法请参考博客: ES 10 - Elasticsearch的索引别名和索引模板
参考资料
版权声明
做者: 马瘦风
出处: 博客园 马瘦风的博客
您的支持是对博主的极大鼓励, 感谢您的阅读.
本文版权归博主全部, 欢迎转载, 但请保留此段声明, 并在文章页面明显位置给出原文连接, 不然博主保留追究相关人员法律责任的权利.