ES 12 - 配置使用Elasticsearch的动态映射(dynamic mapping)

目录

  • 1 动态映射(dynamic mapping)

    • 1.1 什么是动态映射
    • 1.2 体验动态映射
    • 1.3 搜索结果不一致的原因分析
  • 2 开启dynamic mapping策略
    • 2.1 约束策略
    • 2.2 策略示例
  • 3 定制dynamic mapping策略
    • 3.1 date_detection - 日期识别策略
    • 3.2 在type中自定义动态映射模板
    • 3.3 [过期]在index中自定义默认映射模板

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 website.

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) 进行如下检索测试:

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

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:

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
              }
            }
          }
        }
      }
    }
  }
}

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

如果使用的是较早的版本, 以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会出现第一条结果.

2 开启dynamic mapping策略

2.1 约束策略

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

2.2 策略示例

(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"
          }
        }
      }
    }
  }
}

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 user/_mapping/blog_user
{
    "date_detection": false
}

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

(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]

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

_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的索引别名和索引模板

参考资料

(6.6版)官方文档 - Dynamic Mapping

版权声明

作者: ma_shoufeng(马瘦风)

出处: 博客园 马瘦风的博客

您的支持是对博主的极大鼓励, 感谢您的阅读.

本文版权归博主所有, 欢迎转载, 但请保留此段声明, 并在文章页面明显位置给出原文链接, 否则博主保留追究相关人员法律责任的权利.

原文地址:https://www.cnblogs.com/shoufeng/p/10655797.html

时间: 2024-11-06 14:52:49

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

Elasticsearch - 自动检测及动态映射Dynamic Mapping

一.自动映射: ES通过查看定义某文档的json格式就能猜测到文档结构,我们称之为自动映射,在开发过程中需要注意这些特性. 字段自动检测 在某个字段第一次出现时,如果之前没有定义过映射,ES会自动检测它可能满足的类型,然后创建对应的映射. JSON数据 ES中的数据类型 null 不会添加字段 true or false boolean floating point number double integer long object object array 依赖于第一个非null得值 stri

ElasticSearch之动态映射和模板

1 类型确定机制 mappings numeric_detection dynamic :是否支持动态添加字段 2 动态映射 希望根据不同情形,如JSON格式中的字段名称和字段类型,来确定不同类型. 3 索引模板

[Elasticsearch] 索引管理 (四) - 动态映射

动态映射(Dynamic Mapping) 当ES在文档中碰到一个以前没见过的字段时,它会利用动态映射来决定该字段的类型,并自动地对该字段添加映射. 有时这正是需要的行为,但有时不是.你或许不知道在以后你的文档中会添加哪些字段,但是你想要它们能够被自动地索引.或许你只是想要忽略它们.或者 - 尤其当你将ES当做主要的数据存储使用时 - 大概你会希望这些未知的字段会抛出异常来提醒你注意这一问题. 幸运的是,你可以通过dynamic设置来控制这一行为,它能够接受以下的选项: true:默认值.动态添

Elasticsearch 动态映射——自动检测

ES中有一个非常重要的特性——动态映射,即索引文档前不需要创建索引.类型等信息,在索引的同时会自动完成索引.类型.映射的创建. 那么什么是映射呢?映射就是描述字段的类型.如何进行分析.如何进行索引等内容. 本篇就着重讲述下,ES中映射的自动检测特性. 更多内容参考:Elastisearch知识总结 字段自动检测 在某个字段第一次出现时,如果之前没有定义过映射,ES会自动检测它可能满足的类型,然后创建对应的映射. JSON数据 ES中的数据类型 null 不会添加字段 true or false

ASP.NET路由系统实现原理:HttpHandler的动态映射

我们知道一个请求最终通过一个具体的HttpHandler进行处理,而我们熟悉的用于表示一个Web页面的Page对象就是一个HttpHandler,被用于处理基于某个.aspx文件的请求.我们可以通过HttpHandler的动态映射来实现请求地址与物理文件路径之间的分离.实际上ASP.NET路由系统就是采用了这样的实现原理.如下图所示,ASP.NET路由系统通过一个注册到当前应用的自定义HttpModule对所有的请求进行拦截,并通过对请求的分析为之动态匹配一个用于处理它的HttpHandler.

ES(一)——Windows安装ElasticSearch

一.安装JDK环境与环境变量配置 因为ElasticSearch是用Java语言编写的,所以必须安装JDK的环境,并且是JDK 1.8以上,具体操作步骤自行百度 安装完查看java版本      注意:最好还是安装jdk11或者以上的,我jdk8安装后面报错 java -version 二.官网下载最新版本ElasticSearch 下载地址:https://www.elastic.co/cn/downloads/elasticsearch,选择相应版本下载即可 三.下载其他版本 直接点击:ht

Bottle?中的基本映射和动态映射

这篇Bottle 教程是比较基础的,主要讲解Bottle?的基本映射和动态映射. 基本映射 映射使用在根据不同 URLs 请求来产生相对应的返回内容. Bottle 使用 route() 修饰器来实现映射. from bottle import route, [email protected]('/hello')def hello(): return "Hello World!" run() # This starts the HTTP server 运行这个程序,访问 http://

快速配置 Samba 将 Linux 目录映射为 Windows 驱动器,用于跨平台编程

快速配置 Samba 将 Linux 目录映射为 Windows 驱动器,用于跨平台编程  大 | 中 | 小  [ 2011-4-8 08:53 | by 张宴 ] [文章作者:张宴 本文版本:v1.0 最后修改:2011.04.08 转载请注明原文链接:http://blog.zyan.cc/samba_linux_windows/] 一.局域网内的 Linux 服务器上操作步骤: 1.安装samba(CentOS Linux): yum install samba system-confi

驱动学习之静态映射和动态映射

1:静态映射方法的特点: 内核移植时以代码的形式硬编码,如果要更改必须改源代码后重新编译内核在内核启动时建立静态映射表,到内核关机时销毁,中间一直有效对于移植好的内核,你用不用他都在那里 2:动态映射方法的特点: 驱动程序根据需要随时动态的建立映射.使用.销毁映射映射是短期临时的 3:如何选择虚拟地址映射方法 (1)2种映射并不排他,可以同时使用 (2)静态映射类似于C语言中全局变量,动态方式类似于C语言中malloc堆内存 (3)静态映射的好处是执行效率高,坏处是始终占用虚拟地址空间:动态映射