开发者社区> elasticstack> 正文

【Elastic Engineering】Elasticsearch:Dynamic mapping

简介: Elasticsearch:Dynamic mapping
+关注继续查看

作者:刘晓国


Elasticsearch 最重要的功能之一是它试图摆脱你的方式,让你尽快开始探索你的数据。 要索引文档,你不必首先创建索引,定义映射类型和定义字段 - 你只需索引文档,那么 index,type 和 field 将自动生效。比如:

PUT data/_doc/1 
{ "count": 5 }

上面的命令将自动帮我们生成一个叫做 data 的 index,并同时生成一个叫做 _doc 的 type 及一个叫做 count 的 field。count 的数据类型是 long。这个非常方便,它不像传统的 RDMS 那样,先要创建一个数据库,让后一个 table,然后才可以向 table 里写入数据。


自动检测和添加新字段称为动态映射。 动态映射规则可以根据你的目的进行定制:


动态字段映射:管理动态 field 检测的规则

动态模板:用于配置动态添加字段的映射的自定义规则


在今天的这篇文章中,我们来分别介绍这两个方面的内容。


动态模板


假设你有包含大量字段的文档

或者在映射定义时未知的动态字段名称的文档

nested 的 key/value 对不是一个很好的解决方案

使用动态模板,你可以基于定义字段的映射


字段的数据类型, 使用 match_mapping_type

字段的名字,使用 match and unmatchmatch_pattern.

或者字段的路径,使用 path_match 及 path_unmatch.

动态模板由命名对象的数组来定义的:

"dynamic_templates": [
    {
      "my_template_name": {   (1)
        ...  match conditions ...  (2) 
        "mapping": { ... }  (3)
      }
    },
    ...
  ]

template 的名字可以是任何一个字符串

匹配的条件可以是这里的任何一种 match_mapping_type, match,match_pattern, unmatch, path_match, path_unmatch

被匹配的字段的 mapping

例如,如果我们想要将所有整数字段映射为整数而不是 long,并将所有字符串字段映射为 text 和 keyword,我们可以使用以下模板:

PUT my_index
{
  "mappings": {
    "dynamic_templates": [
      {
        "integers": {
          "match_mapping_type": "long",
          "mapping": {
            "type": "integer"
          }
        }
      },
      {
        "strings": {
          "match_mapping_type": "string",
          "mapping": {
            "type": "text",
            "fields": {
              "raw": {
                "type":  "keyword",
                "ignore_above": 256
              }
            }
          }
        }
      }
    ]
  }
}
 
PUT my_index/_doc/1
{
  "my_integer": 5, 
  "my_string": "Some string" 
}

通过上面的动态 template 映射,我们可以看到 my_integer 被映射为 integer 而不是 long。my_string 是一个 multi_field 字段。


假设你希望任何未映射的字符串字段默认情况下映射为 “keyword” 类型,那么我们可以这么定义:

PUT test2
{
  "mappings": {
    "dynamic_templates": [
      {
        "my_string_fields": {
          "match_mapping_type": "string",
          "mapping": {
            "type": "keyword"
          }
        }
      }
    ]
  }
}


match 及 unmatch


match 参数使用模式匹配字段名称,而 unmatch 使用模式排除匹配匹配的字段。


以下示例匹配名称以 long_ 开头的所有字符串字段(以_text结尾的字符串除外)并将它们映射为长字段:

PUT my_index
{
  "mappings": {
    "dynamic_templates": [
      {
        "longs_as_strings": {
          "match_mapping_type": "string",
          "match":   "long_*",
          "unmatch": "*_text",
          "mapping": {
            "type": "long"
          }
        }
      }
    ]
  }
}
 
PUT my_index/_doc/1
{
  "long_num": "5", 
  "long_text": "foo" 
}

我们可以通过如下的命令来查看它们的数据类型:

GET my_index/_mapping

显示的结果为:

