Elasticsearch Mapping 动态模板 Dynamic templates
一、前言
上一篇博客【Elasticsearch教程4】Mapping 动态映射讲的动态映射虽然使用简单,但往往不能满足企业的业务场景。比如:
- 对于整数,一般用
integer
就足够了,但是ES会默认成long
。 - 对于字符串(邮箱,住址),一般我们不用分词,但是ES总会设成带
.keyword
子字段的text
类型。
动态模板(Dynamic templates)可以满足我们需求,在创建mapping时,先定义好规则,当新字段满足某条规则时,就会按照该规则的预先配置来创建字段。
二、动态模板的类型
ES提供了3个角度来定义规则:
- 数据类型(data type)
- 字段名称(field name)
- 字段全点路径(full dotted path to the field)
角度 | 匹配语法 |
---|---|
数据类型 | match_mapping_type |
字段名称 | match 和 unmatch |
字段全点路径 | path_match 和 path_unmatch |
三、动态模板的语法
dynamic_templates
是一个数组
,可以定义多个规则
{
"mappings": {
"dynamic_templates": [
{
"my_template_name": { #1 自定义动态模板名称
...匹配规则... #2 使用match_mapping_type、match、unmatch等等定义规则
"mapping": { ... } #3 设置符合该规则的mapping配置
}
}
]
}
}
四、match_mapping_type
match_mapping_type
是按照数据类型匹配的,比数据类型是long
,而且我们知道该字段的数据范围是不会超过int
时,我们可以设置规则匹配为integer
。
4.1 ES动态字段映射
我们先了解下ES自己根据数据类型
创建的字段类型规则:
JSON数据类型 | ES数据类型 |
---|---|
null | 不添加字段 |
true / false | boolean |
double | float |
long | long |
object | object |
array | 根据数组中第一个非null值的类型 |
通过日期检测的string | date |
通过数字检测的string | float 或 long |
没有通过上面2个检测的string | 带.keyword 子字段的text类型 |
4.2 自定义数据类型规则
创建如下动态模板:long
转integer
和stirng
转keyword
PUT pigg_test
{
"mappings": {
"dynamic_templates": [
{
"my_template_long": {
"match_mapping_type": "long",
"mapping": {
"type": "integer"
}
}
},
{
"my_template_string": {
"match_mapping_type": "string",
"mapping": {
"type": "keyword"
}
}
}
]
}
}
插入一笔测试数据
PUT pigg_test/_doc/1
{
"name": "亚瑟王",
"age": 33
}
通过GET pigg_test/_mapping
查询发现ES创建的字段类型确实符合上面定义的模板
"properties" : {
"age" : {
"type" : "integer"
},
"name" : {
"type" : "keyword"
}
}
五、match
和 unmatch
在企业开发中用的最多的其实还是这个字段名称匹配。
match
:字段名称匹配某规则unmatch
:字段名称不匹配某规则match_pattern
:设置为regex
,配合match
和unmatch
使用正则表达式- 注意:对于嵌套对象,
match
和unmatch
只作用于最后一级字段名
比如企业常用动态表单
场景,我们不知道一个表有多少字段,也不知道字段的类型,也不知道某字段是否要分词。我们可以做如下约定:
规则 | 表达式 | ES类型 | 字段名称案例 |
---|---|---|---|
以short_ 开头 | "match": "short_*" | short | short_age |
以int_ 开头 | "match": "int_*" | integer | integer_people_count |
以long_ 开头 | "match": "long_*" | long | long_click_count |
以bin_ 开头 | "match": "bin_*" | binary | bin_head_img |
以ip_ 开头 | "match": "ip_*" | ip | ip_location |
以text_ 开头,_ik 结尾 | "match": "text_*_ik" | text 用ik 分词器 | text_name_ik |
以key_ 开头 | "match": "key_*" | keyword | key_status |
以profit_ 开头,后面至少跟1位数字,则设为keyword | "match_pattern": "regex","match": "^profit_\d+$" | keyword | prodfit_1 |
我们先选择其中3个作为测试例子:
PUT pigg_test
{
"mappings": {
"dynamic_templates": [
{
"string_to_integer": {
"match_mapping_type": "string",
"match": "int_*",
"mapping": {
"type": "integer"
}
}
},
{
"string_to_long": {
"match_mapping_type": "string",
"match": "long_*",
"mapping": {
"type": "long"
}
}
},
{
"string_to_text_ik": {
"match_mapping_type": "string",
"match": "text_*_ik*",
"mapping": {
"type": "text",
"analyzer": "ik_max_word"
}
}
}
]
}
}
插入测试数据:
PUT pigg_test/_doc/1
{
"int_age": "18",
"long_click_count": "100000",
"text_name_ik": "亚瑟王"
}
通过GET pigg_test/_mapping
查询发现ES创建的字段类型确实符合上面定义的模板
"properties" : {
"int_age" : {
"type" : "integer"
},
"long_click_count" : {
"type" : "long"
},
"text_name_ik" : {
"type" : "text",
"analyzer" : "ik_max_word"
}
}
六、path_match
和 path_unmatch
- 上面一级说了
match
和unmatch
只作用于最后一级的字段名 - 对于一个有多层的内嵌对象,可以用
path_match
和path_unmatch
下面设置person.*
下除了age
都是text
类型
PUT pigg_test
{
"mappings":{
"dynamic_templates":[
{
"test_float":{
"path_match":"person.*",
"path_unmatch":"*.age",
"mapping":{
"type":"text"
}
}
},
{
"test_float":{
"path_match":"*.age",
"mapping":{
"type":"integer"
}
}
}
]
}
}
插入测试数据:
PUT pigg_test/_doc/1
{
"person": {
"count": "100",
"age": "100"
}
}
通过GET pigg_test/_mapping
查询发现ES创建的字段类型确实符合上面定义的模板
"properties" : {
"person" : {
"properties" : {
"age" : {
"type" : "integer"
},
"count" : {
"type" : "text"
}
}
}
}
七、注意事项
- 所有null和空数组[]都属于无效的值,不会匹配任务动态模板的规则
- 匹配规则时,是按照模板的配置顺序依次进行对比的,使用最先匹配到的那个模板
unmatch
和path_unmatch
不能单独使用- 动态模板的3中方式中推荐
match
和unmatch
- 因为
match_mapping_type
的过于简单 - 而
path_match
对用户的设计思想要求比较高,嘎子,path_match
这水比较深,你把握不住啊!