欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Elasticsearch系列7.5--ES中字段的动态映射

程序员文章站 2022-07-09 18:53:43
...

自动映射是es提供的一个重要的特性,它将文档建立索引之前的工作全部自动化了(创建索引、定义映射类型、字段发现/定义字段);
可以通过以下方式自定义动态映射规则

1、字段动态映射:管理字段动态发现

默认情况下文档中新增了字段,es能自动发现变化并添加新字段到索引当中,这个特性可以通过设置dynamic参数为false(忽略新字段)或strict(抛异常)来禁止;
假设dynamic参数映射为true,以下简单规则用于确定新增字段的类型:

序号 json数据类型 es数据类型
1 null 没有字段添加
2 true或false boolean字段
3 浮点数 float字段
4 integer long字段
5 object object字段
6 array 取决于数组第一个非空值的类型
7 string date/double/long/text(新增一个keyword的子级字段)类型中匹配的一个

这些规则仅适用于字段数据类型,其他的类型(复杂类型、geo类型、特殊类型等)必须要显式指定;

日期检测
若date_detection参数启用(默认启用),当新增加的字段内容能够匹配dynamic_date_formates则认定该字段类型为date类型;
dynamic_date_formates默认格式:[“strict_date_optional_time”,“yyyy/MM/dd HH:mm:ss Z||yyyy/MM/dd Z”]

PUT dyn_date_detection_1_index/_doc/1
{
  "create_time":"2020/05/31"
}

GET dyn_date_detection_1_index/_mapping
{
  "dyn_date_detection_1_index" : {
    "mappings" : {
      "properties" : {
        "create_time" : {
          "type" : "date",
          "format" : "yyyy/MM/dd HH:mm:ss||yyyy/MM/dd||epoch_millis"
        }
      }
    }
  }
}

禁用日期自动检测

PUT dyn_date_detection_2_index
{
  "mappings": {
    "date_detection": false
  }
}

PUT dyn_date_detection_2_index/_doc/1
{
  "create_time":"2020/05/31"
}

//create_time类型被映射为text
GET dyn_date_detection_2_index/_mapping
{
  "dyn_date_detection_2_index" : {
    "mappings" : {
      "date_detection" : false,
      "properties" : {
        "create_time" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

数值类型自动检测
因为json支持原生浮点数和整数数据类型,一些应用或编程语言可能会将数值渲染为字符串;通常正确的解决方案是显式映射这些字段,不过启用数字检测(默认为禁用状态)可以自动执行此操作:

PUT dyn_numeric_detection_index
{
  "mappings": {
    "numeric_detection": true
  }
}

PUT dyn_numeric_detection_index/_doc/1
{
  "float_define":"1.0",
  "integer_define":"1"
}

GET dyn_numeric_detection_index/_mapping

2、动态映射模板:配置新增字段的映射

动态模板允许自定义映射规则:
1)、es结合match_mapping_type自动检测数据类型;
2)、根据字段名称使用match、unmatch或者match_pattern进行匹配;
3)、根据字段全限定路径使用path_match和path_unmatch进行匹配;

原始字段名可使用模板变量{name}代替,检测到的数据类型可使用模板变量{dynamic_type}代替;

动态映射的字段要求新增的字段有确定的值(null或空数组不满足),这也就意味着如果在动态模板字段中设置了null_value参数,该参数要在配置该参数字段首次有确定值的时被应用;

动态模板映射模板格式:

"dynamic_templates": [
    {
      //模板名称可以自定义
      "my_template_name": {
        //match conditions可包含的类型:match_maooing_type,match,match_pattern,unmatch,path_match,path_unmatch
        ... match conditions ...
        //匹配的字段应该映射的类型
        "mapping": { ... }
      }
    }
]

若模板代码段中包含不合法的表达,则在校验时会导致校验失败的错误,校验的操作会在模板应用于索引时或是模板更新时;
模板的执行将按照代码顺序执行,若字段类型匹配则不会执行其他规则的匹配,当模板代码被更新时,已存在的模板会被重写,这允许初始化之后的模板能够被重新排序或删除;

match_mapping_type参数

match_mapping_type对应的值是json解析器检测到的数据类型,因为json无法区分long与integer类型或doubble与float类型,故而选择较宽的数据类型,即整数会表示为long,浮点数表示为doubble;
以下的数据类型会被自动监测:

序号 类型 可能值
1 boolean true/false
2 date 日期自动检查发现string字段与日期格式匹配
3 double 带小数的数字
4 long 不带小数的数字
5 object 对象
6 string 字符串类型

为了能够匹配所有的数据类型,可以将所有的整数映射成long,所有的字符串类型映射成text和keyword

PUT dyn_all_datatype_match_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
              }
            }
          }
        }
      }
    ]
  }
}

