背景

  • 首先看个例子,有两个 doc,一条是 albino elephant,一条是 elephant elephant
PUT test_elephant/_doc/1
{"title_text":"elephant","body_text":"elephant"
}PUT test_elephant/_doc/2
{"title_text":"albino","body_text":"elephant"
}
复制代码
  • 用户想查 albino elephant , 于是我们就这样写了一条 query 语句,期望可以召回 doc 2
GET test_elephant/_search
{"query": {"query_string": {"fields": ["title_text","body_text"],"query": "albino elephant"}}
}
复制代码
  • 但是实际结果却和我们预期的不一样,两个 doc 评分一模一样,那么这是为什么呢?
  • 首先 expalin 一下可以看到
doc1 max(title_text:elephant,body_text:elephant)
doc2 max(title_text:albino,body_text:elephant)
复制代码
  • 而因为 elephant 和 albino 在 title 字段中都出现了一次,所以分数一样,都是0.69
  • 那么为什么呢?
    • 我们通过 _validate/query?rewrite=true 可以看到这个 query 被翻译成

以字段为中心(field-centric) VS 以词为中心(term-centric)

  • 上述的那个例子就是以字段为中心中经典的『白化象问题』,那么到底什么是以字段为中心,什么是以词为中心呢?下图
  • 左边是为 以字段为中心,可见,字段为中心为query 在各个字段分别算分,然后按一定 function 求最终结果,也就是其实最终的结果也是整个 query 在哪个字段中表现最好。

    • 这种适用于用户意图只会命中一个字段时适用
    • 优势:符合结构化语义,易于控制不同字段权重
    • 问题:
      • 白化象问题(albino elephant) — 有更多搜索词匹配的文档没有被排在靠前的位置
      • 信号冲突(signal discordance) — 多字段 idf 不一,排序难被用户理解。比如一个人经常做演员很少做导演,然后搜索的时候,导演字段的分数就会非常高,造成当导演的电影排序靠前,造成用户困扰
  • 右边为 以词为中心,以词为中心则是词在不同字段中的分数,通过一定 function 算出(图中为 max),然后再将各个词的分数以一定 function 结合作为总分。
    • 这种实际上就是用户并不关系匹配的是什么字段,不关心文档结构,关心的只是匹配到了哪些词。
    • 优势:更符合用户心智,用户往往难以了解数据的结构
    • 问题:不好控制不同字段权重,实现复杂

ES 中的多字段检索方式

查看真实检索语句

  • 利用 _validate/query?rewrite=true 可以看到真实传个 lucene 的语句,便可看出其真实逻辑。也可用explain=true可以看见部分中间过程,但是效果没有 rewrite 直观

常用多字段检索

  • 下面利用 validate 对 title(keyword 字段) , title_text(ik 分词器) 和 body_text(ik 分词器) 进行查询,查询内容为 ZSearch 通用搜索
  • MultiMatch
    • best_fields - 字段中心,字段间 max ,可用 tie_breaker 调整字段间关系

      • (title:ZSearch 通用搜索 | (title_text:zsearch title_text:通用 title_text:搜索) | (body_text:zsearch body_text:通用 body_text:搜索))
    • most_fields - 字段中心 字段间相加
      • title:ZSearch 通用搜索 (title_text:zsearch title_text:通用 title_text:搜索) (body_text:zsearch body_text:通用 body_text:搜索)
    • cross_fields - 词中心 词在不同字段间取 max,然后相加
      • (((title_text:zsearch | body_text:zsearch) (title_text:通用 | body_text:通用) (title_text:搜索 | body_text:搜索)) | title:ZSearch 通用搜索)
  • QueryString - 字段中心 同 best_fields
    • (title:ZSearch 通用搜索 | (title_text:zsearch title_text:通用 title_text:搜索) | (body_text:zsearch body_text:通用 body_text:搜索))
  • SimpleQueryString 词中心,但词在不同字段间为相加
    • (title_text:zsearch title:ZSearch body_text:zsearch) ((title_text:通用 title_text:搜索) title:通用搜索 (body_text:通用 body_text:搜索))
  • 需要注意的是词为中心的查询方式均会受分词器影响,其中 simple query string 和 cross 采取了两种不同的实现方式
    • simple query string 为简单按空格分割,然后直接丢入各字段进行查询,因此是分词前的以词为中心,而不是最终的,及时设置了 analyzer 也依旧如此
    • cross_field 则是采取首先按分词器进行分组,同样的分词器内以词为中心在多字段进行查询,不同的分词器直接按字段取 max
  • 另外,多字段查询的minimum_should_match也只与一级子句(最外边的括号内的)有关,内部再分词均不会作用

扩展阅读

如何实现字段中心和词中心相结合

  1. 相似字段,按用户意图将字段分组,比如 姓 和 名 两个字段合并 姓名 一个字段,将不同意图的搜索完全分开
  2. 以词为中心进行兜底,以字段为中心进行加成,如下

多字段算分在信息检索领域的尝试

  • 传统BM25在计算相关性时把文档当做总体来考虑,但随着搜索技术的发展。文档慢慢的被结构化数据所取代。每个文档都会被切分成多个独立的域,尤其是垂直化的搜索。比如网页有可能被切分成标题,内容,主题词等域,这些域对文章主题的贡献不能同等对待,所以权重就要有所偏重。
  • BM25没有考虑这点。所以BM25F在此基础上做了一些改进,就是不再单单的将单词作为个体考虑,并且将文档也依照field划分为个体考虑,所以BM25F是每一个单词在各个field中分值的加权求和。

