elasticsearch中文档映射Mapping用法详解
  TEZNKK3IfmPf 2023年11月14日 16 0

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

  • 定义索引中的字段的名称
  • 定义字段的数据类型,例如字符串,数字,布尔等
  • 字段,倒排索引的相关配置(Analyzed or Not Analyzed,Analyzer)

ES中Mapping映射可以分为动态映射和静态映射。

动态映射:

        在关系数据库中,需要事先创建数据库,然后在该数据库下创建数据表,并创建表字段、类型、长度、主键等,最后才能基于表插入数据。而Elasticpearch中不需要定义Mapping映射(即关系型数据库的表、字段等),在文档写入Elasticsearch时,会根据文档字段自动识别类型,这种机制称之为动态映射。

        动态映射(Dynamic Mapping)的机制,使得我们无需手动定义Mappings,Elasticsearch会自动根据文档信息,推算出字段的类型。但是有时候会推算的不对,例如地理位置信息。当类型如果设置不对时,会导致一些功能无法正常运行,例如Range查询

静态映射:

        静态映射是在Elasticsearch中也可以事先定义好映射,包含文档的各字段类型、分词器等,这种方式称之为静态映射。

Dynamic Mapping类型自动识别:

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

动态映射:

创建文档(es根据数据类型,会自动创建映射)

# 创建文档(es根据数据类型,会自动创建映射)
PUT /user/_doc/1
{
  "name": "张三",
  "age": 26,
  "address": "北京市朝阳区"
}

运行结果:

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

获取文档映射

# 获取文档映射
GET /user/_mapping

运行结果:

{
  "user" : {
    "mappings" : {
      "properties" : {
        "address" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "age" : {
          "type" : "long"
        },
        "name" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

Mapping一旦建立后,那后期是否还可以更新或者修改Mapping字段类型信息呢?

情况一:新增加字段

  • dynamic设为true时,一旦有新增字段的文档写入,Mapping 也同时被更新
  • dynamic设为false,Mapping 不会被更新,新增字段的数据无法被索引,但是信息会出现在_source中
  • dynamic设置成strict(严格控制策略),文档写入失败,抛出异常

elasticsearch中文档映射Mapping用法详解

情况二:对于已有字段,一旦已经有数据写入,就不再支持修改字段定义

  • Lucene实现的倒排索引,—旦生成后,就不允许修改
  • 如果希望改变字段类型,必须Reindex API,重建索引

        如果修改了字段的数据类型,会导致已被索引的数据无法被搜索;但是如果是增加新的字段,就不会有这样的影响。

首先新建mapping信息:

PUT user2
{
  "mappings": {
    "dynamic": "strict",
    "properties": {
      "name": {
        "type": "text"
      },
      "address": {
        "type": "object",
        "dynamic": "true"
      }
    }
  }
}

运行结果:

{
  "acknowledged" : true,
  "shards_acknowledged" : true,
  "index" : "user2"
}

插入新的文档,原因为age为新增字段报错,抛出异常,之前mapping中dynamic设置的为strict

# 插入新的文档,原因为age为新增字段报错,抛出异常,之前mapping中dynamic设置的为strict
PUT user2/_doc/1
{
  "name": "张三",
  "age": 26,
  "address": {
    "provienc": "北京市",
    "city": "北京市"
  }
}

运行结果:

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

接下来修改dynamic信息,更改为true后再次执行上面的语句:

# 修改mapping信息
PUT user2/_mapping
{
  "dynamic": "true"
}

运行结果:

{
  "acknowledged" : true
}

dynamic修改为true后,再次插入一个新的文档

# dynamic修改为true后,再次插入一个新的文档
PUT user2/_doc/1
{
  "name": "张三",
  "age": 26,
  "address": {
    "provienc": "北京市",
    "city": "北京市"
  }
}

运行结果:

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

添加新字段后,再次查询mapping信息

# 添加新字段后,再次查询mapping信息
GET user2/_mapping

运行结果:  【可以看出新增加了age字段的信息】

{
  "user2" : {
    "mappings" : {
      "dynamic" : "true",
      "properties" : {
        "address" : {
          "dynamic" : "true",
          "properties" : {
            "city" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            },
            "provienc" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            }
          }
        },
        "age" : {
          "type" : "long"
        },
        "name" : {
          "type" : "text"
        }
      }
    }
  }
}

对已经存在的mapping映射进行修改:

具体方法:

  1. 如果要推倒现有的映射,你得重新建立—个静态索引
  2. 然后把之前索引里的数据导入到新的索引里
  3. 删除原创建的索引
  4. 为新索引起个别名,为原索引名

注意:通过上述4个步骤实现了索引的平滑过渡,并且是零停机!

1.重新创建一个静态索引,并将数据迁移到新索引中

# 重新创建一个静态索引
POST _reindex
{
  "source": {
    "index": "user2"
  },
  "dest": {
    "index": "new_user2"
  }
}

运行结果:

{
  "took" : 185,
  "timed_out" : false,
  "total" : 1,
  "updated" : 0,
  "created" : 1,
  "deleted" : 0,
  "batches" : 1,
  "version_conflicts" : 0,
  "noops" : 0,
  "retries" : {
    "bulk" : 0,
    "search" : 0
  },
  "throttled_millis" : 0,
  "requests_per_second" : -1.0,
  "throttled_until_millis" : 0,
  "failures" : [ ]
}

2.查看新索引mapping信息

# 查看新索引mapping信息
GET new_user2/_mapping

运行结果:   【新索引和旧索引mapping信息是相同的】

{
  "new_user2" : {
    "mappings" : {
      "properties" : {
        "address" : {
          "properties" : {
            "city" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            },
            "provienc" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            }
          }
        },
        "age" : {
          "type" : "long"
        },
        "name" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

3.查看新索引的数据信息

# 查看新索引的数据信息
GET new_user2/_search

运行结果:  【新索引已经包含了旧索引所有的数据】

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "new_user2",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "name" : "张三",
          "age" : 26,
          "address" : {
            "provienc" : "北京市",
            "city" : "北京市"
          }
        }
      }
    ]
  }
}

4.删除之前的旧索引

# 删除旧索引
DELETE user2

运行结果:

{
  "acknowledged" : true
}

5.为新索引起个别名,别名为旧索引的名称

# 为新索引起别名
PUT new_user2/_alias/user2

运行结果:

{
  "acknowledged" : true
}

注意:起别名前要确保别名不是已经存在的索引,如果存在则报错!这也是起别名之前先删除旧索引的原因! 

6.查询旧索引(即为新索引的别名)

# 查询旧索引(即为新索引的别名)
GET user2

# 效果等同于 GETuser2
GET new_user2

运行结果:

{
  "new_user2" : {
    "aliases" : {
      "user2" : { }
    },
    "mappings" : {
      "properties" : {
        "address" : {
          "properties" : {
            "city" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            },
            "provienc" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            }
          }
        },
        "age" : {
          "type" : "long"
        },
        "name" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    },
    "settings" : {
      "index" : {
        "routing" : {
          "allocation" : {
            "include" : {
              "_tier_preference" : "data_content"
            }
          }
        },
        "number_of_shards" : "1",
        "provided_name" : "new_user2",
        "creation_date" : "1667317074691",
        "number_of_replicas" : "1",
        "uuid" : "rvKsAyTKQeuc-bWklCW-8A",
        "version" : {
          "created" : "7170699"
        }
      }
    }
  }
}

注意:新起的别名是不能DELETE的!抛出异常!

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月14日 0

暂无评论

推荐阅读
TEZNKK3IfmPf