ElasticSearch映射

映射(Mapping)类似于关系型数据库的Schema,会定义索引中在字段名称、类型以及倒排索引的相关设置。一个Mapping属于一个索引的Type,每个文档都有对应的Type。一个Type都有一个Mapping定义,从7.0开始不需要Mapping定义中指定Type信息。

映射类型

每个索引有一个或者多个映射类型(Type),用来在索引中将文档划分为不同的逻辑组。每个映射类型拥有:

1、元字段:用来定义如何处理文档的元数据。其中包括_index字段、_type字段、_id字段和_source字段。

2、字段/属性:每个映射类型包含不同数据类型的字段/属性。

在ES7.0之前,一个映射可以定义多个映射类型,如下所示:

{
    "user":{
        "mappings":{
            "user_info":{
                "properties":{
                    "name":{
                        "type":"string"
                    },
                    "address":{
                        "type":"string"
                    }
                }
            },
            "user_ext":{
                "properties":{
                    "birthday":{
                        "type":"date",
                        "format":"strict_date_optional_time"
                    },
                    "hobby":{
                        "type":"string"
                    }
                }
            }
        }
    }
}

上面2个映射类型:user_info和user_ext分别都有2个字段。从ES7.0开始,不建议对于一个索引创建多个映射类型,后续也可能禁止创建多个映射类型。

字段数据类型

ES支持一系列不同的数据类型来定义文档的字段,分为和兴数据、复杂数据、地理数据和专门数据。

核心数据类型

字符串:string

数字类型:long、integer、short、byte、double、float

日期类型:date

布尔类型:boolean

二进制:binary

复杂数据类型

数组类型:JSON数组

对象类型:JSON对象

嵌套类型:JSON对象的数组

地理数据类型

地理点类型:geo_point(经纬点)

地理形状类型:geo_shape(多边形的复杂地理形状)

特殊数据类型

IPv4类型:IP协议为IPv4的地址

完成类型:completion,提供自动补全的建议

单词计数类型:token_count,统计字符串中的单词数量

元字段

每个文档都有与之关联的元数据,其实为了保证系统正常运转的内置字段。如_index表示索引字段,_type表示映射类型字段、_id表示文档主键字段。这些字段都是以 _ 开头的,当索引被创建的时候,可以自定义一些元字段的行为。如:标识元字段、文档来源字段、索引元字段、路由元字段等。

标识元数据

_index:文档所属的索引

_uid:包含_type和_id的混合字段

_type:文档的映射类型

_id:文档的ID

文档来源元字段

_source:文档原始内容的JSON

_size:_source 元字段占用的字节数,通过 mapper-size插件提供

索引元字段

_all:索引所有字段的值

_field_names:所有包含非空值的字段

_timestamp:关联文档的时间戳,可以手动指定或自动生成

_ttl:定义文档被自动删除之前的存活时间

路由元字段

_parent:用于在映射类型之间创建父子关系

_routing:一个自定义的路由值,路由文档到一个特定的分片

其他元字段

_meta:应用特定的元字段

动态映射(Dynamic Mapping)

ES可以不事先创建好索引结构,可以在第一次写入文档时,自动创建索引映射。ES会根据第一次写入的文档,自动推测映射的字段类型,这种机制叫做动态映射。

类型自动识别


更改映射

对于Mapping的更改,可以分为2种情况:新增字段和更新字段。

新增字段

当dynamic设置为true时,如果新写入的文档中出现了新的字段,此时是可以动态更新Mapping设置的,也就是可以新增此字段,同时新增的字段也可以被搜索。

当dynamic设置为false时,文档可以被写入,但Mapping不会被更新,新增字段无法被检索,可以在_source 字段中保存新字段。

当dynamic设置为strict时,稳定写入失败。

更新字段

如果新的字段类型不匹配原有的字段Mapping,此时写入失败。此时解决的办法只能使用 Reindex API 进行索引的重建。

动态模板

动态模板可以在ES自动识别字段时,按照模板的规则匹配对应的类型。当在Kibana中写入如下文档时,会将age 字段识别为 text,birthday识别为date。

PUT my_user/_doc/1
{
	"age":"1",
	"birthday":"2019/01/01"
}

获取my_user 的mapping设置如下:

GET my_user/_mapping

{
  "my_user" : {
    "mappings" : {
      "properties" : {
        "age" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "birthday" : {
          "type" : "date",
          "format" : "yyyy/MM/dd HH:mm:ss||yyyy/MM/dd||epoch_millis"
        }
      }
    }
  }
}

查看 my_user 的分片信息如下:


下面我们创建一个 templete_user 的Mapping 模板,匹配规则为 my_user*的索引,分片为1 副本为2,并且关闭日期类型的探测。

PUT /_template/template_user
{
    "index_patterns" : ["my_user*"],
    "order" : 1,
    "settings" : {
    	"number_of_shards": 1,
        "number_of_replicas" : 2
    },
    "mappings" : {
    	"date_detection": false,
    	"numeric_detection": true
    }
}

然后我们创建 my_user2 的索引文档,如下所示:

PUT my_user2/_doc/1
{
	"age":"1",
	"birthday":"2019/01/01"
}

 此时查看 mapping 和分片信息如下所示:对于birthday字段已经不是 date 类型了,并且副本数也变成了2个。

GET my_user2/_mapping

{
  "my_user2" : {
    "mappings" : {
      "date_detection" : false,
      "numeric_detection" : true,
      "properties" : {
        "age" : {
          "type" : "long"
        },
        "birthday" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}



参考:《ElasticSearch技术解析与实战》、《极客时间:ElasticSearch核心技术与实战》