背景
- 首先看个例子,有两个 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 评分如出一辙,那么这是为何呢?
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
也只与一级子句(最外边的括号内的)有关,内部再分词均不会做用
扩展阅读
如何实现字段中心和词中心相结合
- 类似字段,按用户意图将字段分组,好比 姓 和 名 两个字段合并 姓名 一个字段,将不一样意图的搜索彻底分开
- 以词为中心进行兜底,以字段为中心进行加成,以下
多字段算分在信息检索领域的尝试
- 传统BM25在计算相关性时把文档当作整体来考虑,但随着搜索技术的发展。文档慢慢的被结构化数据所取代。每一个文档都会被切分红多个独立的域,尤为是垂直化的搜索。好比网页有可能被切分红标题,内容,主题词等域,这些域对文章主题的贡献不能同等对待,因此权重就要有所偏重。
- BM25没有考虑这点。因此BM25F在此基础上作了一些改进,就是再也不单单的将单词做为个体考虑,而且将文档也依照field划分为个体考虑,因此BM25F是每个单词在各个field中分值的加权求和。
参考资料