我们今天来学一下动态映射Dynamic mapping和映射mapping。
ES如何控制字段类型。
一、什么是Mapping
1、Mapping的理解
Mapping你可以对比这MYsql数据库中的schema理解,其实就是一个数据库中表字段结构的定义。他的具体作用如下:
- 定义索引中的字段的名称。
- 定义字段的数据类型,例如字符串,数字,布尔。。。
- 字段,倒排索引的相关配置,这个字段是不是要分词,用什么分词器分词。都可以定义。
- Mapping会把JSON文档映射成Lucene所需要的扁平格式。
- 一个Mapping属于一个索引的Type。
- 每个文档都属于一个Type,7.0的时候type默认就是_doc。
- 一个Type有一个Mapping定义。
- 7.0开始不需要在Mapping中指定Type信息,都是_doc了。
2、字段的数据类型
- 简单类型
- Text / Keyword
- Date
- Integer / Floating
- Boolean
- 复杂类型-对象和嵌套对象
- 对象类型和嵌套类型
- 特殊类型
- geo_point & geo_shape / percolator
二、什么是Dynamic Mapping
1、Dynamic Mapping简介
- 在写入文档的时候,如果索引不存在,则会自动创建索引。
- Dynamic Mapping的机制,使得我们无需手动定义Mapping。ES会根据文档信息自动推算出字段类型。
- 但是有时候推算的不是很准,例如地理位置信息。
- 当类型如果设置不对的时候,会导致一些功能无法正常运行,例如Range查询。
2、查看Mapping的语法
GET movies/_mappings
3、类型的自动识别
在ES中的文档都是json格式的。
当你输入的字段是个字符串的时候,如果你的字符串是个日期格式,es会匹配日期格式,给你设置成Date类型。如果你输的是数字,他会给你匹配成字符串,因为这个是默认关闭的,你可以主动设置成float或者long。字符串你也可以设置为Text,他会给你增加一个keyword类型的子字段。
布尔值是boolean。
浮点数是float。
整数是long。
对象是Object。
数组由第一个非空数值的类型所决定数组类型。
空值会被忽略。
4、自动识别案例
1、写入一个文档,随便指定一个索引,原来不存在这个索引,ES动态创建。
# 写入文档,查看索引mapping
PUT mapping_test/_doc/1
{
"firstName":"li",
"lastName":"yx",
"loginDate":"2022-07-17T10:29:48.103Z"
}
# 查看mapping结构
GET mapping_test/_mapping
查询结果为:
{
"mapping_test" : {
"mappings" : {
"properties" : {
"firstName" : {
"type" : "text", 字符串li被识别成了test类型
"fields" : {
"keyword" : {
"type" : "keyword", 并且附了一个keyword类型的子字段
"ignore_above" : 256
}
}
},
"lastName" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"loginDate" : {
"type" : "date" 我们输入的字符串2022-07-17T10:29:48.103Z,但是被识别为了日期类型
}
}
}
}
}
2、删除该索引
# 删除索引
DELETE mapping_test
# 再插一个文档进去
PUT mapping_test/_doc/1
{
"uid":"123",
"isVip":false,
"isAdmin":"true",
"age":19,
"height":180
}
# 查看映射信息
GET mapping_test/_mapping
{
"mapping_test" : {
"mappings" : {
"properties" : {
"age" : {
"type" : "long" 数字类型
},
"height" : {
"type" : "long" 数字类型
},
"isAdmin" : {
"type" : "text", 虽然是true但是我是以"true"字符串类型的,所以被识别为text
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"isVip" : {
"type" : "boolean" 布尔类型
},
"uid" : {
"type" : "text",虽然是数字123但是我是以"123"字符串类型的,所以被识别为text
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
}
}
5、能否更改Mapping的字段类型
我们在数据库中是可以通过alter cloum来修改字段的类型的。在ES中要想改,分为以下两种情况。
1、新增加字段
- Dynamic设置为true的时候,一旦有新增字段的文档写入,Mapping也同时被更新。
- Dynamic设置为false的时候,Mapping不会被更新,新增字段的数据无法被索引,也就是不能检索它。但是信息会在_source中出现,就是会被你查别的东西带出来,只是不能查它。但是这个文档是存进去了。
- Dynamic设置为Strict,文档会写入失败。
2、对于已有字段,一旦已经有数据写入,mapping生成了,就不再支持修改字段定义。不能改已有的字段类型,这是因为Lucene实现的倒排索引,一旦生成不允许修改。如果希望改变已有的字段类型,必须Reindex API,重建索引。
其原因就是如果修改了字段数据类型,会导致已经被索引的字段,也就是被建立的倒排索引无法被搜索,需要重新建立索引,开销太大。
但是你要是增加新的字段,就不会有这样的影响。因为新建,不会改动旧的。
6、测试一下
1、先删除这个索引
DELETE mapping_test
2、添加一个文档
PUT dynamic_mapping_test/_doc/1
{
"newField":"someValue"
}
默认Mapping支持dynamic是true
#修改为dynamic false
PUT dynamic_mapping_test/_mapping
{
"dynamic": false
}
#新增 anotherField
PUT dynamic_mapping_test/_doc/10
{
"anotherField":"someValue"
}
#该字段不可以被搜索,因为dynamic已经被设置为false
POST dynamic_mapping_test/_search
{
"query":{
"match":{
"anotherField":"someValue"
}
}
}
GET dynamic_mapping_test/_doc/10
#修改为strict
PUT dynamic_mapping_test/_mapping
{
"dynamic": "strict"
}
#写入数据出错,HTTP Code 400
PUT dynamic_mapping_test/_doc/12
{
"lastField":"value"
}
三、总结
反正就是这么三种设置,你自己使用的时候要用哪种就自己设置好,有时候权限不能给太高,一旦设置好了,不让他改类型,设置为strict就好。