[16]ES mapping 的设置规则

2021-05-25  本文已影响0人  不怕天黑_0819

本文集主要是总结自己在项目中使用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": { # 注意,这里的test_type与json文件名必须一致
      "properties": {
        "name": {
          "type": "string",
          "index": "not_analyzed"
        },
        "age": {
          "type": "integer"
        }
      }
    }
  }

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"
                    }

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

Field支持的数据类型:

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

动态mapping

自动映射:

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

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

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

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

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

一个动态模板的示例:

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:四种定义方式

采用如下方式自动创建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还是数组,所以需要自己在写代码的时候进行选择。

上一篇下一篇

猜你喜欢

热点阅读