Mapping 映射

概念

Mapping 类似于数据库中的表定义,作用如下:

  • 定义索引中的字段名称
  • 定义字段的数据类型
  • 定义字段倒排索引的相关配置

    字段的数据类型

    | 简单类型 | Text | 文本类型,支持分词检索 | | —- | —- | —- | | | Keyword | 关键字类型,不支持分词检索 | | | Date | 时间类型 | | | Integer | 整型 | | | Floating | 浮点型 | | | Boolean | 布尔型 | | | IPv4 & IPv6 | IP地址 | | 复杂类型 | 对象类型 / 嵌套类型 | 对象 | | 特殊类型 | geo_point | 地图坐标 | | | geo_shape | 地图坐标 | | | percolator | 地图坐标 |

Dynamic Mapping

在写入文档的时候,如果索引不存在,会自动创建索引,Dynamic Mapping的机制使得我们无需手动定义 Mapping,Elasticsearch会根据文档信息推断出字段的类型。
如果将 Dynamic 设置为 true 时,一旦有新增字段的文档写入,Mapping 也会同时更新。
如果将 Dynamic 设置为 false 时,Mapping 不会被更新,新增的字段也将无法被索引,但是新增的字段信息依然会出现在_source中。
而如果已有字段定义,写入不同的数据类型的时候,也不会触发 Mapping 字段定义的更新,即不支持修改字段定义,如果希望对已定义字段进行修改,则需要通过 Reindex API,重建索引。
设置 Dynamic Mapping

  1. PUT {索引名称}
  2. {
  3. "mapping": {
  4. "_doc": {
  5. "dynamic": "false"
  6. }
  7. }
  8. }
true false strict
文档可以索引 YES YES NO
字段可以索引 YES NO NO
Mapping被更新 YES NO NO

能否更改 Mapping 字段类型,存在两种情况:

  1. 新增字段
    1. Dynamic 设为 true 时,一旦由新增字段的文档写入,Mapping也同时被更新。
    2. Dynamic 设为 false 时,Mapping 不会被更新,新增字段的数据无法被索引,但信息会出现在 _source。
    3. Dynamic 设为 Strict时,文档写入失败。
  2. 对已有字段,一旦已有数据写入,就不宰支持修改字段的定义
    1. Lucene 实现的倒排索引,一旦生成,就不允许修改,如果希望改变字段类型,必须 Reindex API,重建索引。

类型自动识别

Json 类型 Elasticsearch 类型
字符串
- 匹配日期格式,设置成Data
- 匹配数字格式设置为 float或者long,该选项默认关闭
- 设置为 Text,并增加 keyword 子字段
布尔值 boolean
浮点数 float
整数 long
对象 Object
数组 由第一个非空数组的类型决定
空值 忽略

定义 Mapping

  1. PUT {索引名称}
  2. {
  3. "mappings": {
  4. "properties": {
  5. "{字段}": {
  6. "type": "text",
  7. "index": true,
  8. "index_options":"docs",
  9. "null_value": false,
  10. "copy_to": "new_field"
  11. }
  12. }
  13. }
  14. }
字段参数 描述
type 字段类型
index 是否能被索引,默认 true
index_options 倒排索引记录级别 默认 docs 级别, text类型默认 postions 级别
- docs:记录 doc id
- freqs:记录 doc id 和 term frequencies
- position:记录 doc id / term frequencies / term position
- offsets:记录 doc id / term frequencies / term position / character offects
null_value 是否允许实现对NULL值索引,默认 “NULL”,备注:只有 keyword 类型支持
copy_to 将当前字段拷贝到指定目标字段,copy_to的目标字段不会出现在搜索结果集中

建议

  • 参考API手册
  • 为了减少输入的工作量,减少出错概率,可以依照以下步骤
    • 创建一个临时的 index,写入一些样本数据
    • 通过访问 Mapping API 获得该临时文件的动态 Mapping 定义
    • 修改后使用该配置创建你的 Mapping 定义
    • 删除临时索引

      查看 Mapping 定义

      1. GET /{index_name}/_mapping

      多字段类型特性

      查询很少是简单一句话的 match 匹配查询。通常我们需要用相同或不同的字符串查询一个或多个字段,也就是说,需要对多个查询语句以及它们相关度评分进行合理的合并。
      image.png
      1. PUT products
      2. {
      3. "mappings": {
      4. "properties": {
      5. "company": {
      6. "type": "text",
      7. "fields": {
      8. "keyword": {
      9. "type": "keyword",
      10. "ignore_above": 256
      11. }
      12. }
      13. },
      14. "comment": {
      15. "type": "text",
      16. "fields": {
      17. "english_comment": {
      18. "type": "text",
      19. "analyzer": "english",
      20. "search_analyzer": "english"
      21. }
      22. }
      23. }
      24. }
      25. }
      26. }

      自定义分析器 Analyzer

      虽然Elasticsearch带有一些现成的分析器,然而在分析器上Elasticsearch真正的强大之处在于,你可以通过在一个适合你的特定数据的设置之中组合字符过滤器、分词器、词汇单元过滤器来创建自定义的分析器。
阶段 描述
Character Filters 针对原始文本处理,例如去除html
Tokenizer 按照规则切分为单词
Token Filter 将切分的单词进行加工,小写,删除停用词,增加同义词等

image.png

字符过滤器 (character Filter)

在 Tokenizer 之前对文本进行处理,例如增加删除及替换字符。可以配置多个 Character Filter 。会影响 Tokenizer 的 position 和 offset 信息。
官方字符过滤器

  1. POST _analyze
  2. {
  3. "tokenizer":"keyword",
  4. "char_filter":["html_strip"],
  5. "text": "<b>hello world</b>"
  6. }
  1. POST _analyze
  2. {
  3. "tokenizer": "keyword",
  4. "char_filter": [
  5. {
  6. "type" : "mapping",
  7. "mappings" : [ "- => _"]
  8. }
  9. ],
  10. "text": "123-456, I-test! test-990 650-555-1234"
  11. }
  1. GET _analyze
  2. {
  3. "tokenizer": "keyword",
  4. "char_filter": [
  5. {
  6. "type" : "pattern_replace",
  7. "pattern" : "http://(.*)",
  8. "replacement" : "$1"
  9. }
  10. ],
  11. "text" : "http://www.elastic.co"
  12. }

分词器 (Tokenizer)

分词器可以将原始文本按照一定的规则,切分成词(term or token)

分词器 作用
whitespace 以空格方式进行分词
standard 使用 Unicode 文本分割算法
uax_url_email 对url和emai进行分词
pattern 正则表达式分词
keyword 不进行处理
path hierarchy 文件路径分词
  1. POST _analyze
  2. {
  3. "tokenizer":"whitespace",
  4. "text": "hello world"
  5. }

Token 过滤器 (Token Filter)

最后,词条按顺序通过每个 token 过滤器 。这个过程可能会改变词条(例如,小写化 Quick ),删除词条(例如, 像 aandthe 等无用词),或者增加词条(例如,像 jumpleap 这种同义词)

过滤器 作用
lowercaes 转大小写
stop 删除停用词
synonym 添加同义词
  1. POST _analyze
  2. {
  3. "tokenizer":"whitespace",
  4. "filter": ["lowercaes", "stop"],
  5. "text": "hello world"
  6. }

