Elasticsearch数据建模之——mapping字段的相关配置

es作为以倒排索引为基础实现的存储体系,不遵循关系型数据库中的范式约定,它的数据建模,是根据部署需求和性能需求的物理模型;而在这个建模的过程中,由于es是可以水平扩展的,可以存储到TB级以上的大数据的原因,他的一些预配置就显得尤其重要了,这关系到整个es的性能和查询效率。

—//—

类似于关系型数据库里面的表结构设计,es中对应的是mapping配置;这一章主要讲的就是mapping设置的时候的一些注意点。

mapping字段 的相关配置


名称 枚举 作用
enable true/false 仅存储,不做搜索和聚合分析
index true/false 是否构建倒排索引,false不记录,即不可搜索
index_options docss/freqs/positions/offsets 存储倒排索引的哪些信息,text类型默认配置为positions,其他默认为docs ,记录内容越多,占用空间越大。
norms true/false 是否存储归一化的相关参数,如果字段仅用于过滤和聚合分析,可关闭
doc_values true/false 是否开启,用于排序和聚合分析
field_data true/false 是否为text类型启用,实现排序和聚合分析
store true/false 是否存储该字段值
coerce true/false 是否开启自动数据类型转换,比如字符串转数字,浮点转int(默认是true)
multifields 多字段:灵活使用多字段来解决多样的业务需求
dynamic true/false/strict 控制mapping的自动跟新
date_detection true/false 是否自动识别日期类型 (建议false,手动去设置格式)

Mapping字段属性的设定流程


判断是何种类型的字段

  • 字符串类型:需要分词就设定为text,否则设定为keyword类型
  • 枚举值类型:基于性能考虑设定成keyword类型,即便该数据为整型(比如状态码)
  • 数值类型:尽量选择贴近的数据类型,比如byte即可表示所有数值的时候,选择byte,不要用long
  • 其他类型:比如布尔类型,日期,地理数据等

判断该字段是否需要检索

  • 完全不需要检索,排序,聚合分析的字段:enable设置为false
  • 不需要检索的字段:index设置为false
  • 需要检索的字段,可以根据如下的配置设定需要的存储力度:
    • index_options: 结合需要设定
    • norms: 不需要归一化数据时关闭即可
  • 是否需要排序和聚合分析?
    不需要排序或者聚合分析功能:doc_values设定为false;fielddata设定为false
  • 是否需要专门存储当前字段的数据?
    store设定为true,即可存储该字段的原始内容(与_source中的不相关) 一般结合_source的enabled设定为false时使用

    其他建议


1.对mapping进行版本管理

包含在代码或者以专门的文件进行管理,添加好注释,并加入git等版本管理仓库中方便回顾
为每个增加一个metadata字段,在其中维护一些文档相关的元数据,方便对数据进行管理

{
  "metadata":{
    "version":1
  },
  "username":"alfred",
  "job":"engineer"
}         

#mapping版本,可以自行制定,比如每次更新mapping设置后,该version加1

2.防止字段过多

字段过多:难于维护,当字段成百上千时,基本很难有人明确知道每个字段的含义;mapping的信息存储在cluster state里面,过多的字段会导致mapping过大,最终导致更新变慢。

通过设置index.mapping.total_fields.limit可以限定索引中最大字段数,默认为1000
可以通过key/value的方式解决字段过多的问题,但并不完美(实现方式这里就不赘述了):

key/value方式缺点:

query语句复杂度飙升,且有一些可能无法实现,比如聚合分析相关的
不利于在kibana中做可视化分析
一般字段过多的原因是由于没有高质量的数据建模导致的,比如dynamic设置为true,考虑拆分多个索引来解决问题。

实例


以博客文章blog_index为例说明创建过程:

字段 字段名称 字段类型
标题 title text,子字段keyword
发布日期 publish_date date
作者 author keyword
摘要 abstract text
网络地址 url keyword(需要做相应修改)
内容 content ???

思考:博客的content内容可能会有几百上千字,但是如果博客换成书,content的内容可能会有几十万字,变的非常的大。这样如果content字段依然默认为text类型:在取原始数据时,是通过_source来获取原始内容的,每一次取_source都会把content内容取出来,如果content过大就会导致_source获取过多的内容,降低性能。

mapping设置成如下内容:结合_sourceenabled设定为false时设置storetrue

PUT blog_index
{
  "mappings": {
    "doc":{
      "_source": {
        "enabled": false
      },
      "properties": {
        "title":{
          "type":"text",
          "fields": {
            "keyword":{
              "type": "keyword"
            }
          },
          "store": true
        },
        "publish_date":{
          "type": "date",
          "store": true
        },
        "author":{
          "type": "keyword",
          "store": true
        },
        "abstract":{
          "type": "text",
          "store": true
        },
        "aontent":{
          "type":"text",
          "store": true
        },
        "url":{
          "type": "keyword",
          "doc_values":false,
          "norms": false,
          "ignore_above": 100,
          "store": true          
        }        
      }
    }
  }
}           

配置数据对比:
原来配置
去掉_source字段之后

查询实例

查询高亮显示:

GET blog_index/_search
{
  "stored_fields": ["title","publish_date","author","abstract","url"], #不获取content字段
  "query": {
    "match": {
      "content": "blog"
    }
  },
  "highlight": {
    "fields": {"content": {}}
  }
}

关于mapping的修改问题


mapping一旦建立,就不能更改现有的字段,就不能更改现有的字段映射,如果要推到现有的映射,需要建立一个新的索引,然后重新定义映射然后把之前索引里的数据导入到新建的索引里。
实现方式有如下几种:

