ElasticSearch-相关性查询

  • 相关性算分
    • TF-IDF
    • BM25
    • Boosting
  • 布尔查询 bool Query
  • Boosting Query
  • 单字符串多字段查询

相关性算分

  • 如何衡量相关性

    • Precision(查准率)―尽可能返回较少的无关文档
    • Recall(查全率)–尽量返回较多的相关文档
    • Ranking -是否能够按照相关度进行排序
  • 相关性(Relevance):搜索的相关性算分,描述了一个文档和查询语句匹配的程度

    • ES 会对每个匹配查询条件的结果进行算分_score
    • 打分的本质是排序,需要把最符合用户需求的文档排在前面
    • ES5之前,默认的相关性算分采用TF-IDF,现在采用BM25
  • TF-IDF(term frequency–inverse document frequency)是一种用于信息检索与数据挖掘的常用加权技术

    • TF-IDF被公认为是信息检索领域最重要的发明
    • 现代搜索引擎,对TF-IDF进行了大量细微的优化
  • Lucene中的TF-IDF评分公式

    • TF-IDF

    • TF是词频 (Term Frequency):检索词在文档中出现的频率越高,相关性也越高

    • IDF是逆向文本频率 (Inverse Document Frequency):每个检索词在索引中出现的频率越高,相关性越低

    • 字段长度归一值 (field-length norm):字段越短,字段的权重越高

      • 检索词出现在一个内容短的 title 要比同样的词出现在一个内容长的 content 字段权重更大
  • BM25 就是对 TF-IDF 算法的改进

    • 对于 TF-IDF 算法,TF(t) 部分的值越大,整个公式返回的值就会越大
    • BM25 就针对这点进行来优化,随着TF(t) 的逐步加大,该算法的返回值会趋于一个数值
    • BM25
  • BM25的公式

    • BM25
  • 通过Explain API查看TF-IDF

GET /test_score/_search
{"explain":true,"query":{"match":{"content":"elasticsearch"}}}
  • Boosting 是控制相关度的一种手段
    • 当 boost > 1 时,打分的权重相对性提升
    • 当 0 < boost <1 时,打分的权重相对性降低
    • 当 boost <0 时,贡献负分
  • 应用场景:希望包含了某项内容的结果不是不出现,而是排序靠后
# 返回匹配 positive 查询的文档并降低匹配 negative 查询的文档相似度分
GET /test_score/_search
{"query":{"boosting":{
  "positive":{"term":{"content":"elasticsearch"}},
  "negative":{"term":{"content":"like"}},
  "negative_boost":0.2}}}

布尔查询 bool Query

  • 一个 bool 查询,是一个或者多个查询子句的组合,总共包括4种子句,其中2种会影响算分,2种不影响算分
    • must: 相当于&& ,必须匹配,贡献算分
    • should: 相当于|| ,选择性匹配,贡献算分
    • must_not: 相当于! ,必须不能匹配,不贡献算分
    • filter: 必须匹配,不贡献算法
  • 在Elasticsearch中,有Query和 Filter两种不同的Context
    • Query Context: 相关性算分
    • Filter Context: 不需要算分 ,可以利用Cache,获得更好的性能
  • 相关性并不只是全文本检索的专利,也适用于 yes | no 的子句,匹配的子句越多,相关性评分越高
    • 如果多条查询子句被合并为一条复合查询语句
    • 比如 bool 查询,则每个查询子句计算得出的评分会被合并到总的相关性评分中
  • bool 查询语法
    • 子查询可以任意顺序出现
    • 可以嵌套多个查询
    • 如果你的bool查询中,没有must条件,should中必须至少满足一条查询
GET /es_db/_search
{"query":{"bool":{
  "must":{"match":{"remark":"java developer"}},
  "filter":{"term":{"sex":"1"}},
  "must_not":{"range":{"age":{"gte":30}}},
  "should":[
    {"term":{"address.keyword":{"value":"广州天河公园"}}},
    {"term":{"address.keyword":{"value":"广州白云山公园"}}}],
  "minimum_should_match":1}}}
  • 解决结构化查询“包含而不是相等”的问题
    • 增加count字段,使用bool查询解决
POST /employee/_bulk
{"index":{"_id":1}}
{"name":"小明","interest":["跑步","篮球"],"interest_count":2}
{"index":{"_id":2}}
{"name":"小红","interest":["跑步"],"interest_count":1}

"query":{"bool":{"must":[
   {"term":{"interest.keyword":{"value":"跑步"}}},
   {"term":{"interest_count":{"value":1}}}]}}
  • 利用bool嵌套实现should not逻辑