自定义Analyzer

  1. PUT {索引名称}
  2. {
  3. "settings": {
  4. "analysis": {
  5. "analyzer": {
  6. "自定义分词器名称": {
  7. "type": "custom",
  8. "char_filter": [
  9. "自定义characterFilter名称"
  10. ],
  11. "tokenizer": "自定义Tokenizer名称",
  12. "filter": ["自定义filter名称", "stop"],
  13. }
  14. },
  15. "tokenizer": {
  16. "自定义Tokenizer名称": {
  17. "type": "pattern",
  18. "pattern": "[.,!?]"
  19. }
  20. },
  21. "char_filter": {
  22. "自定义characterFilter名称": {
  23. "type" : "mapping",
  24. "mappings" : [ "- => _"]
  25. }
  26. },
  27. "filter": {
  28. "自定义filter名称": {
  29. "type": "stop",
  30. "stopwords": "_englis_"
  31. }
  32. }
  33. }
  34. }
  1. PUT index_name/
  2. {
  3. "settings": {
  4. "analysis": {
  5. "filter": {
  6. "pinyin_filter": {
  7. "type" : "pinyin",
  8. "keep_separate_first_letter" : false,
  9. "keep_full_pinyin" : false,
  10. "keep_joined_full_pinyin": true,
  11. "keep_original" : true,
  12. "limit_first_letter_length" : 16,
  13. "lowercase" : true,
  14. "remove_duplicated_term" : true,
  15. "none_chinese_pinyin_tokenize": false,
  16. "keep_none_chinese": true
  17. }
  18. },
  19. "analyzer": {
  20. "ik_synonym_pinyin": {
  21. "type": "custom",
  22. "tokenizer": "ik_max_word",
  23. "filter": ["pinyin_filter"]
  24. }
  25. }
  26. }
  27. },
  28. "mappings" : {
  29. "properties" : {
  30. "title" : {
  31. "type" : "text",
  32. "analyzer": "ik_synonym_pinyin",
  33. "search_analyzer": "ik_smart"
  34. }
  35. }
  36. }
  37. }

Index Template

Index Template 能够帮助你设定 Mappings 和 Settings,并按照一定的规则,自动匹配到新创建的索引之上。

  • 模板仅在一个索引被新创建时,才会产生作用。修改模板不会影响已创建的索引
  • 你可以设定多个索引模板,这些设置会被“merge”在一起
  • 你可以指定“order”的值,控制“merging”的过程
    1. PUT _template/template_name
    2. {
    3. "index_patterns": ["*"],
    4. "order": 0,
    5. "version": 1,
    6. "settings": {
    7. "number_of_shards": 1,
    8. "number_of_replicas": 1
    9. }
    10. }
    1. PUT _template/template_name
    2. {
    3. "index_patterns": ["test*"],
    4. "order": 1,
    5. "settings": {
    6. "number_of_shards": 1,
    7. "number_of_replicas": 2
    8. },
    9. "mappings": {
    10. "date_detection": false,
    11. "numeric_detection": true
    12. }
    13. }
    索引被新创建时,会按照以下流程执行
  1. 应用 Elasticsearch 默认的 settings 和 mappings
  2. 应用 order 数值低的 Index Template 中的设定
  3. 应用 order 高的 Index Template 中的设定,之前的设定会被覆盖
  4. 应用创建索引时,用户所指定的 Settings 和 Mappings,并覆盖之前模板中的设定

    Dynamic Template 动态模板

    Dynamic Template 的作用是根据 Elasticsearch 识别的数据类型,结合字段名称,来动态设定字段类型,例如:
  • 所有的字符串类型都设定成 Keyword,或者关闭 Keyword 字段
  • is开头的字段都设置成 boolean
  • long_ 开头的都设置成 long 类型

Dynamic Template 是定义在某个索引的Mappings 中的,template有一个名称,匹配规则是一个数组。

  1. # my_index:索引名称
  2. # dynamic_templates:动态模板名称
  3. # strings_as_boolean / strings_as_keywords:模板规则名称
  4. PUT my_index
  5. {
  6. "mappings": {
  7. "dynamic_templates": [
  8. {
  9. "strings_as_boolean": {
  10. "match_mapping_type": "string",
  11. "match":"is*",
  12. "mapping": {
  13. "type": "boolean"
  14. }
  15. }
  16. },
  17. {
  18. "strings_as_keywords": {
  19. "match_mapping_type": "string",
  20. "mapping": {
  21. "type": "keyword"
  22. }
  23. }
  24. }
  25. ]
  26. }
  27. }
字段 名称 描述
match_mapping_type 匹配映射类型 数据类型的匹配:boolean(布尔类型),date(日期),double(浮点型),long(长整型),object(对象类型),string(字符类型)
match 匹配 匹配字段名称,允许*表示模糊匹配
unmatch 不匹配 不匹配字段名称,允许*表示模糊匹配
path_match 路径匹配 与match一致,但是可以映射匹配到子字段上
path_unmatch 路径不匹配 与unmatch一致,但是可以映射匹配到子字段上

索引重建

使用场景

  • 索引的 Mappings 发生变更:字段类型变更,分词器及字典更新
  • 索引的 Settings 发生变更:索引的主分片数发生改变
  • 集群内,集群间需要做数据迁移

    Update By Query

    ```json

    blogs:索引名称

    POST blogs/_update_by_query {

}

  1. <a name="wglnp"></a>
  2. ## Reindex
  3. Elasticsearch 不允许在原有 Mapping 上对字段类型进行修改,只能创建新的索引,并且设定正确的字段类型,再重新导入数据。
  4. ```json
  5. # blogs:原索引名称
  6. # blogs_fix:新索引名称
  7. POST _reindex
  8. {
  9. "source": {
  10. "index": "blogs"
  11. },
  12. "dest": {
  13. "index": "blogs_fix"
  14. }
  15. }

使用场景

  • 修改索引的主分片数
  • 改变字段的Mapping 中的字段类型
  • 集群内数据迁移 / 跨集群的数据迁移

OP Type
设置索引重建只会创建不存在的文档,文档如果已经存在,会导致版本冲突

  1. # blogs:原索引名称
  2. # blogs_fix:新索引名称
  3. POST _reindex
  4. {
  5. "source": {
  6. "index": "blogs"
  7. },
  8. "dest": {
  9. "index": "blogs_fix",
  10. "op_type": "create"
  11. }
  12. }

跨集群 Reindex
image.png
查看 Task API
image.png

创建基于时间序列的索引

基于 Date Math 的方式,容易使用,但如果时间发生变化,需要重新部署代码

格式 最终生成索引
logs-2022.03.26
logs-2022.03
logs-2022..7.29
  1. # POST /<logs-{now/d}/_search
  2. POST /%3Clogs-%7Bnow%2Fd%7D%3E/_search
  3. # POST /<logs-{now/w}/_search
  4. POST /%3Clogs-%7Bnow%2Fw%7D%3E/_search