一、使用别名的方法

  • 1.给现有的索引定义一个别名,并且把现有的索引指向这个别名。运行:

    PUT /现有索引/_alias/别名索引
  • 2.新创建一个索引,定义好最新的映射
  • 3.将别名指向新的索引,并且取消之前索引的指向。运行:

    POST /_aliases
    {
      "actions": [
        {
          "remove": {
            "index": "现有索引名",
            "alias": "别名A"
          }
        }
        {
          "add": {
            "index": "新建索引名",
            "alias": "别名A"
          }
        }
      ]
    }

    以上步骤可以实现索引的平滑过渡,并且是零停机的。

二、使用reindex

使用reindex来重建索引,这个的过程是使用的快照的办法,所以在重新索引的时候,一定要停止往里面添加索引的时候去操作,不然快照无法统计到哪个时候的信息,写法如下:

POST _reindex
{
  "source": {
    "index": "log-yht-tbs-test-1-2018.09.06"
  },
  "dest": {
    "index": "log_yht_tbs_2018.09.06_back"
  }
}

数据重建的时间收文档规模的影响,规模越大,所需时间越久,此时通过设定url的参数wait_for_completionfalse来异步执行,ES以task来描述此类执行任务,
es提供了api来查看任务进度和相关数据。

三、_update_by_query

_update_by_query是指在现有索引上重建,和上面两种都不一样。
这里写图片描述

Mapping设置补充


当字段遇到null值时的处理策略

null_value: 当字段遇到null值时的处理策略,默认为null,即空值,此时es会忽略该值。可以通过设定该值设定字段的默认值

PUT  myindex1
{
  "mappings": {
    "doc": {
      "properties": {
        "status_code": {
          "type": "keyword",
          "null_value": "NULL" 
        }
      }
    }
  }
}

multi-fields多字段特性

允许对同一个字段采用不同的配置,比如分词,常见的例子如对人名实现拼音搜索,只需要在人名中新增一个子字段为pinyin即可。

PUT  myindex1
{
  "mappings": {
    "doc": {
      "properties": {
        "username": {
          "type":"text",
          "fields": {
            "pinyin": {
              "type": "text",
              "analyzer": "pinyin"
            }
          }
        }
      }
    }
  }
}       

GET myindex1/_search
{
  "query": {
    "match": {
      "username.pinyin": "hanhan"
    }
  }
}  

动态字段映射

es可以自动识别文档字段类型,从而降低用户使用成本;
es是依靠JSOn文档的字段类型来实现自动识别字段类型,支持的类型如下:

json类型 es类型
null 忽略
Boolean Boolean
浮点类型 float
整数 long
object object
array 由第一个非null值的类型决定
string 匹配为日期则设为date类型(默认开启,建议关闭,自己配置format);匹配为数字的话设为float或long类型(默认关闭);设为text类型,并且附带keyword的子字段

其中,我们讲下日期识别:
默认是[ "strict_date_optional_time","yyyy/MM/dd HH:mm:ss Z||yyyy/MM/dd Z"]
"strict_date_optional_time"
是ISO datetime的格式,完整格式类似为:YYYY-MM-DDThh:mm:ssTZD(eg 1997-07-16T19:20:30+01:00)

  • dynamic_date_formats可以自定义日期类型
  • date_detection可以关闭日期自动识别的机制
PUT my_index
{
  "mappings": {
    "my_type":{
      "dynamic_date_formats": ["yyyy-MM-dd"]
    }
  }
}

动态模板

允许根据es自动识别的数据类型、字段名等动态设定字段类型,可以实现如下效果:

  • 所有字符串都设定为keyword类型,即默认不分词
  • 所有以message开头字段都设定为text类型,即分词
  • 所有以long_开头的字段都设定为long类型
  • 所有自动匹配为double类型的都设定为float类型,以节省空间
PUT test_index
{
  "mappings": {
    "doc":{
      "dynamic_templates": [{    #数组,可以指定多个匹配规则
        "strings":{               #template的名称
          "match_mapping_type":"string",  #匹配规则
          "mapping":{
            "type":"keyword"             #设置mapping信息
          }
        }
      }]
    }
  }
}

匹配规则一般有如下几个参数:

  • match_mapping_type: 匹配es自动识别的字段类型,如boolean,long,string等
  • match,unmatch:匹配字段名
  • path_match,path_unmatch: 匹配路径

案例:

(一)设置字符串默认使用keyword类型
PUT test_index
{
  "mappings": {
    "doc": {
      "dynamic_templates": [
          {
            "strings_as_keywords": {
              "match_mapping_type": "string",
              "mapping":{
                "type": "keyword"
              }
            }
          }
        ]
    }
  }
}

PUT test_index/doc/1
{
  "name": "alfred"
}

GET test_index/_mapping    
设置以message开头的字段都设置为text类型 (顺序由上而下)
PUT test_index
{
  "mappings": {
    "doc": {
      "dynamic_templates": [
          {
            "message_as_text": {
              "match_mapping_type": "string",
              "match": "message*",
              "mapping":{
                "type": "text"
              }
            }
          },
          {
            "strings_as_keywords": {
              "match_mapping_type": "string",
              "mapping":{
                "type": "keyword"
              }
            }
          }          
        ]
    }
  }
}

索引模板

索引模板:英文为 Index Template,主要用于在新建索引时自动应用预先设定的配置,简化索引创建的操作步骤。

  • 可以设定索引的配置和mapping
  • 可以有多个模板,根据order设置,order大的覆盖小的配置

索引模板API,endpoint为_template,如下所示:
这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_34646817/article/details/82585517