"query":{"bool":{
 "must":{"match":{"remark":"java developer"}},
 "should":[{"bool":{"must_not":[{"term":{"sex":1}}]}}],
 "minimum_should_match":1}}

Boosting Query

  • 控制字段的 Boosting:Boosting是控制相关的一种手段。可以通过指定字段的boost值影响查询结果
    • 当boost>1时,打分的权重相对性提升
    • 当0<boost<1时,打分的权重相对性降低
    • 当boost<0时,贡献负分
GET /blogs/_search 
{"query":{"bool":{"should":[
 {"match":{"title":{"query":"apple,ipad","boost":1}}},
 {"match":{"content":{"query":"apple,ipad","boost":4}}}]}}}
  • 利用must not排除
GET /news/_search
{"query":{"bool":{
 "must":{"match":{"content":"apple"}},
 "must_not":{"match":{"content":"pie"}}}}}
  • 利用negative_boost降低相关性
    • negative_boost 对 negative部分query生效
    • 计算评分时,boosting部分评分不修改,negative部分query乘以negative_boost值
    • negative_boost取值: 0-1.0
  • 对某些返回结果不满意,但又不想排除掉可以考虑boosting query的negative_boost
GET /news/_search 
{"query":{"boosting":{
  "positive":{"match":{"content":"apple"}},
  "negative":{"match":{"content":"pie"}},
  "negative_boost":0.2}}}

单字符串多字段查询

  • 三种场景
    • 最佳字段 (Best Fields):当字段之间相互竞争,又相互关联。例如,对于博客的 title和 body这样的字段,评分来自最匹配字段
    • 多数字段 (Most Fields):处理英文内容时的一种常见的手段是,在主字段( English Analyzer),抽取词干,加入同义词,以匹配更多的文档。相同的文本,加入子字段(Standard Analyzer),以提供更加精确的匹配。其他字段作为匹配文档提高相关度的信号,匹配字段越多则越好
    • 混合字段 (Cross Field):对于某些实体,例如人名,地址,图书信息。需要在多个字段中确定信息,单个字段只能作为整体的一部分。希望在任何这些列出的字段中找到尽可能多的词
  • bool should的算法过程
    • 查询should语句中的两个查询
    • 加两个查询的评分
    • 乘以匹配语句的总数
    • 除以所有语句的总数
  • 最佳字段查询 Dis Max Query
    • 将任何与任一查询匹配的文档作为结果返回,采用字段上最匹配的评分最终评分返回
    • 竞争关系的字段,不应该讲分数简单叠加,而是应该找到单个最佳匹配的字段的评分
POST blogs/_search
{"query":{"dis_max":{"queries":[
  {"match":{"title":"Brown fox"}}, 
  {"match":{"body":"Brown fox"}}]}}}
  • 可以通过tie_breaker参数调整
    • Tier Breaker是一个介于0-1之间的浮点数
    • 0代表使用最佳匹配;1代表所有语句同等重要
  • 流程
    • 获得最佳匹配语句的评分_score
    • 将其他匹配语句的评分与tie_breaker相乘
    • 对以上评分求和并规范化
POST /blogs/_search
{"query":{"dis_max":{"queries":[
  {"match":{"title":"Quick pets"}},
  {"match":{"body":"Quick pets"}}],"tie_breaker":0.2}}}
  • Multi Match Query 最佳字段 (Best Fields) 搜索
  • Best Fields 是默认类型,可以不用指定
POST /blogs/_search
{"query":{"multi_match":{
  "type":"best_fields",
  "query":"Quick pets",
  "fields":["title","body"],"tie_breaker":0.2}}}
  • 使用多数字段(Most Fields)搜索
    • 每个字段对于最终评分的贡献可以通过自定义值boost 来控制
# 增加 title 的权重
GET /titles/_search 
{"query":{"multi_match":{
  "query":"barking dogs", 
  "type":"most_fields",
  "fields":["title^10","title.std"]}}}
  • 跨字段(Cross Field)搜索
    • 与copy_to相比,其中一个优势就是它可以在搜索时为单个字段提升权重
GET /address/_search
{"query":{"multi_match":{
 "query":"湖南常德",
 "type":"cross_fields",
 "operator":"and",
 "fields":["province","city"]}}}
  • 可以用copy_to解决,但是需要额外的存储空间
PUT /address
{"mappings":{"properties":{
  "province":{"type":"keyword","copy_to":"full_address"},
  "city":{"type":"text","copy_to":"full_address"}}},
 "settings":{"index":{"analysis.analyzer.default.type":"ik_max_word"}}}
GET /address/_search 
{"query":{"match":{"full_address":{"query":"湖南常德","operator":"and"}}}}
  • 14
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值