三、Mapping参数
3.1 analyzer
指定分词器(分析器更合理),对索引和查询都有效。如下,指定ik分词的配置:
PUT http://192.168.20.46:9200/my_index
{
"mappings": {
"my_type": {
"properties": {
"content": {
"type": "text",
"analyzer": "ik_smart",
"search_analyzer": "ik_max_word"
}
}
}
}
}
POST http://192.168.20.46:9200/my_index/my_type/1
{
"content":"我是中国人,我爱我的祖国"
}
POST http://192.168.20.46:9200/my_index/_search?pretty
{
"query":{
"match":{
"content":"祖国"
}
}
}
3.2 normalizer
normalizer用于解析前的标准化配置,比如把所有的字符转化为小写等。例子:
POST http://node1:9200/my_index
{
"settings":{
"analysis":{
"normalizer":{
"my_normalizer":{
"type":"custom",
"char_filter":[],
"filter":[
"lowercase",
"asciifolding"
]
}
}
}
},
"mappings":{
"my_data":{
"properties":{
"foo":{
"type":"keyword",
"normalizer":"my_normalizer"
}
}
}
}
}
POST http://node1:9200/my_index/my_data/1
{
"foo":"Zhangsan"
}
POST http://node1:9200/my_index/_search
{
"query":{
"match":{
"foo":"ZHANGSAN"
}
}
}
具体解释:https://my.oschina.net/u/3101476/blog/1493626
3.3 boost
boost字段用于设置字段的权重,比如,关键字出现在title字段的权重是出现在content字段中权重的2倍,设置mapping如下,其中content字段的默认权重是1.
POST http://node1:9200/my_index
{
"mappings":{
"my_type":{
"properties":{
"title":{
"type":"text",
"boost":2
},
"content":{
"type":"text"
}
}
}
}
}
同样,在查询时指定权重也是一样的:
POST http://node1:9200/my_index/_search
{
"query": {
"match" : {
"title": {
"query": "quick brown fox",
"boost": 2
}
}
}
}
推荐在查询时指定boost,第一中在mapping中写死,如果不重新索引文档,权重无法修改,使用查询可以实现同样的效果。
3.4 coerce
coerce属性用于清除脏数据,coerce的默认值是true。整型数字5有可能会被写成字符串“5”或者浮点数5.0.coerce属性可以用来清除脏数据:
- 字符串会被强制转换为整数
- 浮点数被强制转换为整数
POST http://node1:9200/my_index
{
"mappings":{
"my_data":{
"properties":{
"number_one":{
"type": "integer"
},
"number_two":{
"type":"integer",
"coerce":false
}
}
}
}
}
POST http://node1:9200/my_index/my_data/1
{
"number_one":"10"
}
POST http://node1:9200/my_index/my_data/2
{
"number_two":"10"
}
mapping中指定number_one字段是integer类型,虽然插入的数据类型是String,但依然可以插入成功。number_two字段关闭了coerce,因此插入失败。
3.5 copy_to
copy_to属性用于配置自定义的_all字段。换言之,就是多个字段可以合并成一个超级字段。比如,first_name和last_name可以合并为full_name字段。
POST http://node1:9200/my_index
{
"mappings":{
"my_data":{
"properties":{
"first_name":{
"type":"text",
"copy_to":"full_name"
},
"last_name":{
"type":"text",
"copy_to":"full_name"
},
"full_name":{
"type":"text"
}
}
}
}
}
POST http://node1:9200/my_index/my_data/1
{
"first_name": "John",
"last_name": "Smith"
}
POST http://node1:9200/my_index/_search
{
"query":{
"match":{
"full_name":{
"query":"John Smith",
"operator":"and"
}
}
}
}
3.6 doc_values
doc_values是为了加快排序、聚合操作,在建立倒排索引的时候,额外增加一个列式存储映射,是一个空间换时间的做法。默认是开启的,对于确定不需要聚合或者排序的字段可以关闭。
POST http://node1:9200/my_index
{
"mappings":{
"my_type":{
"properties":{
"status_code":{
"type":"keyword"
},
"session_id":{
"type":"keyword",
"doc_values":false
}
}
}
}
}
注:text类型不支持doc_values。
3.7 dynamic
dynamic属性用于检测新发现的字段,有三个取值:
- true:新发现的字段添加到映射中。(默认)
- flase:新检测的字段被忽略。必须显式添加新字段。
- strict:如果检测到新字段,就会引发异常并拒绝文档。
例子:
POST http://node1:9200/my_index
{
"mappings":{
"my_data":{
"dynamic":false,
"properties":{
"user":{
"properties":{
"name":{
"type":"text"
},
"social_networks":{
"dynamic":true,
"properties":{}
}
}
}
}
}
}
}
PS:取值为strict,非布尔值要加引号。
3.8 enabled
ELasticseaech默认会索引所有的字段,enabled设为false的字段,es会跳过字段内容,该字段只能从_source中获取,但是不可搜。而且字段可以是任意类型。
POST http://node1:9200/my_index
{
"user_id": "kimchy",
"session_data": {
"arbitrary_object": {
"some_array": [ "foo", "bar", { "baz": 2 } ]
}
},
"last_updated": "2015-12-06T18:20:22"
}
POST http://node1:9200/my_index/session/session_1
{
"user_id": "kimchy",
"session_data": {
"arbitrary_object": {
"some_array": [ "foo", "bar", { "baz": 2 } ]
}
},
"last_updated": "2015-12-06T18:20:22"
}
POST http://node1:9200/my_index/session/session_2
{
"user_id": "jpountz",
"session_data": "none",
"last_updated": "2015-12-06T18:22:13"
}
3.9 fielddata
搜索要解决的问题是“包含查询关键词的文档有哪些?”,聚合恰恰相反,聚合要解决的问题是“文档包含哪些词项”,大多数字段再索引时生成doc_values,但是text字段不支持doc_values。
取而代之,text字段在查询时会生成一个fielddata的数据结构,fielddata在字段首次被聚合、排序、或者使用脚本的时候生成。ELasticsearch通过读取磁盘上的倒排记录表重新生成文档词项关系,最后在Java堆内存中排序。
text字段的fielddata属性默认是关闭的,开启fielddata非常消耗内存。在你开启text字段以前,想清楚为什么要在text类型的字段上做聚合、排序操作。大多数情况下这么做是没有意义的。
“New York”会被分析成“new”和“york”,在text类型上聚合会分成“new”和“york”2个桶,也许你需要的是一个“New York”。这是可以加一个不分析的keyword字段:
POST http://node1:9200/my_index
{
"mappings":{
"my_type":{
"properties":{
"my_field":{
"type":"text",
"fields":{
"keyword":{
"type":"keyword"
}
}
}
}
}
}
}
上面的mapping中实现了通过my_field字段做全文搜索,my_field.keyword做聚合、排序和使用脚本。
3.10 format
format属性主要用于格式化日期:
POST http://node1:9200/my_index
{
"mappings": {
"my_type": {
"properties": {
"date": {
"type": "date",
"format": "yyyy-MM-dd"
}
}
}
}
}
更多内置的日期格式:https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-date-format.html
3.11 ignore_above
ignore_above用于指定字段索引和存储的长度最大值,超过最大值的会被忽略:
PUT http://node1:9200/my_index
{
"mappings":{
"my_type":{
"properties":{
"message":{
"type":"keyword",
"ignore_above":15
}
}
}
}
}
POST http://node1:9200/my_index/my_type/1
{
"message": "Syntax error"
}
POST http://node1:9200/my_index/my_type/2
{
"message": "Syntax error with some long stacktrace"
}
POST http://node1:9200/my_index/_search
{
"size": 0,
"aggs": {
"messages": {
"terms": {
"field": "message"
}
}
}
}
mapping中指定了ignore_above字段的最大长度为15,第一个文档的字段长小于15,因此索引成功,第二个超过15,因此不索引,返回结果只有”Syntax error”,结果如下:
{
"took": 50,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 0,
"hits": []
},
"aggregations": {
"message": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "Syntax error",
"doc_count": 1
}
]
}
}
}
3.12 ignore_malformed
ignore_malformed可以忽略不规则数据,对于login字段,有人可能填写的是date类型,也有人填写的是邮件格式。给一个字段索引不合适的数据类型发生异常,导致整个文档索引失败。如果ignore_malformed参数设为true,异常会被忽略,出异常的字段不会被索引,其它字段正常索引。
POST http://node1:9200/my_index
{
"mappings":{
"my_type":{
"properties":{
"number_one":{
"type":"integer",
"ignore_malformed":true
},
"number_two":{
"type":"integer"
}
}
}
}
}
POST http://node1:9200/my_index/my_type/1
{
"text": "Some text value",
"number_one": "foo"
}
POST http://node1:9200/my_index/my_type/2
{
"text": "Some text value",
"number_one": 123
}
POST http://node1:9200/my_index/my_type/3 --> error
{
"text": "Some text value",
"number_two": "abc"
}
GET http://node1:9200/my_index/_search
{
"took": 21,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 1,
"hits": [
{
"_index": "my_index",
"_type": "my_type",
"_id": "2",
"_score": 1,
"_source": {
"text": "Some text value",
"number_one": 123
}
},
{
"_index": "my_index",
"_type": "my_type",
"_id": "1",
"_score": 1,
"_source": {
"text": "Some text value",
"number_one": "foo"
}
}
]
}
}
上面的例子中number_one接受integer类型,ignore_malformed属性设为true,因此文档一种number_one字段虽然是字符串但依然能写入成功,并且索引成功;number_two接受integer类型,默认ignore_malformed属性为false,因此写入失败。
3.13 include_in_all
include_in_all属性用于指定字段是否包含在_all字段里面,默认开启,除索引时index属性为no。
例子如下,title和content字段包含在_all字段里,date不包含。
POST http://node1:9200/my_index
{
"mappings":{
"my_type":{
"properties":{
"title":{
"type":"text"
},
"content":{
"type":"text"
},
"date":{
"type":"text",
"include_in_all":false
}
}
}
}
}
include_in_all也可用于字段级别,如下my_type下的所有字段都排除在_all字段之外,author.first_name 和author.last_name 包含在in _all中:
POST http://node1:9200/my_index
{
"mappings":{
"my_type":{
"include_in_all":false,
"properties":{
"title":{"type":"text"},
"author":{
"include_in_all":true,
"properties":{
"first_name":{"type":"text"},
"last_name":{"type":"text"}
}
},
"editor":{
"properties":{
"first_name":{"type":"text"},
"last_name":{"type":"text","include_in_all":true}
}
}
}
}
}
}
3.14 index
index属性指定字段是否索引,不索引也就不可搜索,取值可以为true或者false。
3.15 index_options
index_options控制索引时存储哪些信息到倒排索引中,接受以下配置:
参数 | 作用 |
---|---|
docs | 只存储文档编号 |
freqs | 存储文档编号和词项频率 |
positions | 文档编号、词项频率、词项的位置被存储,偏移位置可用于临近搜索和短语查询 |
offsets | 文档编号、词项频率、词项的位置、词项开始和结束的字符位置都被存储,offsets设为true会使用Postings highlighter |
3.16 fields
fields可以让同一文本有多种不同的索引方式,比如一个String类型的字段,可以使用text类型做全文检索,使用keyword类型做聚合和排序。
POST http://node1:9200/my_index
{
"mappings":{
"my_type":{
"properties":{
"city":{
"type":"text",
"fields":{
"raw":{
"type":"keyword"
}
}
}
}
}
}
}
POST http://node1:9200/my_index/my_type/1
{
"city":"New York"
}
POST http://node1:9200/my_index/my_type/2
{
"city":"York"
}
POST http://node1:9200/my_index/_search
{
"query":{
"match":{
"city":"york"
}
},
"sort":{
"city.raw":"asc"
},
"aggs":{
"cities":{
"terms":{
"field":"city.raw"
}
}
}
}
{
"took": 141,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 2,
"max_score": null,
"hits": [
{
"_index": "my_index",
"_type": "my_type",
"_id": "1",
"_score": null,
"_source": {
"city": "New York"
},
"sort": [
"New York"
]
},
{
"_index": "my_index",
"_type": "my_type",
"_id": "2",
"_score": null,
"_source": {
"city": "York"
},
"sort": [
"York"
]
}
]
},
"aggregations": {
"cities": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "New York",
"doc_count": 1
},
{
"key": "York",
"doc_count": 1
}
]
}
}
}
3.17 norms
norms参数用于标准化文档,以便查询时计算文档的相关性。norms虽然对评分有用,但是会消耗较多的磁盘空间,如果不需要对某个字段进行评分,最好不要开启norms。
3.18 null_value
值为null的字段不索引也不可以搜索,null_value参数可以让值为null的字段显式的可索引、可搜索。例子:
PUT http://node1:9200/my_index
{
"mappings":{
"my_type":{
"properties":{
"status_code":{
"type":"keyword",
"null_value":"NULL"
}
}
}
}
}
POST http://node1:9200/my_index/my_type/1
{
"status_code":null
}
POST http://node1:9200/my_index/my_type/2
{
"status_code":[]
}
POST http://node1:9200/my_index/_search
{
"query":{
"term":{
"status_code":"NULL"
}
}
}
文档1可以被搜索到,因为status_code的值为null,文档2不可以被搜索到,因为status_code为空数组,但是不是null。
3.19 position_increment_gap
为了支持近似或者短语查询,text字段被解析的时候会考虑此项的位置信息。举例,一个字段的值为数组类型:
"names": [ "John Abraham", "Lincoln Smith"]
为了区别第一个字段和第二个字段,Abraham和Lincoln在索引中有一个间距,默认是100。例子如下,这是查询”Abraham Lincoln”是查不到的:
POST http://node1:9200/my_index/groups/1
{
"names": [ "John Abraham", "Lincoln Smith"]
}
//查询不到
POST http://node1:9200/my_index/groups/_search
{
"query":{
"match_phrase":{
"names":{
"query": "Abraham Lincoln"
}
}
}
}
指定间距大于100可以查询到:
//查询得到
POST http://node1:9200/my_index/groups/_search
{
"query":{
"match_phrase":{
"names":{
"query": "Abraham Lincoln" ,
"slop":101
}
}
}
}
在mapping中通过position_increment_gap参数指定间距:
PUT http://node1:9200/my_index
{
"mappings":{
"groups":{
"properties":{
"names":{
"type":"text",
"position_increment_gap":0
}
}
}
}
}
POST http://node1:9200/my_index/groups/1
{
"names": [ "John Abraham", "Lincoln Smith"]
}
http://node1:9200/my_index/groups/_search
{
"query":{
"match_phrase":{
"names":{
"query": "Abraham Lincoln"
}
}
}
}
可以查到数据
3.20 properties
Object或者nested类型,下面还有嵌套类型,可以通过properties参数指定。
PUT http://node1:9200/my_index
{
"mappings":{
"my_type":{
"properties":{
"manager":{
"properties":{
"age":{"type":"integer"},
"name":{"type":"text"}
}
},
"employee":{
"type":"nested",
"properties":{
"age":{"type":"integer"},
"name":{"type":"text"}
}
}
}
}
}
}
POST http://node1:9200/my_index/my_type/1
{
"region": "US",
"manager": {
"name": "Alice White",
"age": 30
},
"employees": [
{
"name": "John Smith",
"age": 34
},
{
"name": "Peter Brown",
"age": 26
}
]
}
可以对manager.name、manager.age做搜索、聚合等操作。(未验证通过 回头看)
POST http://node1:9200/my_index/_search
{
"query": {
"match": {
"manager.name": "Alice White"
}
},
"aggs": {
"Employees": {
"nested": {
"path": "employees"
},
"aggs": {
"Employee Ages": {
"histogram": {
"field": "employees.age",
"interval": 5
}
}
}
}
}
}
3.21 search_analyzer
大多数情况下索引和搜索的时候应该指定相同的分析器,确保query解析以后和索引中的词项一致。但是有时候也需要指定不同的分析器,例如使用edge_ngram过滤器实现自动补全。
默认情况下查询会使用analyzer属性指定的分析器,但也可以被search_analyzer覆盖。例子:
PUT http://node1:9200/my_index
{
"settings":{
"analysis":{
"filter":{
"autocomplete_filter":{
"type":"edge_ngram",
"min_gram":1,
"max_gram":20
}
},
"analyzer":{
"autocomplete":{
"type":"custom",
"tokenizer":"standard",
"filter":[
"lowercase",
"autocomplete_filter"
]
}
}
}
},
"mappings":{
"my_type":{
"properties":{
"text":{
"type":"text",
"analyzer":"autocomplete",
"search_analyzer":"standard"
}
}
}
}
}
POST http://node1:9200/my_index/my_type/1
{
"text": "Quick Brown Fox"
}
POST http://node1:9200/my_index/_search
{
"query": {
"match": {
"text": {
"query": "Quick Br",
"operator": "and"
}
}
}
}
3.22 similarity
similarity参数用于指定文档评分模型,参数有三个:
- BM25 :ES和Lucene默认的评分模型
- classic :TF/IDF评分
- boolean:布尔模型评分
例子:
POST http://node1:9200/my_index
{
"mappings":{
"my_type":{
"properties":{
"default_field":{
"type":"text"
},
"classic_field":{
"type":"text",
"similarity":"classic"
},
"boolean_sim_field":{
"type":"text",
"similarity":"boolean"
}
}
}
}
}
default_field自动使用BM25评分模型,classic_field使用TF/IDF经典评分模型,boolean_sim_field使用布尔评分模型。
3.23 store
默认情况下,自动是被索引的也可以搜索,但是不存储,这也没关系,因为_source字段里面保存了一份原始文档。在某些情况下,store参数有意义,比如一个文档里面有title、date和超大的content字段,如果只想获取title和date,可以这样:
PUT http://node1:9200/my_index
{
"mappings":{
"my_type":{
"properties":{
"title":{
"type":"text",
"store":true
},
"date":{
"type":"date",
"store":true
},
"content":{
"type":"text"
}
}
}
}
}
POST http://node1:9200/my_index/my_type/1
{
"title": "Some short title",
"date": "2015-01-01",
"content": "A very long content field..."
}
POST http://node1:9200/my_index/_search
{
"stored_fields": [ "title", "date"]
}
{
"took": 12,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 1,
"hits": [
{
"_index": "my_index",
"_type": "my_type",
"_id": "1",
"_score": 1,
"fields": {
"date": [
"2015-01-01T00:00:00.000Z"
],
"title": [
"Some short title"
]
}
}
]
}
}
Stored fields返回的总是数组,如果想返回原始字段,还是要从_source中取。
3.24 term_vector
词向量包含了文本被解析以后的以下信息:
- 词项集合
- 词项位置
- 词项的起始字符映射到原始文档中的位置。
term_vector参数有以下取值:
参数取值 | 含义 |
---|---|
no | 默认值,不存储词向量 |
yes | 只存储词项集合 |
with_positions | 存储词项和词项位置 |
with_offsets | 词项和字符偏移位置 |
with_positions_offsets | 存储词项、词项位置、字符偏移位置 |
例子:
PUT http://node1:9200/my_index
{
"mappings":{
"my_type":{
"properties":{
"text":{
"type":"text",
"term_vector":"with_positions_offsets"
}
}
}
}
}
POST http://node1:9200/my_index/my_type/1
{
"text": "Quick brown fox"
}
POST http://node1:9200/my_index/_search
{
"query": {
"match": {
"text": "brown fox"
}
},
"highlight": {
"fields": {
"text": {}
}
}
}
{
"took": 89,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.5063205,
"hits": [
{
"_index": "my_index",
"_type": "my_type",
"_id": "1",
"_score": 0.5063205,
"_source": {
"text": "Quick brown fox"
},
"highlight": {
"text": [
"Quick <em>brown</em> <em>fox</em>"
]
}
}
]
}
}