商业发展与职能技术部-体验保障研发组 康睿 姚再毅 李振 刘斌 王北永
说明:以下全部均基于eslaticsearch 8.1 版本
一.索引的定义
官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/indices.html
索引的全局认知
ElasticSearchMysqlIndexTableType废弃Table废弃DocumentRowFieldColumnMappingSchemaEverything is indexedIndexQuery DSLSQLGET http://...select * fromPOST http://...update table set ...Aggregationsgroup by\sum\sumcardinality去重 distinctreindex数据迁移索引的定义
定义: 相同文档结构(Mapping)文档的结合 由唯一索引名称标定 一个集群中有多个索引 不同的索引代表不同的业务类型数据 注意事项: 索引名称不支持大写 索引名称最大支持255个字符长度 字段的名称,支持大写,不过建议全部统一小写
索引的创建

index-settings 参数解析
官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/index-modules.html
注意: 静态参数索引创建后,不再可以修改,动态参数可以修改 思考: 一、为什么主分片创建后不可修改? A document is routed to a particular shard in an index using the following formula: the defalue value userd for _routing is the document`s _id es中写入数据,是根据上述的公式计算文档应该存储在哪个分片中,后续的文档读取也是根据这个公式,一旦分片数改变,数据也就找不到了 简单理解 根据ID做Hash 然后再 除以 主分片数 取余,被除数改变,结果就不一样了 二、如果业务层面根据数据情况,确实需要扩展主分片数,那怎么办? reindex 迁移数据到另外一个索引 https://www.elastic.co/guide/en/elasticsearch/reference/8.1/docs-reindex.html

索引的基本操作

二.Mapping-Param之dynamic
官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/dynamic.html
核心功能
自动检测字段类型后添加字段 也就是哪怕你没有在es的mapping中定义该字段,es也会动态的帮你检测字段类型
初识dynamic
- // 删除test01索引,保证这个索引现在是干净的
- DELETE test01
- // 不定义mapping,直接一条插入数据试试看,
- POST test01/_doc/1
- {
- "name":"kangrui10"
- }
- // 然后我们查看test01该索引的mapping结构 看看name这个字段被定义成了什么类型
- // 由此可以看出,name一级为text类型,二级定义为keyword,但其实这并不是我们想要的结果,
- // 我们业务查询中name字段并不会被分词查询,一般都是全匹配(and name = xxx)
- // 以下的这种结果,我们想要实现全匹配 就需要 name.keyword = xxx 反而麻烦
- GET test01/_mapping
- {
- "test01" : {
- "mappings" : {
- "properties" : {
- "name" : {
- "type" : "text",
- "fields" : {
- "keyword" : {
- "type" : "keyword",
- "ignore_above" : 256
- }
- }
- }
- }
- }
- }
- }
复制代码 dynamic的可选值
可选值说明解释trueNew fields are added to the mapping (default).创建mapping时,如果不指定dynamic的值,默认true,即如果你的字段没有收到指定类型,就会es帮你动态匹配字段类型falseNew fields are ignored. These fields will not be indexed or searchable, but will still appear in the _source field of returned hits. These fields will not be added to the mapping, and new fields must be added explicitly.若设置为false,如果你的字段没有在es的mapping中创建,那么新的字段,一样可以写入,但是不能被查询,mapping中也不会有这个字段,也就是被写入的字段,不会被创建索引strictIf new fields are detected, an exception is thrown and the document is rejected. New fields must be explicitly added to the mapping.若设置为strict,如果新的字段,没有在mapping中创建字段,添加会直接报错,生产环境推荐,更加严谨。示例如下,如要新增字段,就必须手动的新增字段动态映射的弊端
- 字段匹配相对准确,但不一定是用户期望的
- 比如现在有一个text字段,es只会给你设置为默认的standard分词器,但我们一般需要的是ik中文分词器
- 占用多余的存储空间
- string类型匹配为text和keyword两种类型,意味着会占用更多的存储空间
- mapping爆炸
- 如果不小心写错了查询语句,get用成了put误操作,就会错误创建很多字段
三.Mapping-Param之doc_values
官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/doc-values.html
核心功能
DocValue其实是Lucene在构建倒排索引时,会额外建立一个有序的正排索引(基于document => field value的映射列表) DocValue本质上是一个序列化的 列式存储,这个结构非常适用于聚合(aggregations)、排序(Sorting)、脚本(scripts access to field)等操作。而且,这种存储方式也非常便于压缩,特别是数字类型。这样可以减少磁盘空间并且提高访问速度。 几乎所有字段类型都支持DocValue,除了text和annotated_text字段。
何为正排索引
正排索引其实就是类似于数据库表,通过id和数据进行关联,通过搜索文档id,来获取对应的数据
doc_values可选值
- true:默认值,默认开启
- false:需手动指定,设置为false后,sort、aggregate、access the field from script将会无法使用,但会节省磁盘空间
真题演练
- // 创建一个索引,test03,字段满足以下条件
- // 1. speaker: keyword
- // 2. line_id: keyword and not aggregateable
- // 3. speech_number: integer
- PUT test03
- {
- "mappings": {
- "properties": {
- "speaker": {
- "type": "keyword"
- },
- "line_id":{
- "type": "keyword",
- "doc_values": false
- },
- "speech_number":{
- "type": "integer"
- }
- }
- }
- }
复制代码 四.分词器analyzers
ik中文分词器安装
https://github.com/medcl/elasticsearch-analysis-ik
何为倒排索引

数据索引化的过程

分词器的分类
官网地址: https://www.elastic.co/guide/en/elasticsearch/reference/8.1/analysis-analyzers.html

五.自定义分词
自定义分词器三段论
1.Character filters 字符过滤
官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/analysis-charfilters.html 可配置0个或多个
HTML Strip Character Filter:用途:删除HTML元素,如 ,并解 码HTML实体,如&amp
<b>Mapping Character Filter:用途:替换指定字符
Pattern Replace Character Filter:用途:基于正则表达式替换指定字符
2.Tokenizer 文本切为分词
官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/analysis-tokenizers.html#_word_oriented_tokenizers 只能配置一个 用分词器对文本进行分词
3.Token filters 分词后再过滤
官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/analysis-tokenfilters.html 可配置0个或多个 分词后再加工,比如转小写、删除某些特殊的停用词、增加同义词等
真题演练
有一个文档,内容类似 dag & cat, 要求索引这个文档,并且使用match_parase_query, 查询dag & cat 或者 dag and cat,都能够查到 题目分析: 1.何为match_parase_query:match_phrase 会将检索关键词分词。match_phrase的分词结果必须在被检索字段的分词中都包含,而且顺序必须相同,而且默认必须都是连续的。 2.要实现 & 和 and 查询结果要等价,那么就需要自定义分词器来实现了,定制化的需求 3.如何自定义一个分词器:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/analysis-custom-analyzer.html 4.解法1核心使用功能点,Mapping Character Filter 5.解法2核心使用功能点,https://www.elastic.co/guide/en/elasticsearch/reference/8.1/analysis-synonym-tokenfilter.html
解法1
- # 新建索引
- PUT /test01
- {
- "settings": {
- "analysis": {
- "analyzer": {
- "my_analyzer": {
- "char_filter": [
- "my_mappings_char_filter"
- ],
- "tokenizer": "standard",
- }
- },
- "char_filter": {
- "my_mappings_char_filter": {
- "type": "mapping",
- "mappings": [
- "& => and"
- ]
- }
- }
- }
- },
- "mappings": {
- "properties": {
- "content":{
- "type": "text",
- "analyzer": "my_analyzer"
- }
- }
- }
- }
- // 说明
- // 三段论之Character filters,使用char_filter进行文本替换
- // 三段论之Token filters,使用默认分词器
- // 三段论之Token filters,未设定
- // 字段content 使用自定义分词器my_analyzer
- # 填充测试数据
- PUT test01/_bulk
- {"index":{"_id":1}}
- {"content":"doc & cat"}
- {"index":{"_id":2}}
- {"content":"doc and cat"}
- # 执行测试,doc & cat || oc and cat 结果输出都为两条
- POST test01/_search
- {
- "query": {
- "bool": {
- "must": [
- {
- "match_phrase": {
- "content": "doc & cat"
- }
- }
- ]
- }
- }
- }
复制代码 解法2
- # 解题思路,将& 和 and 设定为同义词,使用Token filters
- # 创建索引
- PUT /test02
- {
- "settings": {
- "analysis": {
- "analyzer": {
- "my_synonym_analyzer": {
- "tokenizer": "whitespace",
- "filter": [
- "my_synonym"
- ]
- }
- },
- "filter": {
- "my_synonym": {
- "type": "synonym",
- "lenient": true,
- "synonyms": [
- "& => and"
- ]
- }
- }
- }
- },
- "mappings": {
- "properties": {
- "content": {
- "type": "text",
- "analyzer": "my_synonym_analyzer"
- }
- }
- }
- }
- // 说明
- // 三段论之Character filters,未设定
- // 三段论之Token filters,使用whitespace空格分词器,为什么不用默认分词器?因为默认分词器会把&分词后剔除了,就无法在去做分词后的过滤操作了
- // 三段论之Token filters,使用synony分词后过滤器,对&和and做同义词
- // 字段content 使用自定义分词器my_synonym_analyzer
- # 填充测试数据
- PUT test02/_bulk
- {"index":{"_id":1}}
- {"content":"doc & cat"}
- {"index":{"_id":2}}
- {"content":"doc and cat"}
- # 执行测试
- POST test02/_search
- {
- "query": {
- "bool": {
- "must": [
- {
- "match_phrase": {
- "content": "doc & cat"
- }
- }
- ]
- }
- }
- }
复制代码 六.multi-fields
官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/multi-fields.html
- // 单字段多类型,比如一个字段我想设置两种分词器
- PUT my-index-000001
- {
- "mappings": {
- "properties": {
- "city": {
- "type": "text",
- "analyzer":"standard",
- "fields": {
- "fieldText": {
- "type": "text",
- "analyzer":"ik_smart",
- }
- }
- }
- }
- }
- }
复制代码 七.runtime_field 运行时字段
官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/runtime.html
产生背景
假如业务中需要根据某两个数字类型字段的差值来排序,也就是我需要一个不存在的字段, 那么此时应该怎么办? 当然你可以刷数,新增一个差值结果字段来实现,假如此时不允许你刷数新增字段怎么办?
解决方案

应用场景
- 在不重新建立索引的情况下,向现有文档新增字段
- 在不了解数据结构的情况下处理数据
- 在查询时覆盖从原索引字段返回的值
- 为特定用途定义字段而不修改底层架构
功能特性
- Lucene完全无感知,因没有被索引化,没有doc_values
- 不支持评分,因为没有倒排索引
- 打破传统先定义后使用的方式
- 能阻止mapping爆炸
- 增加了API的灵活性
- 注意,会使得搜索变慢
实际使用
- 运行时检索指定,即检索环节可使用(也就是哪怕mapping中没有这个字段,我也可以查询)
- 动态或静态mapping指定,即mapping环节可使用(也就是在mapping中添加一个运行时的字段)
真题演练1
- # 假定有以下索引和数据
- PUT test03
- {
- "mappings": {
- "properties": {
- "emotion": {
- "type": "integer"
- }
- }
- }
- }
- POST test03/_bulk
- {"index":{"_id":1}}
- {"emotion":2}
- {"index":{"_id":2}}
- {"emotion":5}
- {"index":{"_id":3}}
- {"emotion":10}
- {"index":{"_id":4}}
- {"emotion":3}
- # 要求:emotion > 5, 返回emotion_falg = '1',
- # 要求:emotion < 5, 返回emotion_falg = '-1',
- # 要求:emotion = 5, 返回emotion_falg = '0',
复制代码 解法1
检索时指定运行时字段: https://www.elastic.co/guide/en/elasticsearch/reference/8.1/runtime-search-request.html 该字段本质上是不存在的,所以需要检索时要加上 fields *- GET test03/_search
- {
- "fields": [
- "*"
- ],
- "runtime_mappings": {
- "emotion_falg": {
- "type": "keyword",
- "script": {
- "source": """
- if(doc['emotion'].value>5)emit('1');
- if(doc['emotion'].value<5)emit('-1');
- if(doc['emotion'].value==5)emit('0');
- """
- }
- }
- }
- }
复制代码 真题演练
- # 创建索引并指定运行时字段
- PUT test03_01
- {
- "mappings": {
- "runtime": {
- "emotion_falg": {
- "type": "keyword",
- "script": {
- "source": """
- if(doc['emotion'].value>5)emit('1');
- if(doc['emotion'].value<5)emit('-1');
- if(doc['emotion'].value==5)emit('0');
- """
- }
- }
- },
- "properties": {
- "emotion": {
- "type": "integer"
- }
- }
- }
- }
- # 导入测试数据
- POST test03_01/_bulk
- {"index":{"_id":1}}
- {"emotion":2}
- {"index":{"_id":2}}
- {"emotion":5}
- {"index":{"_id":3}}
- {"emotion":10}
- {"index":{"_id":4}}
- {"emotion":3}
- # 查询测试
- GET test03_01/_search
- {
- "fields": [
- "*"
- ]
- }
复制代码 </b>
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |