ES的开发手册
搜索分析
搜索中的常见问题
- 对检索类型了解不全、拿来就用
- 不能分辨不同检索类型的应用场景和可能的副作用
- 临时使用,没有关注使用的细节与注意事项
检索类型
精准匹配检索
- 是一种根据确切词条值查找文档的方法
- 查询的关键词须与文档的词条完全吻合,方可视为匹配
- 常用于结构化数据检索,如:ID、状态、标签等
- 不需要对待检索的文本进行分词处理,而是将整个文本视为一个完整的词条进行匹配
- 使用精准匹配须避免text类型的字段,精准匹配主要针对的是非text类型
- text类型的字段会进行分词处理成多个词条,并使用倒排索引进行存储
- 而精准匹配不需要对待检索的文本进行分词处理,而是将整个文本视为一个完整的词条进行匹配,因此同样的内容会出现不匹配的情况
全文检索
- 是一种对文档进行深入分析和处理的方法,以便找到与查询关键词相关的文档
- 须考虑词汇的语义关联,包括词干、同义词等,并通常对文档进行评分,以衡量其与查询关键词的相关程度
- 常用于非结构化文本数据,如:文章和评论等
- 需要对文本进行分词处理,在分词后,对每个词条将进行单独检索
- 使用倒排索引进行搜索
组合检索
- 是一种将多个查询条件组合在一起的检索方式
- 允许用户根据多个因素和逻辑操作符(与、或、非)来定位相关文档,从而实现更为复杂且精准的查询
- 主要使用bool检索来实现多条件查询,可以针对不同字段进行精准匹配和全文检索
搜索,Query DSL
全文检索
- match
- 分词检索
- 适用于召回率和结果精度要求较低的场景,在追求高精准度的情况下应慎重选用
- 通过将待检索的语句根据设定的分词器分解为独立的词项单元,然后对多个词项单元分别进行term检索,最后对各term检索词项进行bool组合
- 示例,“match”:{“title”:“测试文本”}
- match_phrase
- 短语检索
- 适用于注重精准度的召回场景
- 检索时要求查询的词条顺序和文档中的词条顺序保持一致,以确保更高的精准度
- 示例,“match_phrase”:{“title”:“测试文本”}
- match_phrase_prefix
- 短语前缀检索
- 查询词语需要按顺序匹配文档中的内容,同时允许最后一个词语只匹配其前缀
- 常用于用户输入时提供搜索建议或自动补全等
- 示例,“match_phrase_prefix”:{“title”:“测试文本”}
- mulit_match
- 多字段检索
- 适用于在多个字段上执行match检索的场景
- 示例,“multi_match”:{“query”:“测试文本”,“fields”:[“field_name_1”, “field_name_2”]}
- query_string
- 允许用户使用Lucene查询语法直接编写复杂地查询表达式
- 这种查询方式具有高度地灵活性和精准度,支持多字段查询、通配符查询、模糊查询、范围查询等多种检索类型
- 应用场景包括高级搜索、数据分析和 报表等,适合处理满足特定需求、要求支持于或非表达式地复杂查询任务
- 通常用于专业领域或需要高级查询功能地应用中
- 示例,“query_string”:{“default_field”:“title”,“query”:“测试内容 AND 测试消息”}
- simple_query_string
- 类似于query_string查询地灵活性,且对用户输入地语法错误更加宽容
- 支持多字段、通配符、模糊等基本检索类型,同时简化了Lucene查询语法
- 应用场景包括基本搜索、快速筛选
- 示例,“query_string”:{“query”:“测试内容 AND 测试消息 AND”,“fields”:[“title”]}
- match boolean prefix
- intervals
- combined fields
精准匹配
- term
- 用于单字段精准匹配的场景
- terms
- 用于多字段精准匹配的场景,允许指定多个词条来进行精准匹配
- 适合从文档中查找包含多个特定值的字段
- range
- 范围检索
- 适合对数字、日期或其它可排序数据类型的字段进行范围筛选
- 支持的操作符有大于(gt)、大于等于(gte)、小于(lt)、小于等于(lte)等
- exists
- 是否存在检索
- 常用于数据完整性检查、查询特定属性的文档以及对可选字段进行筛选。如:检查文档中是否存在某个字段、或者该字段是否包含非空值
- wildcard
- 通配符检索,类似于关系型数据库中的like检索
- 支持的通配符
- 星号(*),表示零或多个字符,可用于匹配任意长度的字符串
- 问号(?),表示一个字符,用于匹配任意单个字符
- 适用于对部分已知内容的文本字段进行模糊检索
- 通配符查询可能导致较高的计算负担,实际中应谨慎使用
- prefix
- 前缀匹配检索,允许根据指定前缀检索文档的字段值
- 适用于检索以特定字符或字符串作为开头的文档,如:产品型号、姓名或地名等
- terms set
- 主要用于解决单字段多个值(数组)中的文档匹配问题
- 常用于处理具有多个属性、分类或标签的复杂数据的检索
- fuzzy
- 支持编辑距离的模糊查询
- 它能在用户输入内容存在拼写错误或者上下文不一致时,通过编辑距离算法来调整输入词,并返回与搜索词相似的文档
- 编辑距离是指从一个单词转换到另一个单词需要的编辑单字符的次数
- 编辑距离支持的转换形式有替换、交换、插入、删除
- IDs
- 基于给定的ID组快速召回相关数据,从而实现高效的文档检索
- regexp
- 正则匹配检索
- 建议谨慎使用,该方式会造成比较大的内存消耗
多表关联检索
- Nested
- 嵌套类型检索
- Has child
- 子文档查询父文档
- Has parent
- 父文档查询子文档
- Parent ID
组合检索
- bool
- 组合检索,适用于处理复杂地检索场景
- 子查询类型
- must,查询结果必须满足指定条件
- must_not,查询结果必须不满足指定条件,召回地数据评分为0
- filter,过滤条件,使用filter可以借助缓存机制提高查询性能,召回地数据评分为0
- should,查询结果可以满足的部分条件,具体满足条件的最小数量由minimum_should_match参数控制
- boosting,提升评分
- constant score
- disjunction max
- function_score,自定义评分
经纬度检索
形状类型检索
跨度检索
特定检索
- script,脚本检索
- script score,脚本评分检索
- more like this,相似度检索
- percolate
- rank fature
- wrapper
- pinned query
- distance feature
其它
高亮
-
简述
- 通过指定高亮语法格式,将待检索的字段在检索返回时形成高亮或者突出显示的功能
-
配置
- highlight
- fragment_size,每个高亮片段的字符数。默认100
- number_of_fragments,高亮最大片段数。默认5;如果片段数设置为0,则不返回任何高亮片段,而是将整个字段内容突出显示并返回
- fields,待高亮字段。支持精准匹配和模糊匹配,如:comment_title、comment_*
- pre_tags,指定高亮字段的前置html标签
- post_tags,指定高亮字段的后置html标签
-
示例
"highlight" : { "number_of_fragments": 3, "fragment_size":150, "fields": { "books.book_name": { "pre_tags": ["<em>"], "post_tags": ["</em>"] } } }
排序
-
简述
- ES支持在查询时自定义排序规则,即以自定义的方式对查询结果进行排序
- 排序可以基于文档评分、字段值、自定义脚本等实现
- 能排序的字段都具备正排索引,单text类型字段是不可以排序的(以倒排索引进行存储,如需要支持排序、聚合需要开启fielddata,fielddata是基于内存的正排索引,会耗费较多的系统资源,不建议开启该功能)
-
配置
- sort
- _score,按分数排序
- _doc,按索引顺序排序(通常用在scroll遍历上)
- order,排序方式,desc和asc
-
示例
"sort" : [ {"bookname": {"order":"desc"}}, {"_score": {"order":"asc"}} ]
搜索命令执行时开启性能分析
- 简述
- 该功能详细地列出了搜索时每一个步骤地耗时,可以帮助用户对DSL地性能进行分析,如:搜索请求响应较慢分析
- 命令
- “profile” : true
检索类型选型流程参考
从上往下进行匹配
是否需要自定义评分
是自定义评分检索
是否需要组合查询
是否需要精准匹配
是term精准匹配检索
是否需要全文检索
是match全文检索
场景分析
文档评分
简述
- ES通过评分算法,根据查询条件与索引文档的匹配程度来确定每个文档的相关度,即文档评分
- ES也允许用户自定义评分
搜索结果相关度
- 即搜索引擎获取的结果与用户期望的结果地相关度
- 而通常是通过检索时返回的文档评分,来衡量其相关度的
- 可以通过调整文档的评分来调整其相关度
文档评分算法
- TF-IDF
- OKapi BM25
- ES5之后默认使用该算法,其中BM是Best Match,25是指经过25次迭代之后得出的算法,由TF-IDF机制演变而来
自定义评分
分析
- 排序偏好,通过在搜索结果中给每个文档自定义评分,可以更好地满足搜索用户地排序偏好
- 特殊字段权重,通过给特定字段赋予更高地权重,可以让这些字段对搜索结果地影响更大
- 业务逻辑需求,根据业务需求,可以定义复杂地评分逻辑,使搜索结果更符合业务需求
- 自定义用户行为,可以使用户行为数据(如点击率)作为评分因素,以提高用户搜索体验
评分策略
-
Index Boost
-
在索引层面修改相关度,适用于索引级别调整评分
-
这种方式能在跨多个索引时,为每个索引配置不同的级别
-
示例
"indeces_boost": { "{index_name}": {分值} }
-
-
boosting
-
修改文档相关度,可在查询时修改文档的相关度
-
值得区间
- boosting小于1时,代表降低评分
- boosting大于1时,代表提升评分
-
示例
"title": { "query": "测试内容", "boost":3 }
-
-
negative_boost
-
降低相关度。如对某些返回结果不满意,但又不想将其排除(must_not),则可以考虑采用negative_boost得方式
-
示例
"boosting": { "negative": {}, "negative_boost": 0.1 }
-
-
function_score
-
自定义评分,通过用户自定义一个或多个查询语句及脚本,达到精细化控制评分得目的,以对搜索结果进行高度个性化的排序设置
-
适用于需进行复杂查询的自定义评分业务场景
-
示例
"function_score": { "script_score": { "script": { "source":"" } } }
-
-
rescore_query
-
查询后二次打分。指重新计算查询所返回的结果文档中指定文档的得分
-
适用于对查询语句的结果不满意,需要重新打分的场景
-
示例
"rescore": { "function_score": { "script_score": { "script": { "source":"" } } } }
-
检索模板
简述
- 检索模板(search template),是指预先定义好的查询语句,它可以用于复制或重复使用复杂的查询操作,而无需手动编写复杂的JSON查询语句
- 检索模板被定义并存储在服务器端,就可以发送一个特定的查询请求来使用这个模板进行检索
特性
- 便于重复使用复杂的查询语句
- 简化查询操作
- 提高查询语句的可读性
操作
- 定义检索模板
- PUT _scripts/{search_template_name}{“script”:{}}
- 使用检索模板
- POST {index_name}/_search/template{“id”:“{search_template_name}”,“params”:{}}
大数据集召回
from+size分页
简述
- ES支持对查询结果进行分页处理,语序用户逐步获取和浏览大量数据
- 分页搜索不会单独缓存(cache),缓存和分页没有关系
- 每次分页的请求都是一次重新搜索的过程,而不是从第一次搜索的结果中获取
配置
- from,表示结果集的起始位置,默认为0
- size,表示每页返回的文档数量,默认为10
示例
- “from”:0,“size”:5
分析
- 查询支持随机翻页,但不能无限翻页,限于max_result_window设置(默认10000),且存在深度翻页性能问题
- 适合小型数据集或者大数据集中返回Top N(N<=10000)结果集的业务场景
- 不推荐使用该方式进行深度分页
- 调大index.max_result_window默认值,可以扩大召回的数据区间
search_after查询
简述
- 该方式类似于数据库中的视图,使用事先构建的视图,进行查询,此视图有存在时间限制
- 该方式的翻页仅支持向后翻页,不支持随机翻页
- 该方式翻页单次返回数据量不能超过max_result_window,但多次翻页时,总返回的数据量可以超过该限制
使用
- 创建PIT视图
- 创建基础查询语句,主要是设置分页的条件
- 指定search_after属性进行翻页操作
scroll查询
简述
- scroll滚动遍历查询是非实时的,数据量较大时,响应时间可能会比较长
使用
- 指定检索语句的同时设置scroll上下文保留时间
- 向后翻页,继续获取数据,直到没有要返回的结果为止
分析
- 支持全量遍历,是检索大量文档的重要方法,但单次遍历的size值不能超过max_result_window的大小
- 响应非实时的,保留上下文需要足够的堆内存空间;需要通过更多的网络请求才能获取所有结果
- 当检索文档数量很大,甚至全量召回数据时,该查询是一个很好的选择
- 滚动API适合对大量文档进行数据处理,如:索引迁移、将数据导入其它技术栈
使用场景分析
- from+size,支持随机翻页,适用于10000条结果数据之内的分页显示场景
- search_after,支持向后翻页,适用于超过10000条结果的分页场景,即深度分页场景
- scroll,适用于遍历全量数据的场景
聚合
简述
- 聚合用于对搜索结果进行统计分析
- 聚合函数可以用于数据分析和数据挖掘,能帮助用户更好的理解数据、识别关键信息、洞察数据趋势
- 常用于用户行为分析(搜索历史、点击率分析)、电商分析(商品销售情况、客户的购买历史分析)、日志分析(异常、性能、链路分析)等
聚合类型
分桶聚合
- 简述
- 用于将数据分组
- 分类
- Terms,分桶聚合
- Range,范围聚合
- Histogram,直方图聚合
- Date histogram,日期聚合
- Date range,日期范围聚合
- Composite,组合聚合(Multi-level Aggregation)
- 该聚合是一种特殊类型的多桶聚合,它能以复合的形式融合并执行多种类型的桶聚合
- 组合聚合具有强大的分页处理能力,可以针对所有层级结构的桶执行精确的分页操作
- Filters,过滤聚合
指标聚合
- 简述
- 用于计算数据的指标
- 分类
- Avg,平均值聚合
- Sum,汇总聚合
- Max,最大值聚合
- Min,最小值聚合
- Stats,统计聚合
- Top hits,详情聚合
- Cardinality,去重聚合
- Value count,计数聚合
管道子聚合
- 简述
- 用于对数据进行复杂的分析,也称为嵌套多重聚合
- 分类
- parent子聚合
- Bucket selector,选择子聚合。对聚合的结果执行进一步的筛选和运算
- Bucket script,脚本子聚合。在聚合的结果上执行脚本运算,以生成新的聚合结果
- Bucket sort,排序子聚合。使用聚合结果的任意字段进行排序,并返回一个排序后的桶列表
- sibling子聚合
- Max bucket,最大值子聚合。获取外层聚合下度量的最大值的桶,并输出桶的值和键
- Min bucket,最小值聚合。获取外层聚合下度量的最小值的桶,并输出桶的值和键
- Sum bucket,求和子聚合。获取外层聚合求和结果
- Stats bucket,统计子聚合。获取外层聚合统计结果
- parent子聚合
拓展
多桶聚合,multi-terms聚合
- 多桶聚合是分桶聚合的拓展,多桶聚合可以按照多个关键字维度进行聚合,而分桶聚合只能对单个关键字进行聚合