如何理解 Elasticsearch 中的 dynamic mapping

前言

Dynamic mapping 是 Elasticsearch 中的特性,指的是当 Elasticsearch 遇到文档中以前未遇到的字段,它用什么数据类型来进行映射。这看似是一个非常好的功能,因为有了 Dynamic Mapping 的机制,使得我们无需手动定义Mappings,ES 会自动推算出字段的类型。但是在某些场景下是有问题的,如果 Elasticsearch 是作为重要的数据存储,如果遇到前所未有的字段,我们可能希望 Elasticsearch 直接抛出异常而不是直接索引,这样可以及时发现问题。

例如:

PUT es_books/_doc/1
{
  "title":" how to master elasticsearch"
}

查看 index mapping

GET es_books/_mapping

输出如下
{
  "es_books" : {
    "mappings" : {
      "properties" : {
        "title" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

当我们索引一个新的字段后,会发现索引的mapping 已经发生变化:

PUT es_books/_doc/2
{
  "title":"ElasticSearch 7.0",
  "public_date":"2017"
}

查看 index mapping 

```json
{
  "es_books" : {
    "mappings" : {
      "properties" : {
        "public_date" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "title" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

如何控制动态字段

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

1. dynamic = strict

将 dynamic mapping 设置为 strict:发现文档将不会被索引:


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

写入数据:

PUT es_books/_doc/4
{
  "title":"ElasticSearch 7.0",
  "public_date":"2017",
  "first_author" : "rudonx"
}

执行后反馈如下:

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

2. dynamic = false

PUT dynamic_mapping_test/_mapping
{
 "dynamic": false
}


PUT dynamic_mapping_test/_doc/2
{
 "newField":"field2"
}

我们发现文档看起来可以被索引,返回如下:

{
  "_index" : "dynamic_mapping_test",
  "_type" : "_doc",
  "_id" : "2",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 2,
    "failed" : 0
  },
  "_seq_no" : 1,
  "_primary_term" : 1
}

但是新的字段没有被索引, 该字段不可以被搜索:

POST dynamic_mapping_test/_search
{
 "query":{
 "match":{
 "newField":"field2"
    }
  }
}

返回如下:

{
  "took" : 4,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 0,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  }
}
dynamic mapping的一些参数

使用 strict 是一种比较严格的方式,如果实际的业务上不可避免的有新字段的加入,我们只能使用 dynamic = true 的设置,在索引中定义太多字段可能会导致索引膨胀,对性能造成损失,我们建议使用一些参数来控制 mapping 的行为。

1. index.mapping.total_fields.limit

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

2, index.mapping.nested_fields.limit

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

3. index.mapping.depth.limit

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

设置的方式如下:

PUT /dynamic_mapping_test/_settings
{
  "index.mapping.total_fields.limit": 200,
  "index.mapping.depth.limit" : "50"
}

查看 index setting
GET dynamic_mapping_test/_settings

输出如下:

{
  "dynamic_mapping_test" : {
    "settings" : {
      "index" : {
        "mapping" : {
          "total_fields" : {
            "limit" : "200"
          },
          "depth" : {
            "limit" : "50"
          }
        },
        "number_of_shards" : "1",
        "provided_name" : "dynamic_mapping_test",
        "creation_date" : "1644810265240",
        "number_of_replicas" : "1",
        "uuid" : "ECDPqm-RQ22y8-eRcWQhjQ",
        "version" : {
          "created" : "7100299"
        }
      }
    }
  }
}

总结

总结下控制dynamic mapping 的参数 dynamic 的三种取值:

  1. 在 dynamic 为 true 时,这个文档将被建立索引,因此新增加的字段将是可以被搜索的,mapping 也会自动更新

  2. 在 dynamic 为 false 时,这个文档将被建立索引,但是新的字段将不被建立索引,mapping 将不被更新。

  3. 在 dynamic 为 strict 时,这个文档将不被建立索引,返回错误信息。

取值doc indexed ?fields indexed ?mapping updated?
true
false
strict

综上所述,如果您的业务对数据要求非常严格,建议您使用 strict。

更多功能,您可以参考文末的官方文档。

参考文档

[1 https://www.elastic.co/guide/en/elasticsearch/reference/7.17/dynamic.html#dynamic-parameters

[2] https://www.elastic.co/guide/en/elasticsearch/reference/7.17/mapping-settings-limit.html#mapping-settings-limit

如果您有其他问题,欢迎您联系火山引擎技术支持服务

0
0
0
0
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论