一. 动态字段映射
我们知道,我们在ES向ES中写入数据的时候会自动检测数据的类型,会为这些数据创建类型,那么es是如何自动检测字段类型的? es会参照默认的字段映射类型表,如下:
json 类型 | es数据类型 |
null | 不添加字段 |
true or false | bool 字段 |
float小数点数值 | float类型 |
integer 类型 | 整型 |
object 类型 | object类型 |
array 类型 | array类型 |
string 类型 | 如下情况: 1.如果设置date_detection则是日期类型,2.设置numberic dection 则是 double或者long类型,3.文本类型 4.带keyword的子字段 |
以上字段类型是自动检测的,其他字段类型必须显示指定映射
除此之外,动态字段映射可以通过dynamic_template进行个性化定制,在后面章节会具体说到。
es在映射的时候会通过dynamic 字段去决定字段映射级别,这个参数有3中类型
- true
: 向es中添加新字段的时候,会自动添加
- false
:添加新字段的时候,会自动忽略掉
- strict
: 遇到陌生字段,会报错
dynamic
参数可以作用到rootObject或者类型为object的字段上,实例如下:
DELETE my_index
PUT /my_index
{
"mappings": {
"my_type": {
"dynamic": "strict",
"properties": {
"title": { "type": "text"},
"new": {
"type": "object",
"dynamic": true
}
}
}
}
}
在new字段上添加新字段,这时候可以的,因为类型是object,下面添加一条数据
DELETE my_index
PUT /my_index
{
"mappings": {
"my_type": {
"dynamic": "strict",
"properties": {
"title": { "type": "text"},
"new": {
"type": "object",
"dynamic": true
}
}
}
}
}
PUT /my_index/my_type/1
{
"title": "This doc adds a new field",
"new": {
"new_field": "Success!"
}
}
GET my_index/_search
在kibana执行:
当在顶层对象上试图添加新字段则会报错:
PUT /my_index/my_type/1
{
"title": "This throws a StrictDynamicMappingException",
"new_field": "Fail!"
}
在kibana中执行
日期检测
如果设置date_detection为enabled(默认设置),则检查新字符串字段以查看其内容是否与dynamic_date_formats中指定的任何日期模式匹配。 如果找到匹配项,则会使用相应的格式添加新的日期字段。
说明
默认的dynamic_date_formats
类型 如下:
[ “strict_date_optional_time”,”yyyy/MM/dd HH:mm:ss Z||yyyy/MM/dd Z”]
默认只要日期字符串满足上面的格式,es索引的时候会自动映射成日期类型
比如:
PUT my_index_new/_doc/1
{
"create_date": "2015/09/02"
}
GET my_index_new/_mapping
关闭日期检测
将dynamic_date_formats
参数设为false
之后,日期字段在es中会一直当成普通的字符串
例如:
PUT my_index_new
{
"mappings": {
"_doc": {
"date_detection": false
}
}
}
PUT my_index_new/_doc/1
{
"create": "2015/09/02"
}
GET my_index_new/_mapping
字段映射:
数值检测
尽管JSON支持本地浮点和整数数据类型,但有些应用程序或语言有时可能会将数字呈现为字符串。 通常,正确的解决方案是显式映射这些字段,但可以启用数字检测(默认情况下禁用)来自动执行此操作
例如:
PUT my_index
{
"mappings": {
"_doc": {
"numeric_detection": true
}
}
}
PUT my_index/_doc/1
{
"my_float": "1.0",
"my_integer": "1"
}
GET my_index/_mapping
查看mapping:
定制化 dynamic_date_formats
当然,以上是默认的日期字段映射规则,比如一个2017-08-08 10:22:33
这种格式的日期field,如果按照默认的format不匹配就会抛错,这时候就自定义 dynamic_date_formats
,这样
参考如下实例:
PUT zxx_dynamic_mapping
{
"mappings": {
"zxx_type":{
"dynamic_date_formats": ["yyyy-MM-dd HH:mm:ss || yyyy/MM/dd HH:mm:ss || yyyy-MM-dd || yyyy/MM/dd || epoch_millis"]
}
}
}
PUT zxx_dynamic_mapping/zxx_type/1
{
"date":"2018/08/08 10:22:33"
}
PUT zxx_dynamic_mapping/zxx_type/2
{
"date":"2018-08-08 10:22:33"
}
PUT zxx_dynamic_mapping/zxx_type/3
{
"date":"2018/08/08"
}
PUT zxx_dynamic_mapping/zxx_type/4
{
"date":"2018-08-08"
}
PUT zxx_dynamic_mapping/zxx_type/5
{
"date":"1528772388000"
}
查看数据情况
GET zxx_dynamic_mapping/_search
动态模板
动态模板允许您根据以下内容定义可应用于动态添加字段的自定义映射:
- Elasticsearch检测到的数据类型,带有match_mapping_type
- 字段的名称,匹配和不匹配或match_pattern
- 到字段的完整虚线路径,带有path_match和path_unmatch
注意
动态字段映射仅在字段包含具体值时才添加 - 不为空或为空数组。 这意味着,如果在dynamic_template中使用
了null_value选项,则只有在为该字段指定了具体值的第一个文档之后才会应用该选项。
match_mapping_type
match_mapping_type
与动态字段映射检测到的数据类型匹配,换句话说,Elasticsearch认为该字段应具有的数据类型。 只能自动检测以下数据类型:布尔型,日期型,双精度型,长型,对象,字符串。 它也接受*来匹配所有的数据类型。
例如,如果我们想要将所有整数字段映射为整数而不是long,并将所有字符串字段映射为text和keyword,则可以使用以下模板:
DELETE my_index
PUT my_index
{
"mappings": {
"doc": {
"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
}
}
}
}
}
]
}
}
}
PUT my_index/doc/1
{
"my_integer": 5,
"my_string": "Some string"
}
match and unmatch
匹配参数使用模式匹配字段名称,而不匹配则使用模式排除匹配已匹配的字段
以下示例匹配名称以long_开头的所有字符串字段(以_text结尾的字符串除外)并将它们映射为long类型:
DELETE my_index
PUT my_index
{
"mappings": {
"doc": {
"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"
}
查看mapping,如下图所示:
根据上图发现字段long_num
字段的mapping
类型为long
模式匹配
match_pattern参数调整匹配参数的行为,以便它支持字段名称上的完整Java正则表达式匹配,而不是简单的通配符,例如:
"match_pattern": "regex",
"match": "^profit_\d+$"
path匹配和不匹配
path_match和path_unmatch参数的工作方式与match和unmatch相同,但在字段的完整虚线路径上运行,而不仅仅是最终名称,例如,some_object。*。some_field。
此示例将名称对象中任何字段的值复制到顶层 full_name字段(中间字段除外):
DELETE my_index
PUT my_index
{
"mappings": {
"doc": {
"dynamic_templates": [
{
"full_name": {
"path_match": "name.*",
"path_unmatch": "*.middle",
"mapping": {
"type": "text",
"copy_to": "full_name"
}
}
}
]
}
}
}
PUT my_index/doc/1
{
"name": {
"first": "Alice",
"middle": "Mary",
"last": "White"
}
}
在kibana中执行以上dsl如下:
注意:
从结果上来看,并没有将first,last字段的值copy到full_name中,原因待查!
{name} and {dynamic_type}
{name}和{dynamic_type}占位符在映射的时候会被替换为字段名称和检测到的动态类型。 如下示例是将所有字符串字段设置为使用与字段名称相同的分析器,并禁用所有非字符串字段的doc_values:
DELETE my_index
PUT my_index
{
"mappings": {
"doc": {
"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
}
在kibana中执行,如下:
模板实例
结构化搜索
默认情况下,Elasticsearch会将字符串字段映射为带有子关键字字段的文本字段。 但是,如果仅关注索引结构化内容而对全文搜索不感兴趣,则可以使Elasticsearch将字段映射为keyword
。 请注意,这意味着为了搜索这些字段,将不得不搜索索引完全相同的值。
实例如下
DELETE my_index
PUT my_index
{
"mappings": {
"doc": {
"dynamic_templates": [
{
"strings_as_keywords": {
"match_mapping_type": "string",
"mapping": {
"type": "keyword"
}
}
}
]
}
}
}
GET my_index/_mapping
在kibana中执行如下:
纯文本映射为string
与前面的例子相反,如果您关心字符串字段的唯一事情是全文搜索,并且不打算运行聚合,对字符串字段进行排序或精确搜索,则可以告知Elasticsearch 将其仅映射为文本字段(这是5.0之前的默认行为):
实例如下:
DELETE my_index
PUT my_index
{
"mappings": {
"doc": {
"dynamic_templates": [
{
"strings_as_text": {
"match_mapping_type": "string",
"mapping": {
"type": "text"
}
}
}
]
}
}
}
GET my_index/_mapping
在kibana中执行如下:
这时候试一下聚合操作
- 向index中插入一些数据
GET my_index/_search
PUT my_index/doc/1
{
"name":"xiaozhang",
"age" : 20
}
PUT my_index/doc/2
{
"name":"xiaoli",
"age" : 30
}
PUT my_index/doc/3
{
"name":"xiaowang",
"age" : 23
}
有如下需求: 统计这个index下总共有多少人,即name的总个数
- dsl如下:
GET my_index/_search
{
"query": {
"match_all": {}
},
"aggs": {
"sum-name": {
"sum": {
"field": "name"
}
}
}
}
在kibana中执行,抛如下异常:
Fielddata is disabled on text fields by default. Set fielddata=true on [name] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory. Alternatively use a keyword field instead.
如下图所示:
这个原因就不用多解释了,这是由于fielddata是默认关闭的,需要在mapping的时候开启
实例如下:
ELETE my_index
PUT my_index
{
"mappings": {
"doc": {
"properties": {
"name" :{
"type": "text",
"fielddata":true
}
}
}
}
}
PUT my_index/doc/1
{
"name":"xiaozhang",
"age" : 20
}
PUT my_index/doc/2
{
"name":"xiaoli",
"age" : 30
}
PUT my_index/doc/3
{
"name":"xiaowang",
"age" : 23
}
GET my_index/_search
{
"aggs": {
"sum-name": {
"value_count": {
"field": "name"
}
}
}
}
关闭分词
分词是索引时间评分因素。 如果不关心评分,例如,如果从不按分数对文档进行排序,则可以禁用这些评分因子在索引中的存储并节省一些空间。
实例如下:
PUT my_index
{
"mappings": {
"doc": {
"dynamic_templates": [
{
"strings_as_keywords": {
"match_mapping_type": "string",
"mapping": {
"type": "text",
"norms": false,
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
]
}
}
}
子关键字字段出现在此模板中,以与动态映射的默认规则保持一致。 当然,如果不需要,因为不需要在这个字段进行精确的搜索或聚合,你可以按照前面的部分所述去除它。
时间序列
在使用Elasticsearch进行时间序列分析时,通常会有许多数字字段,经常会聚合但不会过滤。 在这种情况下,您可以禁用这些字段的索引以节省磁盘空间,并且可能会提升索引速度
例如:
DELETE my_index
PUT my_index
{
"mappings": {
"doc": {
"dynamic_templates": [
{
"unindexed_longs": {
"match_mapping_type": "long",
"mapping": {
"type": "long",
"index": false
}
}
},
{
"unindexed_doubles": {
"match_mapping_type": "double",
"mapping": {
"type": "float",
"index": false
}
}
}
]
}
}
}
GET my_index/_mapping
像默认的动态映射规则一样,双精度映射为浮点数,通常足够精确,但需要一半的磁盘空间。
总结:
本文主要内容提现在以下几个方面
1. 动态字段映射,由dynamic参数控制,比如日期类型会根据默认类型去匹配,如果doc中类型不一致则报错,也可以修改日期类型匹配参数dynamic_date_formats
2.动态模板,分为结构化搜索,纯文本映射为text,时间序列等可以动态觉得某个字段的类型,
3. 以上大部分实例都是使用es官网的例子