ElasticSearch必知必会-基础篇

打印 上一主题 下一主题

主题 1824|帖子 1824|积分 5474

商业发展与职能技术部-体验保障研发组 康睿 姚再毅 李振 刘斌 王北永

说明:以下全部均基于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
  1. // 删除test01索引,保证这个索引现在是干净的
  2. DELETE test01
  3. // 不定义mapping,直接一条插入数据试试看,
  4. POST test01/_doc/1
  5. {
  6.   "name":"kangrui10"
  7. }
  8. // 然后我们查看test01该索引的mapping结构 看看name这个字段被定义成了什么类型
  9. // 由此可以看出,name一级为text类型,二级定义为keyword,但其实这并不是我们想要的结果,
  10. // 我们业务查询中name字段并不会被分词查询,一般都是全匹配(and name = xxx)
  11. // 以下的这种结果,我们想要实现全匹配 就需要 name.keyword = xxx  反而麻烦
  12. GET test01/_mapping
  13. {
  14.   "test01" : {
  15.     "mappings" : {
  16.       "properties" : {
  17.         "name" : {
  18.           "type" : "text",
  19.           "fields" : {
  20.             "keyword" : {
  21.               "type" : "keyword",
  22.               "ignore_above" : 256
  23.             }
  24.           }
  25.         }
  26.       }
  27.     }
  28.   }
  29. }
复制代码
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将会无法使用,但会节省磁盘空间
真题演练
  1. // 创建一个索引,test03,字段满足以下条件
  2. //     1. speaker: keyword
  3. //     2. line_id: keyword and not aggregateable
  4. //     3. speech_number: integer
  5. PUT test03
  6. {
  7.   "mappings": {
  8.     "properties": {
  9.       "speaker": {
  10.         "type": "keyword"
  11.       },
  12.       "line_id":{
  13.         "type": "keyword",
  14.         "doc_values": false
  15.       },
  16.       "speech_number":{
  17.         "type": "integer"
  18.       }
  19.     }
  20.   }
  21. }
复制代码
四.分词器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
  1. # 新建索引
  2. PUT /test01
  3. {
  4.   "settings": {
  5.     "analysis": {
  6.       "analyzer": {
  7.         "my_analyzer": {
  8.           "char_filter": [
  9.             "my_mappings_char_filter"
  10.           ],
  11.           "tokenizer": "standard",
  12.         }
  13.       },
  14.       "char_filter": {
  15.         "my_mappings_char_filter": {
  16.           "type": "mapping",
  17.           "mappings": [
  18.             "& => and"
  19.           ]
  20.         }
  21.       }
  22.     }
  23.   },
  24.   "mappings": {
  25.     "properties": {
  26.       "content":{
  27.         "type": "text",
  28.         "analyzer": "my_analyzer"
  29.       }
  30.     }
  31.   }
  32. }
  33. // 说明
  34. // 三段论之Character filters,使用char_filter进行文本替换
  35. // 三段论之Token filters,使用默认分词器
  36. // 三段论之Token filters,未设定
  37. // 字段content 使用自定义分词器my_analyzer
  38. # 填充测试数据
  39. PUT test01/_bulk
  40. {"index":{"_id":1}}
  41. {"content":"doc & cat"}
  42. {"index":{"_id":2}}
  43. {"content":"doc and cat"}
  44. # 执行测试,doc & cat || oc and cat 结果输出都为两条
  45. POST test01/_search
  46. {
  47.   "query": {
  48.     "bool": {
  49.       "must": [
  50.         {
  51.           "match_phrase": {
  52.             "content": "doc & cat"
  53.           }
  54.         }
  55.       ]
  56.     }
  57.   }
  58. }
复制代码
解法2
  1. # 解题思路,将& 和 and  设定为同义词,使用Token filters
  2. # 创建索引
  3. PUT /test02
  4. {
  5.   "settings": {
  6.     "analysis": {
  7.       "analyzer": {
  8.         "my_synonym_analyzer": {
  9.           "tokenizer": "whitespace",
  10.           "filter": [
  11.             "my_synonym"
  12.           ]
  13.         }
  14.       },
  15.       "filter": {
  16.         "my_synonym": {
  17.           "type": "synonym",
  18.           "lenient": true,
  19.           "synonyms": [
  20.             "& => and"
  21.           ]
  22.         }
  23.       }
  24.     }
  25.   },
  26.   "mappings": {
  27.     "properties": {
  28.       "content": {
  29.         "type": "text",
  30.         "analyzer": "my_synonym_analyzer"
  31.       }
  32.     }
  33.   }
  34. }
  35. // 说明
  36. // 三段论之Character filters,未设定
  37. // 三段论之Token filters,使用whitespace空格分词器,为什么不用默认分词器?因为默认分词器会把&分词后剔除了,就无法在去做分词后的过滤操作了
  38. // 三段论之Token filters,使用synony分词后过滤器,对&和and做同义词
  39. // 字段content 使用自定义分词器my_synonym_analyzer
  40. # 填充测试数据
  41. PUT test02/_bulk
  42. {"index":{"_id":1}}
  43. {"content":"doc & cat"}
  44. {"index":{"_id":2}}
  45. {"content":"doc and cat"}
  46. # 执行测试
  47. POST test02/_search
  48. {
  49.   "query": {
  50.     "bool": {
  51.       "must": [
  52.         {
  53.           "match_phrase": {
  54.             "content": "doc & cat"
  55.           }
  56.         }
  57.       ]
  58.     }
  59.   }
  60. }
