1. dynamic mapping 设置
dynamic mapping主要介绍了,es是如何根据indexing的doc来确定mapping的信息的,也就是根据每个json 属性判断mapping的每个field应该为什么类型。既然说了是dynamic mapping,也就是对应的mapping没有定义,或者mapping存在但是没有该field的情况,如果mapping中已经定义了,那么直接根据mapping中定义的type去尝试解析即可。
json能够表达的类型是有限的,只能表达以下类型
- 字符串
- 数字
- 对象(JSON 对象)
- 数组
- 布尔
- Null
比如日期date,数字中的long,integer是分不清的。所以es需要对这些进行支持
1. es内部支持的field类型的动态识别
1. 默认的field 识别
null: No field is added.
true or false: boolean field
floating point number: float field
integer: long field
object: object field
array: Depends on the first non-null value in the array.
string: 这个看需要,正常情况下是一个带有keyword的text的field,如果开启了date-detection可能会产生date field mapping, 如果开启了numeric-detection课可能会产生 long或者float field mapping.
需要注意的是小数都变成了float,没有特殊识别double,integer,long都变成了long
long 是可以兼容integer,但是float却是不能兼容double的
例如下面的请求
PUT my_index05/_doc/1
{
"number":123446567890233123446567890233123446567890233123446567890233.6
}
返回
{
"error": {
"root_cause": [
{
"type": "mapper_parsing_exception",
"reason": "failed to parse field [number] of type [float] in document with id '1'. Preview of field's value: '1.2344656789023312E59'"
}
],
"type": "mapper_parsing_exception",
"reason": "failed to parse field [number] of type [float] in document with id '1'. Preview of field's value: '1.2344656789023312E59'",
"caused_by": {
"type": "illegal_argument_exception",
"reason": "[float] supports only finite values, but got [Infinity]"
}
},
"status": 400
}
在没有提前创建mapping的情况下回报错,因为number字段的值超出了float的范围
假如先定义mapping
PUT my_index05
{
"mappings": {
"properties": {
"number":{
"type": "double"
}
}
}
}
则是可以成功写入的。
2. date-detection
es对日期做了特殊支持,默认情况下满足特定的格式的string进行indexing的时候可能会被识别为 date字段
默认情况下识别的日期格式是 [ "strict_date_optional_time","yyyy/MM/dd HH:mm:ss Z||yyyy/MM/dd Z"]
PUT my_index/_doc/1
{
"create_date": "2015/09/02"
}
这个是可以正确映射为日期的
你也可以关掉这个设置
PUT my_index
{
"mappings": {
"date_detection": false
}
}
同时还可以自定义日期的格式
PUT my_index
{
"mappings": {
"dynamic_date_formats": ["MM/dd/yyyy"]
}
}
3. numeric-detection
这个会把string类型的数字转换为数字,转为float或者long 类型(double长度的会报错)
这个设置默认情况下是关闭的
PUT my_index
{
"mappings": {
"numeric_detection": true
}
}
PUT my_index/_doc/1
{
"my_float": "1.0",
"my_integer": "1"
}
2. 在mapping中设置动态的模板进行识别
es还可以根据字段名,json数据原始类型等做一些更灵活的动态field映射,这种一般情况下都是通过特征进行设置,相对来说可能会一条规则对过个field都有效,所以叫dynamic templates
dynamic template 主要提供了一下集中方式进行template设置
- 通过 match_mapping_type + es 识别出来的json data type 来进行模式识别,设置filed mapping param 和field type
- 通过match_and_unmatch 或者 match_pattern + field name 来进行模式识别,设置filed mapping param 和field type
- 通过 path_match 和 path_unmatch + 带点符号的field name的匹配 来进行模式识别,设置filed mapping param 和field type
1. data type + match_mapping_type
data type是es识别出来的json的数据类型,在上面已经有描述了,但是es默认增加了对日期的识别,所以有下面几种
- boolean 布尔
- date 日期
- double 类型(这个地方有点奇怪是double而不是float,测试验证过)
- long 类型
- object 类型
- string 类型
样例
PUT my_index
{
"mappings": {
"dynamic_templates": [
{
"integers": {
"match_mapping_type": "long",
"mapping": {
"type": "integer"
}
}
},
{
"strings": {
"match_mapping_type": "string",
"mapping": {
"type": "text",
"fields": {
"raw": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
},
{
"my_float":{
"match_mapping_type":"double", # 注意这个地方只有写成double才能正确匹配,生成mapping中的field的type为double, 没有这个配置的话默认生成的mapping field的type为float.
"mapping":{
"type":"double"
}
}
}
]
}
}
然后执行
PUT my_index/_doc/1
{
"my_integer": 922337203685477580,
"my_string": "Some string"
}
返回
{
"error": {
"root_cause": [
{
"type": "mapper_parsing_exception",
"reason": "failed to parse field [my_integer] of type [integer] in document with id '1'. Preview of field's value: '922337203685477580'"
}
],
"type": "mapper_parsing_exception",
"reason": "failed to parse field [my_integer] of type [integer] in document with id '1'. Preview of field's value: '922337203685477580'",
"caused_by": {
"type": "i_o_exception",
"reason": "Numeric value (922337203685477580) out of range of int\n at [Source: org.elasticsearch.common.bytes.BytesReference$MarkSupportingStreamInputWrapper@56f5802a; line: 2, column: 35]"
}
},
"status": 400
}
这个会生成把long 强制设置为 integer(indexing的时候是long也不行),上面indexing的时候传入了一个大于integer范围的值,导致了失败,假如改成小于integer范围的就可以成功
假如我们直接把这个put语句应用到一个新的自动生成的索引当中,则是可以成功的
PUT my_index01/_doc/1
{
"my_integer": 922337203685477580,
"my_string": "Some string"
}
这个是可以成功的。
2. match_and_unmatch + field name
简单的模式匹配,可以设置以什么开头,以什么结尾的filed
样例
PUT my_index
{
"mappings": {
"dynamic_templates": [
{
"longs_as_strings": {
"match_mapping_type": "string",
"match": "long_*",
"unmatch": "*_text",
"mapping": {
"type": "long"
}
}
}
]
}
}
PUT my_index/_doc/1
{
"long_num": "5",
"long_text": "foo"
}
3. match_pattern + field name
是上一个的增强版,filed name的模式匹配的时候允许使用正则表达式
样例
PUT my_index
{
"mappings": {
"dynamic_templates": [
{
"longs_as_strings": {
"match_mapping_type": "string",
"match_pattern": "regex",
"match": "^long_*",
"unmatch": "*_text",
"mapping": {
"type": "long"
}
}
}
]
}
}
PUT my_index/_doc/1
{
"long_num": "5",
"long_text": "foo"
}
4. path_match 和 path_unmatch + 带点符号的field name
直接看样例
PUT my_index
{
"mappings": {
"dynamic_templates": [
{
"full_name": {
"path_match": "name.*",
"path_unmatch": "*.middle",
"mapping": {
"type": "text",
"copy_to": "full_name"
}
}
}
]
}
}
PUT my_index/_doc/1
{
"name": {
"first": "John",
"middle": "Winston",
"last": "Lennon"
}
}
5. 使用filed name 和 dynamic_type 作为mapping param的设置
这个是什么意思呢,就是将field name 和dynamic_type作为变量,在设置mapping的时候可以直接引用
看一个样例更容易理解
PUT my_index
{
"mappings": {
"dynamic_templates": [
{
"named_analyzers": {
"match_mapping_type": "string",
"match": "*",
"mapping": {
"type": "text",
"analyzer": "{name}"
}
}
},
{
"no_doc_values": {
"match_mapping_type":"*",
"mapping": {
"type": "{dynamic_type}",
"doc_values": false
}
}
}
]
}
}
PUT my_index/_doc/1
{
"english": "Some English text",
"count": 5
}
这里的string类型的属性都会使用它的field name作为analyzer,比如 english 字段的analyzer 就是 english-analyzer ,这个局限性很强,因为只有有限数量的analyzer
其他类型的field的type直接使用es探测到的type
总感觉这个用处很小
2. index template
index template 的作用是什么呢,从字面意思上理解就是为index的mapping指定template使用的
他的功能是你定一个mapping,并且指定一些模式匹配规则,可以指定哪些index创建的时候使用这个mapping,他主要是对还未创建的索引起作用。
这个功能还是很有用的,比如在日志系统当中,一般是按照天创建索引,索引的mapping基本上是一致的,或者说只有有限的几种,而且索引的name一般也都是根据一些规则组成的,所以就可以定义一些index template,在每次创建索引的时候不用再指定mapping,直接会根据index template创建mapping。
当然,在index template中不仅可以指定mapping,还可以指定所有正常创建index的时候使用的参数,包括alias,setting 等设置。
1. 创建一个index template
PUT _template/template_1
{
"index_patterns": ["te*", "bar*"],
"aliases" : {
"kk-log" : { }
},
"settings": {
"number_of_shards": 1
},
"mappings": {
"_source": {
"enabled": false
},
"properties": {
"host_name": {
"type": "keyword"
},
"created_at": {
"type": "date",
"format": "EEE MMM dd HH:mm:ss Z yyyy"
}
}
},
"order" : 10
}
这样的话,所有以te,bar开头的索引都会命中这个index-template,进而对应的index的会使用这个template中的设置。
在template的请求体中有以下比较重要的地方
- index_patterns: 这个是一个string数组,支持通过通配符
*
配置的index name ,进而来匹配新创建时候的index - aliases: 索引别名,可以设置多个别名
- mappings: mapping设置
- settings: index settings
- version: 这个是使用外部系统关联管理使用index-template的时候使用的,es不会自动生成这个数字
- order: 顺序,当一个index命中多个index-template的时候,会都使用,但是order值从小到大一次merge相关配置,也就是order值更大的相同设置会overried order值更小的index-template中的设置。
2. 一个新的index命中多个index-template的规则
这个在上面说的差不多了,这里举一个栗子来看看吧
PUT /_template/template_1
{
"index_patterns" : ["test*"],
"order" : 0,
"settings" : {
"number_of_shards" : 1
},
"mappings" : {
"_source" : { "enabled" : false }
}
}
PUT test_have01/_doc/1
{
"my_integer": 922337203685477580,
"my_string": "Some string"
}
GET test01/_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" : "test_have01",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0
}
]
}
}
可以看到返回的直接没有_source字段了。
增加一个order值更高的template,并打开source字段
PUT /_template/template_2
{
"index_patterns" : ["test_have*"],
"order" : 1,
"settings" : {
"number_of_shards" : 1
},
"mappings" : {
"_source" : { "enabled" : true }
}
}
再写入文档
PUT test_have01/_doc/1
{
"my_integer": 922337203685477580,
"my_string": "Some string"
}
GET test_have01/_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" : "test_have01",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"my_integer" : 922337203685477580,
"my_string" : "Some string"
}
}
]
}
}
可以看到template_2 中对_source字段的设置override 了temple_1中的设置,因为他的order值更大。
3. template中添加version
这个说事在外部系统管理template的时候使用
PUT /_template/template_1
{
"index_patterns" : ["*"],
"order" : 0,
"settings" : {
"number_of_shards" : 1
},
"version": 123
}
等后面有实际的使用经验了再来补充。