写在前面: 本文涉及到的演示以ES 6.6.0版本, 其他版本可能存在不同, 还请读者朋友们注意.

1 动态映射(dynamic mapping)

1.1 什么是动态映射

动态映射时Elasticsearch的一个重要特性: 不需要提前创建iindex、定义mapping信息和type类型, 你可以 直接向ES中插入文档数据时, ES会根据每个新field可能的数据类型, 自动为其配置type等mapping信息, 这个过程就是动态映射(dynamic mapping).

Elasticsearch动态映射的示例:

字段内容(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).

1.2 体验动态映射

(1) 插入如下数据:

如果已有website索引, 先删除DELETE blog , 再执行下面的插入操作: .

PUT blog/_doc/1
{
"blog_id": 10001,
"author_id": 5520,
"post_date": "2018-01-01",
"title": "my first blog",
"content": "my first blog in the website"
} PUT blog/_doc/2
{
"blog_id": 10002,
"author_id": 5520,
"post_date": "2018-01-02",
"title": "my second blog",
"content": "my second blog in the website"
} PUT blog/_doc/3
{
"blog_id": 10003,
"author_id": 5520,
"post_date": "2018-01-03",
"title": "my third blog",
"content": "my third blog in the website"
}

(2) 进行如下检索测试:

注意这里结果数是3的情况.

GET blog/_search?q=2018                 // 1条结果, 5.6之前的版本是3条结果
GET blog/_search?q=2018-01-01 // 1条结果, 5.6之前的版本是3条结果
GET blog/_search?q=post_date:2018 // 1条结果
GET blog/_search?q=post_date:2018-01-01 // 1条结果

(3) 查看ES自动建立的mapping:

GET blog/_mapping

// 结果如下:
{
"blog" : { // index是blog
"mappings" : {
"_doc" : { // type是_doc - 方便后期升级版本
"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
}
}
}
}
}
}
}
}

1.3 搜索结果不一致的原因分析

如果使用的是ES 5.6.x之前的版本, [1.2]节中搜索结果会不一致, 这是因为:

ES自动建立mapping时, 为不同的field映射了不同的数据类型, 而不同数据类型在分词、搜索等行为上也是不同的.

我们通过q=xxx的方式搜索, 底层是从每个文档的_all字段中进行匹配的 —— ES默认将每个文档的所有field的值抽取到一个名为_all的元字段中.

官方文档指出, 从6.0+版本开始, _all字段就被禁止使用了, 建议我们使用copy_to实现相似的功能.—— 也就是说, 如果_all字段被关闭, 就不会出现搜索结果不一致的情况.

(1) GET website/blog/_search?q=2018

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会出现第一条结果.

2 开启dynamic mapping动态映射策略

2.1 约束策略

策略 功能说明
true 开启 —— 遇到陌生字段时, 进行动态映射
false 关闭 —— 忽略遇到的陌生字段
strict 遇到陌生字段时, 作报错处理

2.2 策略示例

(1) 使用不同的约束策略:

PUT blog_user
{
"mappings": {
"_doc": {
"dynamic": "strict", // 严格控制策略
"properties": {
"name": { "type": "text" },
"address": {
"type": "object",
"dynamic": "true" // 开启动态映射策略
}
}
}
}
}

(2) 插入数据演示:

// 插入数据时多添加一个字段
PUT 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 [_doc] is not allowed"
}
],
"type": "strict_dynamic_mapping_exception",
"reason": "mapping set to strict, dynamic introduction of [content] within [_doc] is not allowed"
},
"status": 400
}

添加符合约束的数据, 操作就能成功:

PUT blog_user/_doc/1
{
"name": "shou feng",
"address": {
"province": "guangdong",
"city": "guangzhou"
}
}

(3) 查看映射信息:

GET user/_mapping

