Loading

Elasticsearch:Mapping

概述

  • Mapping定义了文档(document)及其包含的字段(filed)在存储和被索引时的过程和方式。
  • 每个文档都是一组字段的集合,而每个字段也有自己的数据类型。Mapping中不仅包含了与文档相关的字段列表,还包括元数据字段(例如_source),因此可以自定义文档相关元数据的处理方式。
  • Mapping有Dynamic(动态生成)和Explicit(显式指定)两种实现方式,可根据字段的特点配合使用。

Dynamic Mapping

我们只需创建一条文档并指定其所在索引,Dynamic Mapping便会为我们自动生成索引、字段以及字段类型。

PUT /my_index/_doc/first_doc
{
  "num": 5, 
  "text": "5"
}

查看该索引的Mapping,我们发现字段值为数字的num字段的类型自动映射为long类型。而text字段映射为了text类型,其子字段tex.keyword类型则为keyword,可用于排序和聚合等操作(详见:https://www.elastic.co/guide/en/elasticsearch/reference/current/multi-fields.html)。

GET /my_index/_mapping

// 返回
{
  "my_index" : {
    "mappings" : {
      "properties" : {
        "num" : {
          "type" : "long"
        },
        "text" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

但大多数情况下,我们可能希望值为"123"和"2021/02/26"这样的字段能够分别映射为long和date类型,这时便需要对Dynamic Mapping的方式进行自定义。

Dynamic field mappings

当我们将mappings.dynamic属性设置为trueruntime后,便可以增加Dynamic Mapping的映射规则。值得一提的是,runtime这种Mapping方式仍处于beta测试中。

Json数据类型                      mappings.dynamic: true                      mappings.dynamic: runtime                   
null 不添加该字段 不添加该字段
true or false bool bool
double float double
integer long long
object object object
array 由数组第一个非空值的类型决定 由数组第一个非空值的类型决定
检测为日期的string date date
检测为数字的string float or long double or long
其他string 带有.keyword子字段的text keyword

对于数据类型为object的字段,在两种规则下都会将其包含的多个字段映射在mappings.properties.<object-filed>.properties中。我们以mappings.dynamic: true为例,检验Dynamic Mapping的处理方式。由于数字检测是默认关闭的(日期检测默认开启),因此还要先对索引的Mapping进行相关设置:

PUT /my_index/
{
  "mappings": {
    "dynamic": true,
    "numeric_detection": true
  }
}

然后在不指定Mapping的情况下向索引中加入一个文档:

PUT /my_index/_doc/1
{
  "one": null,
  "two": true,
  "three": 1.11111111111111111111,
  "four": 1,
  "five": {
    "one": "3",
    "two" : "true"
  },
  "six": "2021/02/26",
  "seven": "1",
  "eight" : "koktlzz"
}

随后即可查看该索引中各字段的类型:

GET /my_index/_mapping

// 返回
{
  "my_index" : {
    "mappings" : {
      "dynamic" : "true",
      "numeric_detection" : true,
      "properties" : {
        "eight" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "five" : {
          "properties" : {
            "one" : {
              "type" : "long"
            },
            "two" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            }
          }
        },
        "four" : {
          "type" : "long"
        },
        "seven" : {
          "type" : "long"
        },
        "six" : {
          "type" : "date",
          "format" : "yyyy/MM/dd HH:mm:ss||yyyy/MM/dd||epoch_millis"
        },
        "three" : {
          "type" : "float"
        },
        "two" : {
          "type" : "boolean"
        }
      }
    }
  }
}

Dynamic template

我们还可以通过模板(Dynamic template)进一步地自定义索引字段的Mapping方式,而模板与字段的匹配规则有以下三种:

  • match_mapping_type:匹配字段的数据类型;
  • matchunmatch:匹配字段的名称;
  • path_matchpath_unmatch:匹配字段的全路径(如<object>.*.<filed>)。

一个典型的Dynamic template的基本配置如下:

  "dynamic_templates": [
    {
      "dynamic_template_name": { 
        ...  match conditions ... // 使用上述三种规则匹配相关字段
        "mapping": { ... }        // 指定匹配字段的Mapping方式
      }
    },
    ...
  ]

我们使用一个复杂的模板为例,展示Dynamic template对字段的映射方式:

PUT my_index
{
  "mappings": {
    "dynamic_templates": [{
      "longs_as_strings": {
        "match_mapping_type": "string",
        "match": "long_*",
        "unmatch": "*_text",
        "mapping": {
          "type": "long"
          }
        }
      }, {
      "full_name": {
        "path_match": "name.*",
        "path_unmatch": "*.middle",
        "mapping": {
          "type": "text"
        }
      }
    }]
  }
}

该模板规定了两种匹配规则:名称以"long"开头、不以"text"结尾且类型为string的字段将会被映射为long类型;name对象中除middle外的字段将会被映射为text类型:

PUT my_index/_doc/1
{
  "long_num": "5", 
  "long_text": "foo",
  "name": {
    "first":  "John",
    "middle": "Winston"
  }
}

GET /my_index/_mapping
// 返回
{
  ...
  "properties" : {
    "long_num" : {
      "type" : "long"
    },
    "long_text" : {
      "type" : "text",
      "fields" : {
        "keyword" : {
          "type" : "keyword",
          "ignore_above" : 256
        }
      }
    },
    "name" : {
      "properties" : {
        "first" : {
          "type" : "text"
        },
        "middle" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

Explicit Mapping

除了让Elasticsearch为我们动态生成Mapping外,我们当然也可以显式地指定索引中各字段的Mapping方式,如:

PUT /my_index
{
  "mappings": {
    "properties": {
      "age":    { "type": "integer" },  
      "email":  { "type": "keyword"  }, 
      "name":   { "type": "text"  }     
    }
  }
}

对于一个已定义Mapping的索引,我们无法更新其中已存在的字段Mapping方式,但是可以增加字段。相比于创建,PUT请求的URL多了一个"/_mapping":

PUT /my_index/_mapping
{
  "properties": {
    "employee-id": {
      "type": "keyword"
    }
  }
}

之前我们使用了GET /my_index/_mapping的方式查看索引中的Mapping。而如果只想了解其中几个特定字段的Mapping,可以这样做:

GET /my_index/_mapping/field/employee-id

// 返回
{
  "my_index" : {
    "mappings" : {
      "employee-id" : {
        "full_name" : "employee-id",
        "mapping" : {
          "employee-id" : {
            "type" : "keyword"
          }
        }
      }
    }
  }
}

除了上述的基本数据类型外,Elasticsearch还支持多种数据类型,详见官方文档。而除了通常用来存储数据的字段外,每个文档还包含一些元数据字段,如_source字段保存了文档内容的原始JSON文件。

Mapping parameters

在字段的Mapping规则中,我们可以添加一些参数从而让字段的搜索结果更加符合我们的预期。详见官方文档,此处介绍几个相对重要的Mapping参数:

  • index:默认为true,代表是否对该字段进行Text Analysis。若设置为false,则只能通过完全匹配搜索到。常用于对时间序列字段的设置中;
  • enable:默认为true,代表该字段是否被索引。若设置为false,则完全不会被搜索到且不会影响文档的评分,只能在_source中找到该字段;
  • norms:默认为true,代表该字段是否参与评分。若设置为false,则可以减少磁盘占用;
  • doc_value:默认为true。若设置为false,则无法对该字段进行排序、聚合和脚本访问等操作;
  • filedata:默认为false,代表是否对排序、聚合和脚本访问等操作进行优化。若设置为true,则会占用大量内存;
  • store:默认为false,代表数据的存储方式,可以将经常被搜索且较小字段的store参数设置为true来单独存储。相比从_source中搜索,这样设置可以减少IO操作,从而提高效率;
posted @ 2021-03-12 00:59  koktlzz  阅读(97)  评论(0编辑  收藏  举报