美文网首页
[16]ES mapping 的设置规则

[16]ES mapping 的设置规则

作者: 不怕天黑_0819 | 来源:发表于2021-05-25 17:02 被阅读0次

    本文集主要是总结自己在项目中使用ES 的经验教训,包括各种实战和调优。

    创建mapping的时候,_all设置为false。主要是从性能方面考虑。

    包括mapping创建方式、mapping相关知识等。官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html#mapping-type


    新增字段

    curl -XPOST "http://127.0.0.1:9200/productindex/product/_mapping?pretty" -d '{ "product": { "properties": { "onSale":{ "type":"keyword" } } } }'
    

    创建索引的同时创建setting和mapping:

    curl -XPUT "192.168.1.101:9200/index_test" -d ' # 注意这里的'号
    {
      "settings": {
        "index": {
          "number_of_replicas": "1", # 设置复制数
          "number_of_shards": "5" # 设置主分片数
        }
      },
      "mappings": { # 创建mapping
        "test_type": { # 在index中创建一个新的type(相当于table)
          "properties": {
            "name": { # 创建一个字段(string类型数据,使用普通索引)
              "type": "string",
              "index": "not_analyzed"
            },
            "age": {
              "type": "integer"
            }
          }
        }
      }
    }'
    
    

    ES还可以使用json的方式来创建mapping:

    • 创建一个扩展名为test_type.json的文件名,其中type_test就是mapping所对应的type名。
    • 在test_type.json中输入mapping信息。假设你的mapping如下:
    {
      "test_type": { # 注意,这里的test_type与json文件名必须一致
          "properties": {
            "name": {
              "type": "string",
              "index": "not_analyzed"
            },
            "age": {
              "type": "integer"
            }
          }
        }
      }
    
    • 在$ES_HOME/config/路径下创建mappings/index_test子目录,这里的index_test目录名必须与我们要建立的索引名一致。将test_type.json文件拷贝到index_tes目录下。
    • 步骤4 创建index_test索引。操作如下:

    curl -XPUT "192.168.1.101:9200/index_test" # 注意,这里的索引名必须与mappings下新建的index_test目录名一致

    这样我们就创建了一个新的索引,并且使用了test_type.json所定义的mapping作为索引的mapping。

    参考链接:具体方法参考http://blog.csdn.net/xialei199023/article/details/48085125


    mapping中一些常用的属性:

                      "activity_type": {
                            "type": "string",//string在新版本已经废弃
                            "index": "not_analyzed"
                        },
                        "address": {
                            "type": "string",
                            "analyzer": "ik_smart"
                        },
                        "last_update_time": {
                            "type": "date",
                            "format": "yyyy-MM-dd HH:mm:ss"
                        }
    

    • Fields with the same name in different mapping types in the same index must have the same mapping.(同一索引下,不同类型的相同字段必须定义成相同的mapping),但是每个字段的以下属性可以用不同的设置,如copy to、dynamic、enabled、ignore_above、include_in_all、properties。

    具体可参考https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html#_field_datatypes

    Field支持的数据类型:

    • 基本类型:text、keyword、date、long、double、boolean、ip
    • range datatypes:integer_range, float_range, long_range, double_range, date_range (可以直接存区间数据,目前项目中尚未应用,主要应用场景尚不明确,合同管理的日期似乎可以应用)
    • 支持json分层属性,复杂的数据类型,如array、object、nested
    • 特殊类型:地理点、地理形状、completion

    防止mapping激增的一些常用设置:

    • index.mapping.total_fields.limit The maximum number of fields in an index. The default value is 1000.
    • index.mapping.depth.limit 一个字段的最大深度,默认是20
    • index.mapping.nested_fields.limit 嵌套字段的最大数目,默认50

    动态mapping

    • 不允许更新已经设置好的mapping
    • multi-fields是可以使用多种分词器,如french analyzer,目前我们使用的是standard analyzer、english analyzer、id_smart analyzer。

    自动映射:

    • 动态映射:可以设置为true(默认值。动态添加字段)、false(忽略新字段)、strict(如果碰到陌生字段,抛出异常)
    • 默认映射:通常,一个索引中的所有类型具有共享的字段和设置。用 default 映射来指定公用设置会更加方便,而不是每次创建新的类型时重复操作。_default 映射像新类型的模板。所有在 default 映射 之后 的类型将包含所有的默认设置,除非在自己的类型映射中明确覆盖这些配置。

    例如,我们可以使用 default 映射对所有类型禁用 _all 字段,而只在 blog 字段上开启它:

    PUT /my_index
    {
        "mappings": {
            "_default_": {
                "_all": { "enabled":  false }
            },
            "blog": {
                "_all": { "enabled":  true  }
            }
        }
    }
    

    default 映射也是定义索引级别的动态模板的好地方。

    • 动态模板:通过dynamic_templates,你可以拥有对新字段的动态映射规则拥有完全的控制。你设置可以根据字段名称或者类型来使用一个不同的映射规则。

    每个模板都有一个名字,可以用来描述这个模板做了什么。同时它有一个mapping用来指定具体的映射信息,和至少一个参数(比如match)用来规定对于什么字段需要使用该模板。

    模板的匹配是有顺序的 - 第一个匹配的模板会被使用。比如我们可以为string字段指定两个模板:

    • es:以_es结尾的字段名应该使用spanish解析器
    • en:其它所有字段使用english解析器

    一个动态模板的示例:

    PUT /my_index
    {
        "mappings": {
            "my_type": {
                "dynamic_templates": [
                    { "es": {
                          "match":              "*_es", 
                          "match_mapping_type": "string",
                          "mapping": {
                              "type":           "string",
                              "analyzer":       "spanish"
                          }
                    }},
                    { "en": {
                          "match":              "*", 
                          "match_mapping_type": "string",
                          "mapping": {
                              "type":           "string",
                              "analyzer":       "english"
                          }
                    }}
                ]
    }}}
    

    另外一个典型的mapping对象:

    {
        "mappings": {
            "my_type": {
            //true:表示自动识别新字段并创建索引,false:不自动索引新字段,strict:遇到未知字段,抛异常,不能存入
                "dynamic":      "strict", 
    
                  //动态模板
                 "dynamic_templates": [
                        { "stash_template": {
                          "path_match":  "stash.*",
                          "mapping": {
                            "type":           "string",
                            "index":       "not_analyzed"
                          }
                        }}
                      ],
                //属性列表
                "properties": {
                    //一个string类型的字段
                    "title":  { "type": "string"},
    
                    "stash":  {
                        "type":     "object",
                        "dynamic":  true //这里设置为true主要针对的是动态模板,即新增的field要是动态模板匹配不上,就会抛异常,否则就是按照模板来创建。
                    }
                }
            }
        }
    }
    

    注意点:Elasticsearch映射虽然有idnex和type两层关系,但是实际索引时是以index为基础的。 如果同一个index下不同type的字段出现mapping不一致的情况 虽然数据依然可以成功写入并生成并生成各自的mapping, 但实际上fielddata中的索引结果却依然是以index内第一个mapping类型来生成的。


    一次定义一个index下的两个type mapping:

    糖果库mapping设置:

    curl -XPUT 'http://localhost:9200/moparticle3' -d '
    
    {
    
    "settings": {
    
    "number_of_shards": 6,
    
    "number_of_replicas": 1
    
    },
    
    "mappings": {
    
    "article": {
    
    "_all" : {
    
    "enabled" : false
    
    },
    
    "_routing" : {
    
    "required" : true
    
    },
    
    "properties" : {
    
    "docid" : {
    
    "type" : "keyword"
    
    },
    
    "boardid" : {
    
    "type" : "keyword"
    
    },
    
    "postid" : {
    
    "type" : "keyword"
    
    },
    
    "topicid" : {
    
    "type" : "keyword"
    
    },
    
    "del" : {
    
    "type" : "integer"
    
    },
    
    "title" : {
    
    "type" : "text",
    
    "analyzer" : "ik_smart",
    
    "search_analyzer": "ik_smart",
    
    "fields" : {
    
    "keyword" : {
    
    "type" : "keyword",
    
    "ignore_above" : 256
    
    },
    
    "en" : {
    
    "type": "text",
    
    "analyzer": "english"
    
    }
    
    }
    
    },
    
    "digest" : {
    
    "type" : "text",
    
    "analyzer" : "ik_smart",
    
    "search_analyzer": "ik_smart",
    
    "fields" : {
    
    "keyword" : {
    
    "type" : "keyword",
    
    "ignore_above" : 256
    
    },
    
    "en" : {
    
    "type": "text",
    
    "analyzer": "english"
    
    }
    
    }
    
    },
    
    "source" : {
    
    "type" : "keyword"
    
    },
    
    "ptime" : {
    
    "type" : "date",
    
    "format": "yyyy-MM-dd HH:mm:ss"
    
    }
    
    }
    
    }
    
    }
    
    }
    
    '
    

    article表mapping设置:

    curl -XPOST http://localhost:9200/subscribe/article/_mapping -d '{
    
    "article" : {
    
    "_all" : {
    
    "enabled" : false
    
    },
    
    "_routing" : {
    
    "required" : true
    
    },
    
    "properties" : {
    
    "id" : {
    
    "type" : "text",
    
    "fields" : {
    
    "keyword" : {
    
    "type" : "keyword",
    
    "ignore_above" : 256
    
    }
    
    }
    
    },
    
    "original" : {
    
    "type" : "long"
    
    },
    
    "postState" : {
    
    "type" : "long"
    
    },
    
    "publishTime" : {
    
    "type" : "date",
    
    "format": "yyyy-MM-dd HH:mm:ss"
    
    },
    
    "source" : {
    
    "type" : "long"
    
    },
    
    "title" : {
    
    "type" : "text",
    
    "analyzer" : "ik_smart",
    
    "fields" : {
    
    "keyword" : {
    
    "type" : "keyword",
    
    "ignore_above" : 256
    
    },
    
    "en" : {
    
    "type": "text",
    
    "analyzer": "english"
    
    }
    
    }
    
    },
    
    "tname" : {
    
    "type" : "text",
    
    "fields" : {
    
    "keyword" : {
    
    "type" : "keyword",
    
    "ignore_above" : 256
    
    }
    
    }
    
    },
    
    "topState" : {
    
    "type" : "long"
    
    },
    
    "type" : {
    
    "type" : "long"
    
    },
    
    "updateTime" : {
    
    "type" : "date",
    
    "format": "yyyy-MM-dd HH:mm:ss"
    
    },
    
    "userClassify" : {
    
    "type" : "text",
    
    "fields" : {
    
    "keyword" : {
    
    "type" : "keyword",
    
    "ignore_above" : 256
    
    }
    
    }
    
    },
    
    "wemediaId" : {
    
    "type" : "keyword"
    
    }
    
    }
    
    }
    
    }'
    

    一些不常用的datatype 整理

    Array datatype:四种定义方式

    • an array of strings: [ "one", "two" ]
    • an array of integers: [ 1, 2 ]
    • an array of arrays: [ 1, [ 2, 3 ]] which is the equivalent of [ 1, 2, 3 ]
    • an array of objects: [ { "name": "Mary", "age": 12 }, { "name": "John", "age": 10 }]

    采用如下方式自动创建mapping:

    PUT my_index/my_type/2
    {
    "tags": [ "哈哈哈","中国社会主义人民" ]
    }
    

    这时的tags是按照text的形式来定义的,但其实是个数组。会对我们数组中的每个元素进行分词,我们在搜索的时候,相当于对整个数组的数据进行分词匹配。同时还可以使用must方法来匹配一个数组的多个。比如匹配数组中既有1又有2的数据。


    Binary datatype:

    Binary类型的field是不能被搜索的。同时会以列的形式存到硬盘上,后续可以用来排序、聚合等,但是默认不会被store,即不会从_source字段中剥离出来,需要自己手动配置。


    Range datatypes:
    官网链接:https://www.elastic.co/guide/en/elasticsearch/reference/current/range.html

    具体可以参考文档,暂不做总结,觉得可能实用不是很大。


    项目在实际使用中,为了提升性能,降低带宽,在es查询时,只返回部分字段。具体实现方式如下:

    官网链接:https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-store.html

    官网说明:If you only want to retrieve the value of a single field or of a few fields, instead of the whole_source, then this can be achieved with source filtering.

    主要作用:不需要返回_source数据,减少返回数据的大小

    es在定义mapping时可以指定某一个字段是都设置store参数,

    PUT my_index
    {
     "mappings": {
       "my_type": {
         "properties": {
           "title": {
             "type": "text",
             "store": true 
           },
           "date": {
             "type": "date",
             "store": true 
           },
           "content": {
             "type": "text"
           }
         }
       }
     }
    }
    

    注:Stored fields returned as arrays

    For consistency, stored fields are always returned as an array because there is no way of knowing if the original field value was a single value, multiple values, or an empty array.

    Another situation where it can make sense to make a field stored is for those that don’t appear in the _source field (such as copy_to fields).

    Java API的使用:

    首先需要mapping定义store属性。

    在SearchRequestBuilder后面可以添加storedFields(String...)或者addStoredField(String)方法。添加后,response.getHits().getHits()的hit对象的source就为空了,只能获取我们storedFields方法添加的字段。

    方法如下:
    hit.field("title").getValue()
    hit.getFields().get("title").getValue()
    hit.getFields().get("title").getValues()

    同时还可以通过getValues方法或者一个List<Object>对象,因为es也不知道你要获取的这个字段到底是string还是数组,所以需要自己在写代码的时候进行选择。

    相关文章

      网友评论

          本文标题:[16]ES mapping 的设置规则

          本文链接:https://www.haomeiwen.com/subject/dnxorktx.html