//age字段映射成integer,desc字段映射成text且子级字段映射成keyword
PUT dyn_all_datatype_match_index/_doc/1
{
  "age":5,
  "desc":"it's a nice girl"
}

match与unmatch参数

match参数使用模式匹配来匹配字段名,unmatch参数使用模式匹配来排除匹配的字段名;
以下示例演示了所有string类型字段名匹配以long_开始的字段并且排除以_text结果的字段,并将满足条件的字段映射成long类型:

PUT dyn_param_match_index
{
  "mappings": {
    "dynamic_templates": [
      {
        "long_as_strings": {
          "match_mapping_type": "string",
          "match": "long_*",
          "unmatch": "*_text",
          "mapping": {
            "type": "long"
          }
        }
      }
    ]
  }
}

//long_num匹配规则'long_*'将映射成long类型,long_text因匹配'*_text'将无法映射成long,转而使用默认的映射规则
PUT dyn_param_match_index/_doc/1
{
  "long_num":"5",
  "long_text":"it's a long text"
}

查看映射详情

GET dyn_param_match_index/_mapping

结果返回

{
  "dyn_param_match_index" : {
    "mappings" : {
      "dynamic_templates" : [
        {
          "long_as_strings" : {
            "match" : "long_*",
            "unmatch" : "*_text",
            "match_mapping_type" : "string",
            "mapping" : {
              "type" : "long"
            }
          }
        }
      ],
      "properties" : {
        "long_num" : {
          "type" : "long"
        },
        "long_text" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

match_pattern参数

match_pattern参数用于调整match参数的行为,其支持java正则匹配表达式

PUT dyn_template_regex_index
{
  "mappings": {
    "dynamic_templates": [
      {
        "profit_adapt": {
          "match_pattern": "regex",
          "match": """^total_orders_\d+$""",
          "unmatch": """^total_orders_*_text$""",
          "mapping": {
            "type": "long"
          }
        }
      }
    ]
  }
}

PUT dyn_template_regex_index/_doc/1
{
  "total_orders_202004":"1254",
  "total_orders_202005":"1665",
  "total_orders_202005_text":"1665"
}

GET dyn_template_regex_index/_mapping

{
  "dyn_template_regex_index" : {
    "mappings" : {
      "dynamic_templates" : [
        {
          "profit_adapt" : {
            "match" : """^total_orders_\d+$""",
            "unmatch" : "^total_orders_*_text$",
            "match_pattern" : "regex",
            "mapping" : {
              "type" : "long"
            }
          }
        }
      ],
      "properties" : {
        "total_orders_202004" : {
          "type" : "long"
        },
        "total_orders_202005" : {
          "type" : "long"
        },
        "total_orders_202005_text" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

path_match与path_unmatch参数

path_match/path_unmatch参数工作方式与match/unmatch参数工作方式一样,不过前者需要指定字段路径,而不仅仅是字段名称,例如some_object.*.some_field:

//以下template限定路径匹配以'name'开头且排除以'middle'结尾的字段,定义其类型为text,并将字段值拷贝到'full_name'字段上,排除的字段将按照默认映射规则处理

PUT dyn_template_path_match_index
{
  "mappings": {
    "dynamic_templates": [
      {
        "full_name": {
          "path_match": "name.*",
          "path_unmatch": "*.middle",
          "mapping": {
            "type": "text",
            "copy_to": "full_name"
          }
        }
      }
    ]
  }
}

//此处name.first与name.last将命中规则,name.middle将使用默认映射规则处理
PUT dyn_template_path_match_index/_doc/1
{
  "name":{
    "first":"Jack",
    "middle":"Black",
    "last":"Rose"
  }
}

需要注意的是path_match/path_unmatch参数匹配需要指定到叶子节点的字段,反之若匹配的为非叶子节点将会报错:

//报错,因为name,title获取到的是object而非string,错误信息:Can't get text on a START_OBJECT at 5:13
PUT dyn_template_path_match_index/_doc/2
{
  "name":{
    "first":"Paul",
    "last":"Mike",
    "title":{
      "value":"es",
      "category":"distribute too of software"
    }
  }
}

占位符{name}与{dynamic_type}

{name}与{dynamic_type}占位符分别代表了在映射时映射字段的名称及检测的字段类型
//'named_analyzer’指定analyzer为映射字段名,而’no_doc_values’则指定字段自动的映射类型为其type

PUT dyn_template_placeholder_index
{
  "mappings": {
    "dynamic_templates": [
      {
        "named_analyzer": {
          "match_mapping_type": "string",
          "match": "*",
          "mapping": {
            "type": "text",
            "analyzer": "{name}"
          }
        }
      },
      {
        "no_doc_values": {
          "match_mapping_type": "*",
          "mapping": {
            "type": "{dynamic_type}",
            "doc_values": false
          }
        }
      }
    ]
  }
}

//此处指定字段english的analyzer为english,count字段自动映射,其类型为long
PUT dyn_template_placeholder_index/_doc/1
{
  "english":"some english text",
  "count":5
}

模板实例

1)、结构化查询
默认情况下es映射string类型字段会处理为text类型且其子字段类型为keyword,若只想建立结构化索引且不需要全文索引,可以将es中所有字段的类型映射为keyword类型,这也就意味着查询这些字段需要精确指定查询值:

PUT dyn_structure_search_index
{
  "mappings": {
    "dynamic_templates": [
      {
        "string_as_keyword": {
          "match_mapping_type": "string",
          "mapping": {
            "type": "keyword"
          }
        }
      }
    ]
  }
}

2)、string类型字段全部以text进行映射
与前例相反,若只需要全文索引而不考虑排序、聚合或精确查找,可以将所有string类型字段映射为text类型:

PUT dyn_text_only_index
{
  "mappings": {
    "dynamic_templates": [
      {
        "string_as_text": {
          "match_mapping_type": "string",
          "mapping": {
            "type": "text"
          }
        }
      }
    ]
  }
}

3)、禁用norms参数
norms参数影响索引时分数计算,若不会使用文档相关分来进行排序则可以禁用该参数以节约一些存储空间:

PUT dyn_disable_norms_index
{
  "mappings": {
    "dynamic_templates": [
      {
        "string_as_keywords": {
          "match_mapping_type": "string",
          "mapping": {
            "type": "text",
            "norms": false,
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          }
        }
      }
    ]
  }
}

4)、时间序列
使用es针对时间序列进行分析时,通常有很多的数值字段且经常对这些字段进行聚合操作而根本不用过滤操作,这种情况下可以禁止为这些字段建立索引以节省磁盘空间以及提升索引的速度:

PUT dyn_time_series_index
{
  "mappings": {
    "dynamic_templates": [
      {
        "unindexed_longs": {
          "match_mapping_type": "long",
          "mapping": {
            "type": "long",
            "index": false
          }
        }
      },
      {
        "unindexed_doubles": {
          "match_mapping_type": "double",
          "mapping": {
            "type": "double",
            "index": false
          }
        }
      }
    ]
  }
}
相关标签: ELK elasticsearch