ElasticSearch学习笔记七(映射参数)

本学习笔记基于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字段在索引或者查询时都不会进行分词。如果在索引前没有做好数据清洗,导致大小写不一致,例如 ambyAmby,使用 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_valuesfieldata
默认开启默认关闭
索引时创建使用时动态创建
磁盘内存
不占用内存不占用磁盘
索引速度降低一点文档很多时,动态创建慢,占内存

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 是最常用的参数之一,可以作用于 mappingsobject 字段、 nested 字段中,进行属性的添加。这些属性可以是任意字段类型,包括 objectnested 。可以通过以下三种方式添加属性:

  • 创建索引时定义。
  • 使用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学习心得,如有侵权请联系删除。
更多内容请访问原创作者:江南一点雨
微信公众号:江南一点雨

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值