复制代码
六.multi-fields

官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/multi-fields.html
  1. // 单字段多类型,比如一个字段我想设置两种分词器
  2. PUT my-index-000001
  3. {
  4.   "mappings": {
  5.     "properties": {
  6.       "city": {
  7.         "type": "text",
  8.         "analyzer":"standard",
  9.         "fields": {
  10.           "fieldText": {
  11.             "type":  "text",
  12.             "analyzer":"ik_smart",
  13.           }
  14.         }
  15.       }
  16.     }
  17.   }
  18. }
复制代码
七.runtime_field 运行时字段

官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/runtime.html
产生背景

假如业务中需要根据某两个数字类型字段的差值来排序,也就是我需要一个不存在的字段, 那么此时应该怎么办? 当然你可以刷数,新增一个差值结果字段来实现,假如此时不允许你刷数新增字段怎么办?
解决方案



应用场景


  • 在不重新建立索引的情况下,向现有文档新增字段
  • 在不了解数据结构的情况下处理数据
  • 在查询时覆盖从原索引字段返回的值
  • 为特定用途定义字段而不修改底层架构
功能特性


  • Lucene完全无感知,因没有被索引化,没有doc_values
  • 不支持评分,因为没有倒排索引
  • 打破传统先定义后使用的方式
  • 能阻止mapping爆炸
  • 增加了API的灵活性
  • 注意,会使得搜索变慢
实际使用


  • 运行时检索指定,即检索环节可使用(也就是哪怕mapping中没有这个字段,我也可以查询)
  • 动态或静态mapping指定,即mapping环节可使用(也就是在mapping中添加一个运行时的字段)
真题演练1
  1. # 假定有以下索引和数据
  2. PUT test03
  3. {
  4.   "mappings": {
  5.     "properties": {
  6.       "emotion": {
  7.         "type": "integer"
  8.       }
  9.     }
  10.   }
  11. }
  12. POST test03/_bulk
  13. {"index":{"_id":1}}
  14. {"emotion":2}
  15. {"index":{"_id":2}}
  16. {"emotion":5}
  17. {"index":{"_id":3}}
  18. {"emotion":10}
  19. {"index":{"_id":4}}
  20. {"emotion":3}
  21. # 要求:emotion > 5, 返回emotion_falg = '1',  
  22. # 要求:emotion < 5, 返回emotion_falg = '-1',  
  23. # 要求:emotion = 5, 返回emotion_falg = '0',  
复制代码
解法1

检索时指定运行时字段: https://www.elastic.co/guide/en/elasticsearch/reference/8.1/runtime-search-request.html 该字段本质上是不存在的,所以需要检索时要加上 fields *
  1. GET test03/_search
  2. {
  3.   "fields": [
  4.     "*"
  5.   ],
  6.   "runtime_mappings": {
  7.     "emotion_falg": {
  8.       "type": "keyword",
  9.       "script": {
  10.         "source": """
  11.           if(doc['emotion'].value>5)emit('1');
  12.           if(doc['emotion'].value<5)emit('-1');
  13.           if(doc['emotion'].value==5)emit('0');
  14.           """
  15.       }
  16.     }
  17.   }
  18. }
复制代码
真题演练
  1. # 创建索引并指定运行时字段
  2. PUT test03_01
  3. {
  4.   "mappings": {
  5.     "runtime": {
  6.       "emotion_falg": {
  7.         "type": "keyword",
  8.         "script": {
  9.           "source": """
  10.           if(doc['emotion'].value>5)emit('1');
  11.           if(doc['emotion'].value<5)emit('-1');
  12.           if(doc['emotion'].value==5)emit('0');
  13.           """
  14.         }
  15.       }
  16.     },
  17.     "properties": {
  18.       "emotion": {
  19.         "type": "integer"
  20.       }
  21.     }
  22.   }
  23. }
  24. # 导入测试数据
  25. POST test03_01/_bulk
  26. {"index":{"_id":1}}
  27. {"emotion":2}
  28. {"index":{"_id":2}}
  29. {"emotion":5}
  30. {"index":{"_id":3}}
  31. {"emotion":10}
  32. {"index":{"_id":4}}
  33. {"emotion":3}
  34. # 查询测试
  35. GET test03_01/_search
  36. {
  37.   "fields": [
  38.     "*"
  39.   ]
  40. }
复制代码
</b>
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

tsx81428

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表