参考资料

  • Doug Turnbull,John Berryman 《相关性搜索-利用Solr与Elasticsearch创建智能应用》P120-192
  • Elasticsearch 权威指南
  • Elasticsearch 文档

转载于:https://juejin.im/post/5cf4de4de51d454f73356cfb

【相关性搜索】 多字段搜索的两种方式——词中心与字段中心相关推荐

  1. 模糊匹配 读音_onenote搜索机制详解②:两种搜索模式,模糊与精确匹配

    先从纯文本搜索讲起,这是最基本也是最重要的. 从这篇开始,以及接下来连续几篇文章,都会介绍搜索的基础功能.注意,这几篇文章中谈论的都是基本的.正常的搜索功能,暂时不考虑Bug等因素. 在很多软件(例如 ...

  2. 模块的四种形式 模块的调用 循环导入问题 模块的搜索路径 py文件的两种用途 编译python文件 包...

    目录 模块的四种形式 什么是模块 模块的四种形式 自定义模块 第三方模块 内置模块 包 使用模块的好处 模块的调用 循环导入问题 模块的搜索路径 py文件的两种用途 编译python文件 包 什么是包 ...

  3. oracle 创建字段自增长——两种实现方式汇总(转)

    mysql等其他数据库中有随着记录的插入而表ID自动增长的功能,而oracle却没有这样的功能,我们有以下两种方式可以解决字段自增长的功能. 因为两种方式都需要通过创建序列来实现,这里先给出序列的创建 ...

  4. python使用smtplib群发工资条的两种方式(及群发只成功一条的问题)

    smtplib模块是python自带的发邮件模块,同时还需要的是email模块,不过安装时只需要安装smtplib即可 安装方式两种: pip install smtplib pycharm中,Fil ...

  5. 服务端验证Google Pay订单的两种方式

    Google Pay主要支付流程: 1.手机端向服务端发起支付,生成预订单,给手机端返回生成的订单号 2.手机端向Google发起支付(传入本地服务器生成的订单号) 3.Google服务器将支付结果返 ...

  6. DLL中导出函数的声明有两种方式

    本文引用自:VC编程时DLL中导出函数的声明有两种方式 一种方式是:在函数声明中加上__declspec(dllexport): 另外一种方式是:采用模块定义(.def)文件声明,(.def)文件为链 ...

  7. Java技术分享:升级所安装Java版本的两种方式

    在进行Java开发的时候我们可能会需要升级所安装的Java版本,那么你知道应该如何安装吗?小千今天就来给大家介绍两种方式. 一.卸载掉原本安装的Java,下载最新安装包安装即可. 这个步骤就不介绍了, ...

  8. Linux下编译、链接、加载运行C++ OpenCV的两种方式及常见问题的解决

    Linux下编译.链接.加载运行C++ OpenCV的两种方式及常见问题的解决 在Linux下安装完OpenCV C++之后(还没有安装的读者请参考Ubuntu 18.04 安装OpenCV C++) ...

  9. 从Maven中央仓库网站下载jar包的两种方式,将会伴随java后端开发者的整个职业生涯

    这个肥肠重要的网站就是:https://mvnrepository.com/ 下面我会以mysql-connector-java-8.0.26.jar为例,教会你使用两种方式下载使用jar包资源 首先 ...

最新文章

  1. Android之解析XML
  2. [总结篇1]openstack neutron 中是如何做到二层隔离的
  3. 堆栈 cookie 检测代码检测到基于堆栈的缓冲区溢出_WhatsApp缓冲区漏洞曝光 攻击者可通过MP4文件执行远程代码...
  4. WPF模板(二)应用
  5. for遍历和foreach遍历的一个细小差别
  6. 【OpenPose-Windows】error1 OpenPose项目加载失败
  7. python数据结构_(列表)大O性能_学习笔记(2)
  8. php中接口验证失败,php短信验证失败的原因
  9. 将状态机模式实现为流处理器
  10. 前端学习(1884)vue之电商管理系统电商系统之实现侧边栏的折叠和展开
  11. houghcircle函数_Hough Circle 变换
  12. 罗永浩与银联合作直播,但因过程太流畅被网友调侃是录播
  13. T2 Funcin T1,out T2(T1 arg)
  14. html5 canvas 获取当前坐标,html5 canvas fillRect坐标和大小的问题解决方法
  15. php上传压缩文件,8行代码实现PHP上传RAR文件并解压
  16. 克拉默法则(Cramer's Rule)的证明
  17. 二进制转8421bcd码_绝对值编码器当中的格雷码
  18. 我和你,不是影子一样的朋友,只在光明的日子里相随
  19. Android系统屏幕亮度调节Brightness
  20. MP-BGP报文详解

热门文章

  1. centos oracle 服务自动启动,CentOS下配置Oracle 11gR2为系统服务自动启动
  2. python mac地址转换_Python MAC地址 获取,过滤,转换 Python MYSQL 数据获取,比较
  3. java同时输入输出buf_java输入输出流小细节
  4. linux上部署mysql服务_在Linux环境下部署MySql服务
  5. sketch如何做设计稿交互_做交互设计不可不知的十大原则
  6. 牛客网 华为机试题 数据重复的筛选问题记录
  7. linux php ftp扩展,Linux中如何安装 PHP 扩展?(方法介绍)
  8. 安装mysql 10055_Can’t connect to MySQL server on ‘localhost’ (10055) | 学步园
  9. ii 组合总和_40. 组合总和 II
  10. matlab 将矩阵中的0置为Inf(邻接矩阵)