本学习笔记基于ElasticSearch 7.10版本,旧版本已经废弃的功能暂时不做笔记,以后有涉及到再做补充。
参考官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-params.html
概述
在映射Mapping中,前面我们已经学习过type
参数,它使用于描述字段类型,详见:ElasticSearch学习笔记五(映射mapping)。
除了type
参数,Mapping中还有另外27种映射参数。有些参数对于所有字段类型都是通用的,例如boost
权重参数。而有些参数则只适用于特定字段,例如analyzer
参数只能作用于text
字段。
下面来看看,es中常用的一些映射参数。
1、analyzer
analyzer
参数定义text
字段索引和查询所使用的分析器,默认使用es自带的Standard
标准分析器。
查询分析时,除非使用search_analyzer
映射参数覆盖,否则也是使用的也是analyzer
定义的分析器。
在ElasticSearch学习笔记二(分析器)中,我们就使用了ik分析器,下面再来复习一下:
# 首先不定义分析器
PUT blog
# 添加文档
PUT blog/_doc/1
{
"title": "美国留给伊拉克的是个烂摊子吗"
}
# 使用term vectors查看词条向量
GET blog/_termvectors/1
{
"fields": ["title"]
}
通过_termvectors
词条向量可以看到,如果不使用分析器,es默认分析器会一个一个将中文拆分。这样的分词结果没有任何意义,因为只能使用单个汉字,而不能使用词语。
所有应该根据实际情况,选择合适的分析器:
# 删除blog索引,重新定义分析器
PUT blog
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_smart"
}
}
}
}
# 添加文档
PUT blog/_doc/1
{
"title": "美国留给伊拉克的是个烂摊子吗"
}
# 使用term vectors查看词条向量
GET blog/_termvectors/1
{
"fields": ["title"]
}
使用了ik分析器之后,这次添加文档,es就能对中文进行正确的分词。
2、search_analyzer
通常情况下,索引和查询应该使用相同的分析器,以确保查询时的术语与倒排索引中的术语具有相同的格式。
默认情况下,查询时也是使用analyzer
参数定义的分析器,但有些时候,为了查询更加精准,或是满足不同业务场景,可以通过search_analyzer
参数来覆盖。
参考以下场景:
PUT blog/_doc/1
{
"title": "普通高中生平均年龄15-18岁"
}
# 使用“普通高中”查询文档,此时查询默认也是使用analyzer定义的ik_smart分析器,查询失败!!
GET blog/_search
{
"query": {
"match": {
"title": "普通高中"
}
}
}
查询失败原因分析:
1、 首先我们使用_termvectors
查看词条向量,会发现ik_smart分析器将“普通高中生”分成“普通”和“高中生”两个词条;
2、 对于“普通高中”,ik_smart分析器并不会分词,而是当做一个词条,当使用“普通高中”去查询时,自然查询失败;
3、 此时就可以设置查询的分析器为ik_max_word,查询时将“普通高中”分成“普通”和“高中”两个词条,进行精确查询;
# 删除blog索引,再重新定义查询分析器
PUT blog
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_smart",
"search_analyzer": "ik_max_word"
}
}
}
}
PUT blog/_doc/1
{
"title": "普通高中生平均年龄15-18岁"
}
GET blog/_search
{
"query": {
"match": {
"title": "普通高中"
}
}
}
# 分别使用ik_smart和ik_max_word进行分词测试
POST _analyze
{
"analyzer": "ik_smart",
"text": "普通高中"
}
POST _analyze
{
"analyzer": "ik_max_word",
"text": "普通高中"
}
3、search_quote_analyzer
search_quote_analyzer
参数用于设置短语(句子)的分析器,当使用短语查询时,不会删除停用词。
要禁用短语的停用词,首先需要分别设置以下三个分析器:
- analyzer:用于索引的分析器,包括停用词设置。
- search_analyzer:用于非短语查询的分析器,该设置将删除停用词。
- search_quote_analyzer:短语查询的分析器,不会删除停用词。
然后,添加ik分析器的停用词配置并重启:在IKAnalyzer.cfg.xml的<entry key="ext_stopwords"></entry>
标签中加上extra_stopword.dic。ik在该文件中已经添加了一些中文停止词,例如:的、是、也。
接下来,测试一下非短语查询和短语查询的区别:
# 删除blog索引,再重新定义短语分析器
DELETE blog
PUT blog
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_smart",
"search_analyzer": "ik_max_word",
"search_quote_analyzer": "ik_smart"
}
}
}
}
PUT blog/_doc/1
{
"title": "歌唱美好地祖国"
}
PUT blog/_doc/2
{
"title": "歌唱美好的祖国"
}
# 使用非短语查询
GET blog/_search
{
"query": {
"match": {
"title": "歌唱美好的祖国"
}
}
}
# 当使用query_string短语查询
GET blog/_search
{
"query": {
"query_string": {
"query": "\"歌唱美好的祖国\""
}
}
}
可以发现,短语查询和非短语查询返回结果不同:
- 使用非短语查询时,search_analyzer使用的ik_max_word会删除掉停止词“的”,导致两个文档都匹配,会查询出两条记录。
- 当使用query_string,并将查询短语用引号""引起来时,它被检测为短语查询,因此search_quote_analyzer启动,不会删除掉停用词“的”,只会查询出一条记录。
4、normalizer
normalizer
作用于keyword
字段类型,用于解析前(索引或者查询)的标准化配置。
我们知道,keyword
字段在索引或者查询时都不会进行分词。如果在索引前没有做好数据清洗,导致大小写不一致,例如 amby 和 Amby,使用 amby 就无法查询到 Amby 的文档,实际它们应该是相同的。
此时,我们就可以使用normalizer
在索引之前以及查询之前进行文档的标准化。
# 自定义my_normalizer,并设置为author字段的normalizer参数值
PUT blog
{
"settings": {
"analysis": {
"normalizer":{
"my_normalizer":{
"type":"custom",
"filter":["lowercase"]
}
}
}
},
"mappings": {
"properties": {
"author":{
"type": "keyword",
"normalizer":"my_normalizer"
}
}
}
}
# 分别添加amby和Amby文档
PUT blog/_doc/1
{
"author":"amby"
}
PUT blog/_doc/2
{
"author":"Amby"
}
# 接下来不论是使用amby还是Amby,甚至是AMBY,都能查询出两个文档来
GET blog/_search
{
"query": {
"term": {
"author": "AMBY"
}
}
}
# 查看author字段的聚合返回归一化值,Amby在索引前已经被转成amby
GET blog/_search
{
"size": 0,
"aggs": {
"foo_terms": {
"terms": {
"field": "author"
}
}
}
}
5、boost
boost
参数可以设置字段的权重。
boost
有两种使用思路:
- 一种就是在定义 mappings 的时候使用,在指定字段类型时使用
- 另一种就是在查询时使用。
实际开发中建议使用后者,前者有问题:如果不重新索引文档,权重无法修改。
# mapping 中使用 boost(不推荐)
PUT blog
{
"mappings": {
"properties": {
"content": {
"type": "text",
"boost": 2
}
}
}
}
# 在查询的时候,指定boost
GET blog/_search
{
"query": {
"match": {
"content": {
"query": "你好",
"boost": 2
}
}
}
}
6、coerce
coerce
参数用来清除脏数据,默认为 true。
例如一个整数,在 JSON 中,用户可能输入了错误的类型:
{
"age": "99"} # 字符串类型
{
"age": 99.0} # 浮点类型
这些都不是正确的数字格式,但是经过 coerce
之后,都能正确的存储为整数类型:
# 设置age为整数类型
PUT blog
{
"mappings": {
"properties": {
"age":{
"type": "integer"
}
}
}
}
# 无论是整数,还是字符串或浮点类型,都能正确的存储
POST blog/_doc
{
"age": 99
}
POST blog/_doc
{
"age": "99"
}
POST blog/_doc
{
"age": 99.0
}
也可以修改 coerce
为 false ,修改之后,只有正确输入整数类型,才能存储,否则报错。
PUT blog
{
"mappings": {
"properties": {
"age":{
"type": "integer",
"coerce": false
}
}
}
}
7、copy_to
这个参数可以将多个字段的值,复制到同一个字段中。
定义和使用方式如下:
PUT blog
{
"mappings": {
"properties": {
"title":{
"type": "text",
"copy_to": "full_content"
},
"content":{
"type": "text",
"copy_to": "full_content"
},
"full_content":{
"type": "text"
}
}
}
}
PUT blog/_doc/1
{
"title":"amby ",
"content":"怡宝的大方哥"
}
GET blog/_search
{
"query": {
"term": {
"full_content": "大"
}
}
}
8、doc_values 和 fielddata
es中的搜索主要是用到倒排索引,doc_values
参数是为了加快排序、聚合操作而生的。当建立倒排索引的时候,会额外增加列式存储映射,以空间换时间。
doc_values
默认是开启的,如果确定某个字段不需要排序或者不需要聚合,那么可以关闭 doc_values。
大部分的字段在索引时都会生成 doc_values
,除了 text。text 字段在查询时会生成一个 fielddata
的数据结构,fieldata
在字段首次被聚合、排序的时候生成。
下面简单对比一下两者的区别:
doc_values | fieldata |
---|---|
默认开启 | 默认关闭 |
索引时创建 | 使用时动态创建 |
磁盘 | 内存 |
不占用内存 | 不占用磁盘 |
索引速度降低一点 | 文档很多时,动态创建慢,占内存 |
fieldata
参数使用场景很少,因为text字段一般都不用与排序和聚合。所以如果真的需要用到这个参数,一定要想清楚为什么,是否还有可替代方法。
doc_values
演示排序效果:
PUT users
PUT users/_doc/1
{
"age":100
}
PUT users/_doc/2
{
"age":99
}
PUT users/_doc/3
{
"age":98
}
PUT users/_doc/4
{
"age":101
}
GET users/_search
{
"query": {
"match_all": {
}
},
"sort":[
{
"age":{
"order": "desc"
}
}
]
}
9、dynamic
dynamic
参数作用是对字段类型动态映射,之前在ElasticSearch学习笔记五(映射mapping)中已经学习过,这里就不再介绍。
10、enabled
es默认会索引所有的字段,但是有的字段可能只需要存储,不需要索引,例如图片url地址。此时可以通过 enabled
字段来控制,设置为 false 之后,就不能再通过该字段进行搜索了。:
PUT blog
{
"mappings": {
"properties": {
"title":{
"enabled": false
}
}
}
}
PUT blog/_doc/1
{
"title":"amby"
}
GET blog/_search
{
"query": {
"term": {
"title": "amby"
}
}
}
11、format
format
参数我们在上一章讲日期类型时介绍过,它可以自定义日期格式,一次可以定义多个 format
。多个日期格式之间,使用 || 符号连接,注意没有空格。
如果没有指定format
,日期类型默认的格式是:strict_date_optional_time||epoch_millis
PUT users
{
"mappings": {
"properties": {
"birthday":{
"type": "date",
"format": "yyyy-MM-dd||yyyy-MM-dd HH:mm:ss"
}
}
}
}
PUT users/_doc/1
{
"birthday":"2020-11-11"
}
PUT users/_doc/2
{
"birthday":"2020-11-11 11:11:11"
}
可以在官网中查看所有的日期格式:
https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-date-format.html
12、ignore_above
ignore_above
用于指定分词和索引的字符串最大长度,超过最大长度的话,该字段将不会被索引,这个字段只适用于 keyword 类型。
PUT blog
{
"mappings": {
"properties": {
"title":{
"type": "keyword",
"ignore_above": 10
}
}
}
}
PUT blog/_doc/1
{
"title":"amby"
}
PUT blog/_doc/2
{
"title":"ambyambyambyamby"
}
GET blog/_search
{
"query": {
"term": {
"title": "ambyambyambyamby"
}
}
}
13、ignore_malformed
ignore_malformed
参数可以忽略不规则的数据,该参数默认为 false。
PUT users
{
"mappings": {
"properties": {
"birthday":{
"type": "date",
"format": "yyyy-MM-dd||yyyy-MM-dd HH:mm:ss"
},
"age":{
"type": "integer",
"ignore_malformed": true
}
}
}
}
PUT users/_doc/1
{
"birthday":"2020-11-11",
"age":99
}
PUT users/_doc/2
{
"birthday":"2020-11-11 11:11:11",
"age":"abc"
}
PUT users/_doc/2
{
"birthday":"2020-11-11 11:11:11aaa",
"age":"abc"
}
14、include_in_all
这个是针对 _all
字段的,但是在 es7 中,该字段已经被废弃了。
15、index
index
参数用于指定一个字段是否被索引,为 true 表示字段被索引,false 表示字段不被索引。
注意,如果字段不能被索引,也就不能通过该字段进行搜索。
PUT users
{
"mappings": {
"properties": {
"age":{
"type": "integer",
"index": false
}
}
}
}
PUT users/_doc/1
{
"age":99
}
GET users/_search
{
"query": {
"term": {
"age": 99
}
}
}
16、index_options
index_options
参数用于控制索引时哪些信息被存储到倒排索引中,仅作用在 text 字段,有四种取值:
- docs:只存储文档编号。
- freqs:在docs基础上,存储词项频率。
- positions (默认):在freqs基础上,存储词项偏移位置。
- offsets:在positions基础上,存储词项开始和结束的字符位置。
17、norms
norms
对字段评分有用,text 类型会默认开启,如果不是特别需要,不要开启 norms
。
18、null_value
在es 中,值为 null 的字段不索引也不可以被搜索,null_value
可以让值为 null 的字段显式的可索引、可搜索:
PUT users
{
"mappings": {
"properties": {
"name":{
"type": "keyword",
"null_value": "javaboy_null"
}
}
}
}
PUT users/_doc/1
{
"name":null,
"age":99
}
GET users/_search
{
"query": {
"term": {
"name": "javaboy_null"
}
}
}
19、position_increment_gap
被解析的 text 字段会将 term 的位置考虑进去,目的是为了支持近似查询和短语查询。当我们去索引一个含有多个值的 text 字段时,会在各个值之间添加一个假想的空间,将值隔开,这样就可以有效避免一些无意义的短语匹配。
间隙大小通过 position_increment_gap
参数来控制,默认是 100。
下面进行演示:
PUT users
# 添加一个数组
PUT users/_doc/1
{
"name":["zhang san","li si"]
}
# 当我们使用“zhang san”或“li si”,可以查询到。如果使用“san li”则查询不了,因为数组中两个值之间间隔了100的空隙,需要指定空隙大小进行查询。
GET users/_search
{
"query": {
"match_phrase": {
"name": {
"query": "san li"
}
}
}
}
# 第一种方式:查询时通过slop指定
GET users/_search
{
"query": {
"match_phrase": {
"name": {
"query": "san li",
"slop": 100
}
}
}
}
# 第二种方式:定义索引时,通过position_increment_gap指定
PUT users
{
"mappings": {
"properties": {
"name":{
"type": "text",
"position_increment_gap": 0
}
}
}
}
20、properties
properties
是最常用的参数之一,可以作用于 mappings
、object
字段、 nested
字段中,进行属性的添加。这些属性可以是任意字段类型,包括 object
和 nested
。可以通过以下三种方式添加属性:
- 创建索引时定义。
- 使用PUT mapping 添加或更新字段类型时定义。
- 索引包含新字段的文档时,通过动态映射定义。
PUT people
{
"mappings": {
"properties": {
"manager": {
"properties": {
"age": {
"type": "integer" },
"name": {
"type": "text" }
}
},
"employees": {
"type": "nested",
"properties": {
"age": {
"type": "integer" },
"name": {
"type": "text" }
}
}
}
}
}
PUT people/_doc/1
{
"manager": {
"name": "Alice White",
"age": 30
},
"employees": [
{
"name": "John Smith",
"age": 34
},
{
"name": "Peter Brown",
"age": 26
}
]
}
21、similarity
similarity
参数用于指定文档的评分模型,使用到的情况不多,默认有三种:
- BM25:es 和 Lucene 默认的评分模型。
- classic:TF/IDF 评分。
- boolean:boolean 评分模型。
22、store
默认情况下,字段会被索引,也可以搜索,但是不会存储,虽然不会被存储的,但是 _source 中有一个字段的备份。如果想将字段存储下来,可以通过配置 store
参数来实现。
23、term_vectors
term_vectors
是通过分词器产生的词项信息,包括:
- 一组 terms
- 每个 term 的位置
- term 的首字符 / 尾字符与原始字符串原点的偏移量
term_vectors取值 | |
---|---|
no | 不存储信息 |
yes | 存储 term 信息 |
with_positions | 存储 term 信息和位置信息 |
with_offset | 存储 term 信息和偏移信息 |
with_positions_offset | 存储 term 信息、位置信息和偏移信息 |
24、fields
fields
参数可以让同一字段有多种不同的索引方式。例如:
PUT blog
{
"mappings": {
"properties": {
"title":{
"type": "text",
"fields": {
"raw":{
"type":"keyword"
}
}
}
}
}
}
PUT blog/_doc/1
{
"title":"javaboy"
}
GET blog/_search
{
"query": {
"term": {
"title.raw": "javaboy"
}
}
}
版权声明:
本文仅记录ElasticSearch学习心得,如有侵权请联系删除。
更多内容请访问原创作者:江南一点雨
版权声明:本文不是「本站」原创文章,版权归原作者所有 | 原文地址: