架构师系列-搜索引擎ElasticSearch(六)- 映射

时间:2024-04-15 07:01:55

映射配置

        在创建索引时,可以预先定义字段的类型(映射类型)及相关属性。

        数据库建表的时候,我们DDL依据一般都会指定每个字段的存储类型,例如:varchar、int、datetime等,目的很明确,就是更精确的存储数据,防止数据类型格式混乱,在Elasticsearch中也是这样,创建索引的时候一般也需要指定索引的字段类型,这种方式称为映射(Mapping)。

被动创建(动态映射)

        此时字段和映射类型不需要事先定义,只需要存在文档的索引,当向此索引添加数据的时候当遇到不存在的映射字段,ES会根据数据内容自动添加映射字段定义。使用动态映射的时候,根据传递请求数据的不同会创建对应的数据类型。

禁止动态映射

一般生产环境下需要禁用动态映射,使用动态映射可能出现以下问题

  1. 造成集群元数据一直变更,导致不稳定;
  2. 可能造成数据类型与实际类型不一致;

禁用动态映射,动态mappingdynamic字段进行配置,可选值及含义如下

  • true:支持动态扩展,新增数据有新的字段属性时,自动添加对于的mapping,数据写入成功
  • false:不支持动态扩展,新增数据有新的字段属性时,直接忽略,数据写入成功
  • strict:不支持动态扩展,新增数据有新的字段时,报错,数据写入失败

主动创建(显示映射)

我们需要对字段除了数据结构定义更多的限制的时候,动态映射创建的内容很可能不符合我们的需求,所以可以使用PUT {index}/mapping来更新指定索引的映射内容。

映射类型

我们要创建映射必须还要知道映射类型,否则就会走默认的映射类型,下面我们看看常用的映射类型。

准备工作

# 创建一个索引
PUT mapping_demo

 字符串类型

符串类型可以被设置为以下几种类型

 text

当一个字段是要被全文搜索的,比如Email内容、产品描述,应该使用text类型,text类型会被分词。设置text类型以后,字段内容会被分词,在生成倒排索引以前,字符串会被分析器分成一个一个词项,text类型的字段不用于排序,很少用于聚合 。

keyword

keyword类型不会被分词,常用于关键字搜索,比如姓名、email地址、主机名、状态码和标签等。如果字段需要进行过滤(比如查姓名是张三发布的博客)、排序、聚合,keyword类型的字段只能通过精确值搜索到,常常被用来过滤、排序和聚合。

两者区别

它们的区别在于text会对字段进行分词处理而keyword则不会进行分词。如果字段是text类型,存入的数据会先进行分词,然后将分完词的词组存入索引,而keyword则不会进行分词,直接存储,这样划分数据更加节省内存。

使用案例 

先创建一个映射,name是keyword类型,描述是text类型的

PUT mapping_demo/_mapping
{
  "properties": {
    "name": {
        "type": "keyword"
     },
      "city": {
        "type": "text",
        "analyzer": "ik_smart"
     }
  }
}

# 插入数据
PUT mapping_demo/_doc/1
{
  "name":"北京小区",
  "city":"北京市昌平区回龙观街道"
}

# 对于keyword的name字段进行精确查询
GET mapping_demo/_search
{
  "query": {
    "term": {
      "name": "北京小区"
    }
  }
}

# 对于text的city进行模糊查询
GET mapping_demo/_search
{
  "query": {
    "term": {
      "city": "北京市"
    }
  }
}

 数字类型

数字类型也是我们最常用的类型之一,下面我们看下数字类型的使用。

  • 在满足需求的情况下,优先使用范围小的字段,字段长度越小,索引和搜索的效率越高。

日期类型 

 JSON表示日期

JSON没有表达日期的数据类型,所以在ES里面日期只能是下面其中之一。

  • 格式化的日期字符串,比如:"2015-01-01" or "2015/01/01 12:10:30"
  • 用数字表示的从新纪元开始的毫秒数
  • 用数字表示的从新纪元开始的秒数(epoch_second)

ES如何处理日期

        在ES的内部,时间会被转换为UTC时间(如果声明了时区)并使用从新纪元开始的毫秒数的长整形数字类型的进行存储,在日期字段上的查询,内部将会转换为使用长整形的毫秒进行范围查询,根据与字段关联的日期格式,聚合和存储字段的结果将转换回字符串。

默认日期格式

日期的格式可以被定制化的,如果没有声明日期的格式,它将会使用默认的格式。

"strict_date_optional_time||epoch_millis" 

意味着它将会接收带时间戳的日期,它将遵守strict_date_optional_time限定的格式(yyyy-MM-dd'T'HH:mm:ss.SSSZ 或者 yyyy-MM-dd)或者毫秒数。

日期格式示例

PUT mapping_demo/_mapping
{
  "properties": {
    "datetime": {
        "type": "date",
        "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
     }
  }
}
# 添加数据
PUT mapping_demo/_doc/2
{
  "name":"河北区",
  "city":"河北省小区",
  "datetime":"2022-02-21 11:35:42"
}

日期类型参数

布尔类型 

boolean类型用于存储文档中的true/false

范围类型

范围类型字段中存储的内容就是一段范围,例如年龄30-55岁,日期在2020-12-28到2021-01-01之间等。

es中有六种范围类型:

  • integer_range
  • float_range
  • long_range
  • double_range
  • date_range
  • ip_range

使用实例 

PUT mapping_demo/_mapping
{
  "properties": {
    "age_range": {
        "type": "integer_range"
     }
  }
}

# 指定年龄范围,可以使用 gt、gte、lt、lte。
PUT mapping_demo/_doc/3
{
  "name":"张三",
  "age_range":{
    "gt":20,
    "lt":30
  }
}