商业发展与职能技术部-体验保障研发组 康睿 姚再毅 李振 刘斌 王北永
说明:以下全部均基于eslaticsearch 8.1 版本
一.索引的定义
官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/indices.html
索引的全局认知
| ElasticSearch | Mysql |
|---|---|
| Index | Table |
| Type废弃 | Table废弃 |
| Document | Row |
| Field | Column |
| Mapping | Schema |
| Everything is indexed | Index |
| Query DSL | SQL |
| GET http://... | select * from |
| POST http://... | update table set ... |
| Aggregations | group by\sum\sum |
| cardinality | 去重 distinct |
| reindex | 数据迁移 |
索引的定义
定义: 相同文档结构(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: <shard_num = hash(_routing) % num_primary_shards> 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索引,保证这个索引现在是干净的 2DELETE test01 3 4// 不定义mapping,直接一条插入数据试试看, 5POST test01/_doc/1 6{ 7 "name":"kangrui10" 8} 9 10// 然后我们查看test01该索引的mapping结构 看看name这个字段被定义成了什么类型 11// 由此可以看出,name一级为text类型,二级定义为keyword,但其实这并不是我们想要的结果, 12// 我们业务查询中name字段并不会被分词查询,一般都是全匹配(and name = xxx) 13// 以下的这种结果,我们想要实现全匹配 就需要 name.keyword = xxx 反而麻烦 14GET test01/_mapping 15{ 16 "test01" : { 17 "mappings" : { 18 "properties" : { 19 "name" : { 20 "type" : "text", 21 "fields" : { 22 "keyword" : { 23 "type" : "keyword", 24 "ignore_above" : 256 25 } 26 } 27 } 28 } 29 } 30 } 31}
dynamic的可选值
| 可选值 | 说明 | 解释 |
|---|---|---|
| true | New fields are added to the mapping (default). | 创建mapping时,如果不指定dynamic的值,默认true,即如果你的字段没有收到指定类型,就会es帮你动态匹配字段类型 |
| false | New 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中也不会有这个字段,也就是被写入的字段,不会被创建索引 |
| strict | If 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 5PUT 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://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元素,如 <b>,并解 码HTML实体,如&amp
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# 新建索引 2PUT /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# 填充测试数据 40PUT test01/_bulk 41{"index":{"_id":1}} 42{"content":"doc & cat"} 43{"index":{"_id":2}} 44{"content":"doc and cat"} 45 46# 执行测试,doc & cat || oc and cat 结果输出都为两条 47POST test01/_search 48{ 49 "query": { 50 "bool": { 51 "must": [ 52 { 53 "match_phrase": { 54 "content": "doc & cat" 55 } 56 } 57 ] 58 } 59 } 60}
解法2
1# 解题思路,将& 和 and 设定为同义词,使用Token filters 2# 创建索引 3PUT /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# 填充测试数据 42PUT test02/_bulk 43{"index":{"_id":1}} 44{"content":"doc & cat"} 45{"index":{"_id":2}} 46{"content":"doc and cat"} 47 48# 执行测试 49POST test02/_search 50{ 51 "query": { 52 "bool": { 53 "must": [ 54 { 55 "match_phrase": { 56 "content": "doc & cat" 57 } 58 } 59 ] 60 } 61 } 62}
六.multi-fields
官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/multi-fields.html
1// 单字段多类型,比如一个字段我想设置两种分词器 2PUT 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# 假定有以下索引和数据 2PUT test03 3{ 4 "mappings": { 5 "properties": { 6 "emotion": { 7 "type": "integer" 8 } 9 } 10 } 11} 12POST 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 22# 要求:emotion > 5, 返回emotion_falg = '1', 23# 要求:emotion < 5, 返回emotion_falg = '-1', 24# 要求:emotion = 5, 返回emotion_falg = '0',
解法1
检索时指定运行时字段: https://www.elastic.co/guide/en/elasticsearch/reference/8.1/runtime-search-request.html 该字段本质上是不存在的,所以需要检索时要加上 fields *
1GET 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}
解法2
创建索引时指定运行时字段:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/runtime-mapping-fields.html 该方式支持通过运行时字段做检索
1# 创建索引并指定运行时字段 2PUT 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# 导入测试数据 25POST 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# 查询测试 35GET test03_01/_search 36{ 37 "fields": [ 38 "*" 39 ] 40}
真题演练2
1# 有以下索引和数据 2PUT test04 3{ 4 "mappings": { 5 "properties": { 6 "A":{ 7 "type": "long" 8 }, 9 "B":{ 10 "type": "long" 11 } 12 } 13 } 14} 15PUT task04/_bulk 16{"index":{"_id":1}} 17{"A":100,"B":2} 18{"index":{"_id":2}} 19{"A":120,"B":2} 20{"index":{"_id":3}} 21{"A":120,"B":25} 22{"index":{"_id":4}} 23{"A":21,"B":25} 24 25# 需求:在task04索引里,创建一个runtime字段,其值是A-B,名称为A_B; 创建一个range聚合,分为三级:小于0,0-100,100以上;返回文档数 26// 使用知识点: 27// 1.检索时指定运行时字段: https://www.elastic.co/guide/en/elasticsearch/reference/8.1/runtime-search-request.html 28// 2.范围聚合 https://www.elastic.co/guide/en/elasticsearch/reference/8.1/search-aggregations-bucket-range-aggregation.html
解法
1# 结果测试 2GET task04/_search 3{ 4 "fields": [ 5 "*" 6 ], 7 "size": 0, 8 "runtime_mappings": { 9 "A_B": { 10 "type": "long", 11 "script": { 12 "source": """ 13 emit(doc['A'].value - doc['B'].value); 14 """ 15 } 16 } 17 }, 18 "aggs": { 19 "price_ranges_A_B": { 20 "range": { 21 "field": "A_B", 22 "ranges": [ 23 { "to": 0 }, 24 { "from": 0, "to": 100 }, 25 { "from": 100 } 26 ] 27 } 28 } 29 } 30}
八.Search-highlighted
highlighted语法初识
官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/highlighting.html
九.Search-Order
Order语法初识
官网文档地址: https://www.elastic.co/guide/en/elasticsearch/reference/8.1/sort-search-results.html
1// 注意:text类型默认是不能排或聚合的,如果非要排序或聚合,需要开启fielddata 2GET /kibana_sample_data_ecommerce/_search 3{ 4 "query": { 5 "match": { 6 "customer_last_name": "wood" 7 } 8 }, 9 "highlight": { 10 "number_of_fragments": 3, 11 "fragment_size": 150, 12 "fields": { 13 "customer_last_name": { 14 "pre_tags": [ 15 "<em>" 16 ], 17 "post_tags": [ 18 "</em>" 19 ] 20 } 21 } 22 }, 23 "sort": [ 24 { 25 "currency": { 26 "order": "desc" 27 }, 28 "_score": { 29 "order": "asc" 30 } 31 } 32 ] 33}
十.Search-Page
page语法初识
官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/paginate-search-results.html
1# 注意 from的起始值是 0 不是 1 2GET kibana_sample_data_ecommerce/_search 3{ 4 "from": 5, 5 "size": 20, 6 "query": { 7 "match": { 8 "customer_last_name": "wood" 9 } 10 } 11}
真题演练1
1# 题目 2In the spoken lines of the play, highlight the word Hamlet (int the text_entry field) startint the highlihnt with "#aaa#" and ending it with "#bbb#" 3return all of speech_number field lines in reverse order; '20' speech lines per page,starting from line '40' 4 5# highlight 处理 text_entry 字段 ; 关键词 Hamlet 高亮 6# page分页:from:40;size:20 7# speech_number:倒序 8 9POST test09/_search 10{ 11 "from": 40, 12 "size": 20, 13 "query": { 14 "bool": { 15 "must": [ 16 { 17 "match": { 18 "text_entry": "Hamlet" 19 } 20 } 21 ] 22 } 23 }, 24 "highlight": { 25 "fields": { 26 "text_entry": { 27 "pre_tags": [ 28 "#aaa#" 29 ], 30 "post_tags": [ 31 "#bbb#" 32 ] 33 } 34 } 35 }, 36 "sort": [ 37 { 38 "speech_number.keyword": { 39 "order": "desc" 40 } 41 } 42 ] 43}
十一.Search-AsyncSearch
官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/async-search.html
发行版本
7.7.0
适用场景
允许用户在异步搜索结果时可以检索,从而消除了仅在查询完成后才等待最终响应的情况
常用命令
- 执行异步检索
- POST /sales*/_async_search?size=0
- 查看异步检索
- GET /_async_search/id值
- 查看异步检索状态
- GET /_async_search/id值
- 删除、终止异步检索
- DELETE /_async_search/id值
异步查询结果说明
| 返回值 | 含义 |
|---|---|
| id | 异步检索返回的唯一标识符 |
| is_partial | 当查询不再运行时,指示再所有分片上搜索是成功还是失败。在执行查询时,is_partial=true |
| is_running | 搜索是否仍然再执行 |
| total | 将在多少分片上执行搜索 |
| successful | 有多少分片已经成功完成搜索 |
十二.Aliases索引别名
官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/aliases.html
Aliases的作用
在ES中,索引别名(index aliases)就像一个快捷方式或软连接,可以指向一个或多个索引。别名带给我们极大的灵活性,我们可以使用索引别名实现以下功能:
- 在一个运行中的ES集群中无缝的切换一个索引到另一个索引上(无需停机)
- 分组多个索引,比如按月创建的索引,我们可以通过别名构造出一个最近3个月的索引
- 查询一个索引里面的部分数据构成一个类似数据库的视图(views
假设没有别名,如何处理多索引的检索
方式1:POST index_01,index_02.index_03/_search 方式2:POST index*/search
创建别名的三种方式
- 创建索引的同时指定别名
1# 指定test05的别名为 test05_aliases 2PUT test05 3{ 4 "mappings": { 5 "properties": { 6 "name":{ 7 "type": "keyword" 8 } 9 } 10 }, 11 "aliases": { 12 "test05_aliases": {} 13 } 14}
- 使用索引模板的方式指定别名
1PUT _index_template/template_1 2{ 3 "index_patterns": ["te*", "bar*"], 4 "template": { 5 "settings": { 6 "number_of_shards": 1 7 }, 8 "mappings": { 9 "_source": { 10 "enabled": true 11 }, 12 "properties": { 13 "host_name": { 14 "type": "keyword" 15 }, 16 "created_at": { 17 "type": "date", 18 "format": "EEE MMM dd HH:mm:ss Z yyyy" 19 } 20 } 21 }, 22 "aliases": { 23 "mydata": { } 24 } 25 }, 26 "priority": 500, 27 "composed_of": ["component_template1", "runtime_component_template"], 28 "version": 3, 29 "_meta": { 30 "description": "my custom" 31 } 32}
- 对已有的索引创建别名
1POST _aliases 2{ 3 "actions": [ 4 { 5 "add": { 6 "index": "logs-nginx.access-prod", 7 "alias": "logs" 8 } 9 } 10 ] 11}
删除别名
1POST _aliases 2{ 3 "actions": [ 4 { 5 "remove": { 6 "index": "logs-nginx.access-prod", 7 "alias": "logs" 8 } 9 } 10 ] 11}
真题演练1
1# Define an index alias for 'accounts-row' called 'accounts-male': Apply a filter to only show the male account owners 2# 为'accounts-row'定义一个索引别名,称为'accounts-male':应用一个过滤器,只显示男性账户所有者 3 4POST _aliases 5{ 6 "actions": [ 7 { 8 "add": { 9 "index": "accounts-row", 10 "alias": "accounts-male", 11 "filter": { 12 "bool": { 13 "filter": [ 14 { 15 "term": { 16 "gender.keyword": "male" 17 } 18 } 19 ] 20 } 21 } 22 } 23 } 24 ] 25}
十三.Search-template
官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/search-template.html
功能特点
模板接受在运行时指定参数。搜索模板存储在服务器端,可以在不更改客户端代码的情况下进行修改。
初识search-template
1# 创建检索模板 2PUT _scripts/my-search-template 3{ 4 "script": { 5 "lang": "mustache", 6 "source": { 7 "query": { 8 "match": { 9 "{{query_key}}": "{{query_value}}" 10 } 11 }, 12 "from": "{{from}}", 13 "size": "{{size}}" 14 } 15 } 16} 17 18# 使用检索模板查询 19GET my-index/_search/template 20{ 21 "id": "my-search-template", 22 "params": { 23 "query_key": "your filed", 24 "query_value": "your filed value", 25 "from": 0, 26 "size": 10 27 } 28}
索引模板的操作
创建索引模板
1PUT _scripts/my-search-template 2{ 3 "script": { 4 "lang": "mustache", 5 "source": { 6 "query": { 7 "match": { 8 "message": "{{query_string}}" 9 } 10 }, 11 "from": "{{from}}", 12 "size": "{{size}}" 13 }, 14 "params": { 15 "query_string": "My query string" 16 } 17 } 18}
验证索引模板
1POST _render/template 2{ 3 "id": "my-search-template", 4 "params": { 5 "query_string": "hello world", 6 "from": 20, 7 "size": 10 8 } 9}
执行检索模板
1GET my-index/_search/template 2{ 3 "id": "my-search-template", 4 "params": { 5 "query_string": "hello world", 6 "from": 0, 7 "size": 10 8 } 9}
获取全部检索模板
GET _cluster/state/metadata?pretty&filter_path=metadata.stored_scripts
删除检索模板
DELETE _scripts/my-search-templateath=metadata.stored_scripts
十四.Search-dsl 简单检索
官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/query-dsl.html
检索选型
检索分类
自定义评分
如何自定义评分
1.index Boost索引层面修改相关性
1// 一批数据里,有不同的标签,数据结构一致,不同的标签存储到不同的索引(A、B、C),最后要严格按照标签来分类展示的话,用什么查询比较好? 2// 要求:先展示A类,然后B类,然后C类 3 4# 测试数据如下 5put /index_a_123/_doc/1 6{ 7 "title":"this is index_a..." 8} 9put /index_b_123/_doc/1 10{ 11 "title":"this is index_b..." 12} 13put /index_c_123/_doc/1 14{ 15 "title":"this is index_c..." 16} 17# 普通不指定的查询方式,该查询方式下,返回的三条结果数据评分是相同的 18POST index_*_123/_search 19{ 20 "query": { 21 "bool": { 22 "must": [ 23 { 24 "match": { 25 "title": "this" 26 } 27 } 28 ] 29 } 30 } 31} 32 33官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/search-search.html 34indices_boost 35# 也就是索引层面提升权重 36POST index_*_123/_search 37{ 38 "indices_boost": [ 39 { 40 "index_a_123": 10 41 }, 42 { 43 "index_b_123": 5 44 }, 45 { 46 "index_c_123": 1 47 } 48 ], 49 "query": { 50 "bool": { 51 "must": [ 52 { 53 "match": { 54 "title": "this" 55 } 56 } 57 ] 58 } 59 } 60}
2.boosting 修改文档相关性
1某索引index_a有多个字段, 要求实现如下的查询: 21)针对字段title,满足'ssas'或者'sasa’。 32)针对字段tags(数组字段),如果tags字段包含'pingpang', 4则提升评分。 5要求:写出实现的DSL? 6 7# 测试数据如下 8put index_a/_bulk 9{"index":{"_id":1}} 10{"title":"ssas","tags":"basketball"} 11{"index":{"_id":2}} 12{"title":"sasa","tags":"pingpang; football"} 13 14# 解法1 15POST index_a/_search 16{ 17 "query": { 18 "bool": { 19 "must": [ 20 { 21 "bool": { 22 "should": [ 23 { 24 "match": { 25 "title": "ssas" 26 } 27 }, 28 { 29 "match": { 30 "title": "sasa" 31 } 32 } 33 ] 34 } 35 } 36 ], 37 "should": [ 38 { 39 "match": { 40 "tags": { 41 "query": "pingpang", 42 "boost": 1 43 } 44 45 } 46 } 47 ] 48 } 49 } 50} 51# 解法2 52// https://www.elastic.co/guide/en/elasticsearch/reference/8.1/query-dsl-function-score-query.html 53POST index_a/_search 54{ 55 "query": { 56 "bool": { 57 "should": [ 58 { 59 "function_score": { 60 "query": { 61 "match": { 62 "tags": { 63 "query": "pingpang" 64 } 65 } 66 }, 67 "boost": 1 68 } 69 } 70 ], 71 "must": [ 72 { 73 "bool": { 74 "should": [ 75 { 76 "match": { 77 "title": "ssas" 78 } 79 }, 80 { 81 "match": { 82 "title": "sasa" 83 } 84 } 85 ] 86 } 87 } 88 ] 89 } 90 } 91}
3.negative_boost降低相关性
1对于某些结果不满意,但又不想通过 must_not 排除掉,可以考虑可以考虑boosting query的negative_boost。 2即:降低评分 3negative_boost 4(Required, float) Floating point number between 0 and 1.0 used to decrease the relevance scores of documents matching the negative query. 5官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/query-dsl-boosting-query.html 6 7POST index_a/_search 8{ 9 "query": { 10 "boosting": { 11 "positive": { 12 "term": { 13 "tags": "football" 14 } 15 }, 16 "negative": { 17 "term": { 18 "tags": "pingpang" 19 } 20 }, 21 "negative_boost": 0.5 22 } 23 } 24}
4.function_score 自定义评分
1如何同时根据 销量和浏览人数进行相关度提升? 2问题描述:针对商品,例如有想要有一个提升相关度的计算,同时针对销量和浏览人数? 3例如oldScore*(销量+浏览人数) 4************************** 5商品 销量 浏览人数 6A 10 10 7B 20 20 8C 30 30 9************************** 10# 示例数据如下 11put goods_index/_bulk 12{"index":{"_id":1}} 13{"name":"A","sales_count":10,"view_count":10} 14{"index":{"_id":2}} 15{"name":"B","sales_count":20,"view_count":20} 16{"index":{"_id":3}} 17{"name":"C","sales_count":30,"view_count":30} 18 19官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/query-dsl-function-score-query.html 20知识点:script_score 21 22POST goods_index/_search 23{ 24 "query": { 25 "function_score": { 26 "query": { 27 "match_all": {} 28 }, 29 "script_score": { 30 "script": { 31 "source": "_score * (doc['sales_count'].value+doc['view_count'].value)" 32 } 33 } 34 } 35 } 36}
十五.Search-del Bool复杂检索
官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/query-dsl-bool-query.html
基本语法
真题演练
1写一个查询,要求某个关键字再文档的四个字段中至少包含两个以上 2功能点:bool 查询,should / minimum_should_match 3 1.检索的bool查询 4 2.细节点 minimum_should_match 5注意:minimum_should_match 当有其他子句的时候,默认值为0,当没有其他子句的时候默认值为1 6 7POST test_index/_search 8{ 9 "query": { 10 "bool": { 11 "should": [ 12 { 13 "match": { 14 "filed1": "kr" 15 } 16 }, 17 { 18 "match": { 19 "filed2": "kr" 20 } 21 }, 22 { 23 "match": { 24 "filed3": "kr" 25 } 26 }, 27 { 28 "match": { 29 "filed4": "kr" 30 } 31 } 32 ], 33 "minimum_should_match": 2 34 } 35 } 36}
十六.Search-Aggregations
官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/search-aggregations.html
聚合分类
分桶聚合(bucket)
terms
1官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/search-aggregations-bucket-terms-aggregation.html 2# 按照作者统计文档数 3POST bilili_elasticsearch/_search 4{ 5 "size": 0, 6 "aggs": { 7 "agg_user": { 8 "terms": { 9 "field": "user", 10 "size": 1 11 } 12 } 13 } 14}
date_histogram
1官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/search-aggregations-bucket-datehistogram-aggregation.html 2# 按照up_time 按月进行统计 3POST bilili_elasticsearch/_search 4{ 5 "size": 0, 6 "aggs": { 7 "agg_up_time": { 8 "date_histogram": { 9 "field": "up_time", 10 "calendar_interval": "month" 11 } 12 } 13 } 14}
指标聚合 (metrics)
Max
1官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/search-aggregations-metrics-max-aggregation.html 2# 获取up_time最大的 3POST bilili_elasticsearch/_search 4{ 5 "size": 0, 6 "aggs": { 7 "agg_max_up_time": { 8 "max": { 9 "field": "up_time" 10 } 11 } 12 } 13}
Top_hits
1官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/search-aggregations-metrics-top-hits-aggregation.html 2# 根据user聚合只取一个聚合结果,并且获取命中数据的详情前3条,并按照指定字段排序 3POST bilili_elasticsearch/_search 4{ 5 "size": 0, 6 "aggs": { 7 "terms_agg_user": { 8 "terms": { 9 "field": "user", 10 "size": 1 11 }, 12 "aggs": { 13 "top_user_hits": { 14 "top_hits": { 15 "_source": { 16 "includes": [ 17 "video_time", 18 "title", 19 "see", 20 "user", 21 "up_time" 22 ] 23 }, 24 "sort": [ 25 { 26 "see":{ 27 "order": "desc" 28 } 29 } 30 ], 31 "size": 3 32 } 33 } 34 } 35 } 36 } 37} 38 39// 返回结果如下 40{ 41 "took" : 91, 42 "timed_out" : false, 43 "_shards" : { 44 "total" : 1, 45 "successful" : 1, 46 "skipped" : 0, 47 "failed" : 0 48 }, 49 "hits" : { 50 "total" : { 51 "value" : 1000, 52 "relation" : "eq" 53 }, 54 "max_score" : null, 55 "hits" : [ ] 56 }, 57 "aggregations" : { 58 "terms_agg_user" : { 59 "doc_count_error_upper_bound" : 0, 60 "sum_other_doc_count" : 975, 61 "buckets" : [ 62 { 63 "key" : "Elastic搜索", 64 "doc_count" : 25, 65 "top_user_hits" : { 66 "hits" : { 67 "total" : { 68 "value" : 25, 69 "relation" : "eq" 70 }, 71 "max_score" : null, 72 "hits" : [ 73 { 74 "_index" : "bilili_elasticsearch", 75 "_id" : "5ccCVoQBUyqsIDX6wIcm", 76 "_score" : null, 77 "_source" : { 78 "video_time" : "03:45", 79 "see" : "92", 80 "up_time" : "2021-03-19", 81 "title" : "Elastic 社区大会2021: 用加 Gatling 进行Elasticsearch的负载测试,寓教于乐。", 82 "user" : "Elastic搜索" 83 }, 84 "sort" : [ 85 "92" 86 ] 87 }, 88 { 89 "_index" : "bilili_elasticsearch", 90 "_id" : "8scCVoQBUyqsIDX6wIgn", 91 "_score" : null, 92 "_source" : { 93 "video_time" : "10:18", 94 "see" : "79", 95 "up_time" : "2020-10-20", 96 "title" : "为Elasticsearch启动htpps访问", 97 "user" : "Elastic搜索" 98 }, 99 "sort" : [ 100 "79" 101 ] 102 }, 103 { 104 "_index" : "bilili_elasticsearch", 105 "_id" : "7scCVoQBUyqsIDX6wIcm", 106 "_score" : null, 107 "_source" : { 108 "video_time" : "04:41", 109 "see" : "71", 110 "up_time" : "2021-03-19", 111 "title" : "Elastic 社区大会2021: Elasticsearch作为一个地理空间的数据库", 112 "user" : "Elastic搜索" 113 }, 114 "sort" : [ 115 "71" 116 ] 117 } 118 ] 119 } 120 } 121 } 122 ] 123 } 124 } 125}
子聚合 (Pipeline)
Pipeline:基于聚合的聚合 官网文档地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/search-aggregations-pipeline.html
bucket_selector
1# 根据order_date按月分组,并且求销售总额大于1000 2POST kibana_sample_data_ecommerce/_search 3{ 4 "size": 0, 5 "aggs": { 6 "date_his_aggs": { 7 "date_histogram": { 8 "field": "order_date", 9 "calendar_interval": "month" 10 }, 11 "aggs": { 12 "sum_aggs": { 13 "sum": { 14 "field": "total_unique_products" 15 } 16 }, 17 "sales_bucket_filter": { 18 "bucket_selector": { 19 "buckets_path": { 20 "totalSales": "sum_aggs" 21 }, 22 "script": "params.totalSales > 1000" 23 } 24 } 25 } 26 } 27 } 28}
真题演练
1earthquakes索引中包含了过去30个月的地震信息,请通过一句查询,获取以下信息 2l 过去30个月,每个月的平均 mag 3l 过去30个月里,平均mag最高的一个月及其平均mag 4l 搜索不能返回任何文档 5 6max_bucket 官网地址:https://www.elastic.co/guide/en/elasticsearch/reference/8.1/search-aggregations-pipeline-max-bucket-aggregation.html 7 8POST earthquakes/_search 9{ 10 "size": 0, 11 "query": { 12 "range": { 13 "time": { 14 "gte": "now-30M/d", 15 "lte": "now" 16 } 17 } 18 }, 19 "aggs": { 20 "agg_time_his": { 21 "date_histogram": { 22 "field": "time", 23 "calendar_interval": "month" 24 }, 25 "aggs": { 26 "avg_aggs": { 27 "avg": { 28 "field": "mag" 29 } 30 } 31 } 32 }, 33 "max_mag_sales": { 34 "max_bucket": { 35 "buckets_path": "agg_time_his>avg_aggs" 36 } 37 } 38 } 39}
