小白学ES 11 - 什么是Elasticsearch的映射(mapping) + 如何配置映射

1 映射的相关概念

1.1 什么是映射

① 映射(mapping): 定义index的元数据, 指定要索引并存储的文档的字段类型.

—— 即映射决定了Elasticsearch在建立倒排索引、进行检索时对文档采取的相关策略, 如数字类型、日期类型、文本类型等等.

—— 检索时的分析策略, 要与建立索引时的分析策略相同, 否则将导致数据不准确.

② ES对不同的类型有不同的存储和检索策略.

—— 如对full text型的数据类型(如text), 在索引时, 会经过各类处理, 比如分词、normalization(时态转换、同义词转换、大小写转换)等, 才会建立到索引中.

—— 如对exact value(如date), 在索引的分词阶段, 会将整个value作为一个关键词建立到倒排索引中.

1.2 映射的组成

每个index都有一至多个type, 每个type对应一个mapping. 每个mapping都由下述部分组成:

① 元字段: _index_type_id_source.

② field/properties(字段或属性): 同一index的不同type中, 同名的field的映射配置必须相同

—— 因为index是根据_type 元字段来区分type的, 即存储的每个文档中都有_type等元字段, 若相同名称的field的映射(_type字段的值)不同, Elasticsearch在解析时就会出现冲突.

—— 这些参数可以例外: copy_to、dynamic、enabled、ignore_above、include_in_all.

关于type的处理方法, 详见博客☆type的底层结构

1.3 元字段

每个文档都有与之关联的元数据 —— ES内部为所有的文档配备的field, 都是以下划线"_"开头的内置字段.

具体的内容将在博文 Elasticsearch的元字段 中详细讲解.

1.4 字段的类型

Elasticsearch中每个field都对应一至多个数据类型.

这部分的内容在博文 Elasticsearch字段的类型 中详细讲解.

2 如何配置mapping

2.1 创建mapping

2.1.1 必读事项

  • 创建mapping时, 可以指定每个field是否需要:

    索 引: “index”: true —— 默认配置

    不索引: “index”: false

  • 说明:

    这里使用的是Elasticsearch 5.6.10版本, 是否索引的API已经做了修改, 若使用"analyzed" | “not_analyzed” | “yes” | "no"等, 将抛出如下警告:

    #! Deprecation: Expected a boolean [true/false] for property [index] but got [not_analyzed]
    #! Deprecation: Expected a boolean [true/false] for property [index] but got [no]
    
  • mapping root object:

    每个type对应的mapping的JSON串, 包括properties, metadata(_id, _source, _type) , settings(analyzer) , 其他settings(如include_in_all)

2.1.2 创建示例

需求: 创建名为website的索引, 包含user和blog两个type. user类型中禁用元字段_all.

PUT website
{
    "mappings": {
        "user": {								// 此即为一个root object
            "_all": { "enabled": false },		// 禁用_all字段
            "properties": {
            	"name": { "type": "text" },
                "age": { "type": "integer" },
                "sex": { "type": "keyword" }
            }
        }, 
        "blog": {
            "properties": {
                "author_id": { "type": "text" },
                "title": {
                    "type": "text",
                    "analyzer": "english"
                },
                "content": { "type": "text" },
            	"publisher_id": {
                    "type": "text",
                    "index": false					// 不分词
                }, 
                "post_date": { 
                    "type": "date", 
                    "format": "strict_date_optional_time||epoch_millis"
                }
            }
        }
    }
}

2.2 更新mapping

2.2.1 必读事项

  • 映射一旦创建完成, 就不允许修改:

    —— Elasticsearch将文档索引并存储的过程中, 就是按照映射中的配置进行的. 如果后期修改了映射, 检索时对索引的处理将存在不一致的情况.

  • 只能创建index时手动建立mapping, 或者新增field mapping, 但是不能update field mapping

2.2.2 更新mapping出现异常

  • 修改已经创建好的mapping

    PUT website
    {
        "mappings": {
            "blog": {
                "properties": {
                    "author_id": { "type": "text" }
                }
            }
        }
    }
    
  • 抛出如下错误 —— 索引已经存在的异常:

    {
      "error": {
        "root_cause": [
          {
            "type": "index_already_exists_exception",
            "reason": "index [website/co1dgJ-uTYGBEEOOL8GsQQ] already exists",
            "index_uuid": "co1dgJ-uTYGBEEOOL8GsQQ",
            "index": "website"
          }
        ],
        "type": "index_already_exists_exception",
        "reason": "index [website/co1dgJ-uTYGBEEOOL8GsQQ] already exists",
        "index_uuid": "co1dgJ-uTYGBEEOOL8GsQQ",
        "index": "website"
      },
      "status": 400
    }
    

2.2.3 向mapping中添加新type

  • 向已有mapping中添加字段及其映射信息:

    PUT website/_mapping/blog		// 修改blog类型的_mapping, 注意API的顺序
    {
        "properties": {
            "new_field": {
                "type": "text",
                "index": false
            }
        }
    }
    

2.3 测试mapping

2.3.1 查看mapping

GET website/_mapping

// 响应信息如下: 
{
  "website": {
    "mappings": {
      "user": {
        "_all": {
          "enabled": false			// 禁用_all元字段
        },
        "properties": {
          "age": {
            "type": "integer"
          },
          "name": {
            "type": "text"
          },
          "sex": {
            "type": "keyword"
          }
        }
      },
      "blog": {
        "properties": {
          "author_id": {
            "type": "long"
          },
          "content": {
            "type": "text"
          },
          "new_field": {
            "type": "text",
            "index": false			// 不索引
          },
          "post_date": {
            "type": "date"
          },
          "publisher_id": {
            "type": "text",
            "index": false			// 不索引
          },
          "title": {
            "type": "text",
            "analyzer": "english"
          }
        }
      }
    }
  }
}

2.3.2 对不索引的field进行分词

"new_field"作了不索引的处理, 对其强行分词:

GET website/_analyze
{
  "field": "new_field",
  "text": "shou feng"
}

应该抛出如下错误:

{
  "error": {
    "root_cause": [
      {
        "type": "remote_transport_exception",
        "reason": "[jVSUBme][10.0.20.50:9300][indices:admin/analyze[s]]"
      }
    ],
    "type": "illegal_argument_exception",
    "reason": "Can't process field [new_field], Analysis requests are only supported on tokenized fields"
  },
  "status": 400
}

可是却正常分词了 —— 具体原因尚不可知:

{
  "tokens": [
    {
      "token": "shou",
      "start_offset": 0,
      "end_offset": 4,
      "type": "<ALPHANUM>",
      "position": 0
    },
    {
      "token": "feng",
      "start_offset": 5,
      "end_offset": 9,
      "type": "<ALPHANUM>",
      "position": 1
    }
  ]
}

版权声明

作者: ma_shoufeng(马瘦风)

出处: CSDN 马瘦风的博客

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

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

猜你喜欢

转载自blog.csdn.net/ma_shou_feng/article/details/84711019