{
  "my_index" : {
    "mappings" : {
      "dynamic_templates" : [
        {
          "longs_as_strings" : {
            "match" : "long_*",
            "unmatch" : "*_text",
            "match_mapping_type" : "string",
            "mapping" : {
              "type" : "long"
            }
          }
        }
      ],
      "properties" : {
        "long_num" : {
          "type" : "long"
        },
        "long_text" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

从上面,我们可以看出来,long_num 的数据类型是 long,而 long_text 的数据类型是 text。


控制动态字段


默认情况下,当在文档中找到以前未见过的字段时,Elasticsearch 会将新字段添加到类型映射中。 通过将 dynamic 参数设置为 false(忽略新字段)或 strict(如果遇到未知字段则抛出异常),可以在文档和对象级别禁用此行为。


在生产(product) 环境中,你极有可能会创建你的 mapping 在索引你的数据之前,而且你极有可能不想你的 mapping 会被修改:

POST blogs/_doc/2
{
    "some_new_field": "What should we do?" 
}

在通常的情况下,上面的一个命令可能会自动帮我们在 blogs 索引里增加一个新的叫做 some_new_field 的字段。


你可以使用 “dynamic” 属性(三个选项)控制添加到映射的新字段的效果:


image.png

上面的表格显示,当一个新的字段被添加到一个索引中,并且这个字段之前没有在 mapping 中定义:


在 dynamic 为 true 时,这个文档将被建立索引,从而新增加的字段将是可以被搜索及应用于聚合,mapping 也会自动更新

在 dynamic 为 true 时,这个文档将被建立索引,而且这个 runtime 字段可以被搜索,但是字段没有被分词。关于 runtime 的更多阅读,请参阅文章 “Elasticsearch:动态创建 Runtime fields - 7.11 发行版”。

在 dynamic 为 false 时,这个文档将被建立索引,但是新的字段将不被建立索引,mapping 将不被更新(包含新的的字段的mapping)

在 dynamic 为 strict 时,这个文件将不被建立索引

PUT blogs_example/_mapping
{
  "dynamic": "strict"
}

在上面我们在 mapping 中加入了 dynamic,并且设置为 strict,它表明如果现有的 mapping 里没有定义这个字段,那么就不 index 这个文档。

PUT /blogs_example/_doc/1
{
  "new_field": "this is a new field"
}

如果new_field从来没有在mapping中定义过,那么,上面的命令会出现如下的错误:

{
  "error": {
    "root_cause": [
      {
        "type": "strict_dynamic_mapping_exception",
        "reason": "mapping set to strict, dynamic introduction of [new_field] within [_doc] is not allowed"
      }
    ],
    "type": "strict_dynamic_mapping_exception",
    "reason": "mapping set to strict, dynamic introduction of [new_field] within [_doc] is not allowed"
  },
  "status": 400
}


如果这个问题出现了,我们必须修改我们现有的 index 的 mapping:

PUT blogs_example/_mapping
{
  "properties": {
    "new_field": {
      "type": "text"
    }
  }
}

那么重新运行之前的那个命令就可以了。


settings 以防止映射爆炸


在索引中定义太多字段是一种可能导致映射爆炸的情况,这可能导致内存不足错误和难以恢复的情况。 这个问题可能比预期更常见。 例如,考虑插入的每个新文档引入新字段的情况。 这在动态映射中非常常见。 每次文档包含新字段时,这些字段最终都会出现在索引的映射中。 这并不需要担心少量数据,但随着映射的增加,它可能会成为一个问题。 以下设置允许你限制可手动或动态创建的字段映射的数量,以防止错误的文档导致映射爆炸:


index.mapping.total_fields.limit


索引中的最大字段数。 字段和对象映射以及字段别名都计入此限制。 默认值为1000


index.mapping.depth.limit


字段的最大深度,以内部对象的数量来衡量。 例如,如果所有字段都在根对象级别定义,则深度为1.如果有一个对象映射,则深度为2,等等。默认值为20。


index.mapping.nested_fields.limit


索引中不同 nested 映射的最大数量,默认为50。


index.mapping.nested_objects.limit


所有 nested 类型中单个文档中嵌套 JSON 对象的最大数量,默认为10000。


index.mapping.field_name_length.limit


设置字段名称的最大长度。 默认值为 Long.MAX_VALUE(无限制)。 此设置实际上不是解决映射爆炸的问题,但如果要限制字段长度,则可能仍然有用。 通常不需要设置此设置。 默认是可以的,除非用户开始添加大量具有真正长名称的字段。


上面的字段都可以在一个 index 的设置中进行设置,比如:

PUT test_blog 
{
  "settings": {
    "index.mapping.total_fields.limit": 2000,
    "number_of_replicas": 0,
    "number_of_shards": 1
  }
}

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
YApi 官网说明文档-接口操作
为方便和前端, 节省沟通成本, 编写接口文档非常有比较 使用过swagger, 觉得入侵性太大. POST又感觉和项目结合的不太紧密. 所以一直在寻找 新的接口阅读/生成/测试工具. 下面介绍一下YApi.
5 0
Python MySQL数据库1:数据存储介绍、阿里云安装myspl(使用)以及客户端Navicat使用(上)
Python MySQL数据库1:数据存储介绍、阿里云安装myspl(使用)以及客户端Navicat使用
7 0
【EL与JSTL表达式】学习JSP之后,这是你不得不知道的技术
之前我们已经完成了对JSP的学习,但是还有一些其他的东西我们必须得知道,今天我们来学习EL与JSTL表达式。它们将简化JSP的书写并且使得JSP更加强大。但是如果你对JSP一无所知的话建议你先去看一下之前入门JSP的文章。
7 0
Python MySQL数据库1:数据存储介绍、阿里云安装myspl(使用)以及客户端 Navicat使用(下)
Python MySQL数据库1:数据存储介绍、阿里云安装myspl(使用)以及客户端 Navicat使用(下)
6 0
如何做一个塔防小游戏(四)
嗨!大家好,我是小蚂蚁。今天我们继续分享制作一个塔防小游戏的第四节,如何实现炮塔的升级和出售功能。
3 0
Android Studio快捷键以及使用技巧
Android Studio快捷键以及使用技巧
4 0
文件找不到!
谈文件异常前,先要给各位复习一下磁盘 IO 的知识,说到 IO,就不得不提一下计算机的存储系统体系,主要分为 CPU、内存、磁盘,而磁盘又分为机械磁盘和固态硬盘。一般来说,离 CPU 越近,价格越贵,速度越快,容量越小;反之,离 CPU 越远,价格越便宜,速度越慢,容量越大,见下图。
4 0
如何使用滚动列表插件?
嗨!大家好,我是小蚂蚁。今天来分享一下小游戏制作工具中的滚动列表插件的使用方法。滚动列表在小游戏或者小程序中经常的会被用到,例如关卡选择列表,背包列表,信息展示列表等。滚动列表主要的作用是可以在一个有限的指定的范围内,展示大量的信息。
3 0
小白ECS使用体验
初次使用ECS,从使用原因,使用攻略,使用总结三方面进行阐述ECS服务器
5 0
Maven 仓库介绍 和 nexus 私服搭建
Maven 仓库 在 Maven 的术语中,仓库是一个位置(place)。 Maven 仓库是项目中依赖的第三方库,这个库所在的位置叫做仓库。 在 Maven 中,任何一个依赖、插件或者项目构建的输出,都可以称之为构件。 Maven 仓库能帮助我们管理构件(主要是 JAR ),它就是放置所有 JAR 文件(WAR,ZIP,POM 等)的地方。
6 0
+关注
elasticstack
Elastic 社区布道师
90
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
OceanBase 入门到实战教程
立即下载
阿里云图数据库GDB,加速开启“图智”未来.ppt
立即下载
实时数仓Hologres技术实战一本通2.0版(下)
立即下载