04.elasticsearch-dynamic_mapping_and_index_template

1. dynamic mapping 设置

dynamic mapping主要介绍了,es是如何根据indexing的doc来确定mapping的信息的,也就是根据每个json 属性判断mapping的每个field应该为什么类型。既然说了是dynamic mapping,也就是对应的mapping没有定义,或者mapping存在但是没有该field的情况,如果mapping中已经定义了,那么直接根据mapping中定义的type去尝试解析即可。
json能够表达的类型是有限的,只能表达以下类型

  1. 字符串
  2. 数字
  3. 对象(JSON 对象)
  4. 数组
  5. 布尔
  6. 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设置

  1. 通过 match_mapping_type + es 识别出来的json data type 来进行模式识别,设置filed mapping param 和field type
  2. 通过match_and_unmatch 或者 match_pattern + field name 来进行模式识别,设置filed mapping param 和field type
  3. 通过 path_match 和 path_unmatch + 带点符号的field name的匹配 来进行模式识别,设置filed mapping param 和field type
1. data type + match_mapping_type

data type是es识别出来的json的数据类型,在上面已经有描述了,但是es默认增加了对日期的识别,所以有下面几种

  1. boolean 布尔
  2. date 日期
  3. double 类型(这个地方有点奇怪是double而不是float,测试验证过)
  4. long 类型
  5. object 类型
  6. 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的请求体中有以下比较重要的地方

  1. index_patterns: 这个是一个string数组,支持通过通配符*配置的index name ,进而来匹配新创建时候的index
  2. aliases: 索引别名,可以设置多个别名
  3. mappings: mapping设置
  4. settings: index settings
  5. version: 这个是使用外部系统关联管理使用index-template的时候使用的,es不会自动生成这个数字
  6. 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
}

等后面有实际的使用经验了再来补充。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值