// 映射信息如下:
{
"blog_user" : {
"mappings" : {
"_doc" : {
"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 - 日期识别策略

对于date类型的数据, Elasticsearch有其默认的识别策略, 比如"yyyy-MM-dd". 存在这种情况:

① 第一次添加文档时, 某个field是类似"2018-01-01"的值, 其类型就动态映射成date;

② 后期再次添加文档, 该field是类似"hello world"的值, ES就会因为类型不匹配而报错.

为解决这一问题, 可以手动关闭某个type的date_detection; 如果不需要关闭, 建议手动指定这个field为date类型. 示例如下:

PUT blog_user/_mapping/_doc
{
"date_detection": false
}

3.2 在type中自定义动态映射模板

(1) 在type中定义动态映射模板(dynamic mapping template) —— 把所有的String类型映射成text和keyword类型:

先删除已有的blog_user索引: DELETE blog_user, 再执行下述命令:

PUT blog_user
{
"mappings": {
"_doc": {
"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 blog_user/_doc/1
{
"name": "the first register user"
} PUT blog_user/_doc/2
{
"name_en": "the second register user"
}

(3) 检索数据:

// 有结果: "name"没有匹配到任何动态模板, 默认使用standard分词器
GET blog_user/_search
{
"query": {
"match": {"name": "the"}
}
} // 无结果: "name_en"匹配到了动态模板, 使用english分词器, the是停用词, 被过滤掉了
GET blog_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 [_doc]: 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 [_doc]: 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]

3.3 [过期]在index中自定义默认映射模板

_default mapping - 默认映射模板是类似于全局变量的存在, 对当前配置的索引起作用.

默认映射模板在Elasticsearch 6.x版本中已经不再支持, 因为6.0版本开始, 每个索引只能有一个类型, 因此默认模板没有存在的意义了.

下面的演示过程, 是在6.0之前的版本上的测试.

(1) 在index中定义默认映射模板(default mapping template):

先删除已有的blog_user索引: DELETE blog_user, 再执行下述命令:

PUT blog_user
{
"mappings": {
"_default_": {
"_all": { "enabled": false }
},
"_doc": {
"_all": { "enabled": true }
}
}
}

(2) 动态映射可以和索引模板(Index Templates)配合使用.

无论是自动创建Index, 还是手动显式创建Index, 索引模板都可以用来配置新索引的默认mappings(映射)、settings(配置项)和aliases(别名). 具体使用方法请参考博客: ES 10 - 如何使用Elasticsearch的索引模板(index template)

参考资料

(6.6版)官方文档 - Dynamic Mapping

版权声明

作者: 瘦风(https://healchow.com)

出处: 博客园 瘦风(https://www.cnblogs.com/shoufeng)

感谢阅读, 如果文章有帮助或启发到你, 点个[好文要顶

ES 12 - 配置使用Elasticsearch的动态映射 (dynamic mapping)的更多相关文章

  1. elasticsearch自定义动态映射

    https://www.elastic.co/guide/cn/elasticsearch/guide/current/custom-dynamic-mapping.html如果你想在运行时增加新的字 ...

  2. Logstash中如何处理到ElasticSearch的数据映射

    Logstash作为一个数据处理管道,提供了丰富的插件,能够从不同数据源获取用户数据,进行处理后发送给各种各样的后台.这中间,最关键的就是要对数据的类型就行定义或映射. 本文讨论的 ELK 版本为 5 ...

  3. Elasticsearch 动态映射——自动检测

    ES中有一个非常重要的特性——动态映射,即索引文档前不需要创建索引.类型等信息,在索引的同时会自动完成索引.类型.映射的创建. 那么什么是映射呢?映射就是描述字段的类型.如何进行分析.如何进行索引等内 ...

  4. ES 11 - 配置Elasticsearch的映射 (mapping)

    目录 1 映射的相关概念 1.1 什么是映射 1.2 映射的组成 1.3 元字段 1.4 字段的类型 2 如何配置mapping 2.1 创建mapping 2.2 更新mapping 2.3 查看m ...

  5. 使用Logstash创建ES映射模版并进行数据默认的动态映射规则

    本文配置为 ELK 即(Elasticsearch.Logstash.Kibana)5.5.1. Elasticsearch 能够自动检测字段的类型并进行映射,例如引号内的字段映射为 String,不 ...

  6. elasticsearch 动态映射

    https://www.elastic.co/guide/cn/elasticsearch/guide/current/dynamic-mapping.html#dynamic-mapping当 El ...

  7. elasticsearch索引和映射

    目录 1. elasticsearch如何实现搜索 1.1 搜索实例 1.2 es中数据的类型 1.3 倒排索引 1.4 分析与分析器 1.4.1 什么是分析器 1.4.2 内置分析器种类 1.4.3 ...

  8. ES 基础理论 配置调优

    一.简介 ElasticSearch是一个基于Lucene的搜索服务器.它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口.Elasticsearch是用Java开发的,并作为 ...

  9. 使用Elasticsearch的动态索引和索引优化

    关于映射 实际工作中使用过ES的朋友可能会有和静儿一样的感受.ES存储更新从编码上是很方便.如下,Kubernetes的yaml文件完全可以通过json直接序列化一下,一行代码存入ES. 剩下的工作可 ...

随机推荐

  1. 使用Android Studio Gradle实现友盟多渠道打包

    最新项目中要求在友盟后台看到不同渠道的统计,Android大大小小的应用市场要几百个,要一个一个手工打包那一天也干不完,还好是有大牛的,弄出了好多解决方法,就Gradle做一下记录和分享,首先看一些理 ...

  2. (三)SpringBoot基础篇- 持久层,jdbcTemplate和JpaRespository

    一.介绍 SpringBoot框架为使用SQL数据库提供了广泛的支持,从使用JdbcTemplate的直接JDBC访问到完整的"对象关系映射"技术(如Hibernate).Spri ...

  3. golang自定义路由控制实现(一)

        由于本人之前一直是Java Coder,在Java web开发中其实大家都很依赖框架,所以当在学习Golang的时候,自己便想着在Go开发中脱离框架,自己动手造框架来练习.通过学习借鉴Java ...

  4. 修改ZendStudio新建php文件时的模板

    zendstudio默认的模板不适用,可以自己到Window -- preferences -- php -- code style -- code templates -- code -- samp ...

  5. CF#483(div2 C)

    http://codeforces.com/contest/984/problem/C C. Finite or not time limit per test 1 second memory lim ...

  6. vue 单页应用拆分为多页应用

    npm install glob --save-dev build.js---'./src/pages' 替换为自己实际的项目文件路径 utils.js--- webpack.base.conf.js ...

  7. spring 切入点表达式

    spring表达式有多种的指示符,如: 切入点指示符用来指示切入点表达式目的,,在Spring AOP中目前只有执行方法这一个连接点,Spring AOP支持的AspectJ切入点指示符如下: exe ...

  8. mysql读写分离总结

    随着一个网站的业务不断扩展,数据不断增加,数据库的压力也会越来越大,对数据库或者SQL的基本优化可能达不到最终的效果,我们可以采用读写分离的策略来改变现状.读写分离现在被大量应用于很多大型网站,这个技 ...

  9. 五种开源协议(GPL,LGPL,BSD,MIT,Apache)介绍

    商业化的软件应该主要选用MIT或者Apache license的开源系统作为插件. 什么是许可协议? 什么是许可,当你为你的产品签发许可,你是在出让自己的权利,不过,你仍然拥有版权和专利(如果申请了的 ...

  10. 点击<a>页面跳转解决办法/跨域请求,JSONP

    有些时候做的东西刚好要用到链接,但又不需要去链接,只需要对onclick事件进行处理,但它却这样子写 <a href="#" onclick="gettext()& ...