搜索引擎的核心思想是:针对用户输入的query,进行分词,然后按从倒排索引中匹配term,再基于如BM25等算法计算相关性,召回item。
在搜索场景中,往往还有一个比较常见的需求:根据term间的紧密度进行排序。即:如果一个query包含两个或以上的term,如果一个doc中term间距离较近,则相似性分数应该更高。举例而言:系统中有如下几条数据,我们使得数据长度一致,避免tf-idf造成的影响:
- 上海的汽车很多在市区
- 上海市区的汽车有很多
- 上海市区有很多的汽车
如果搜索上海汽车
,从直观而言,文档的匹配顺序也应该如上。但我们如果通过传统的match
的方式来匹配,各term间是独立的,如下图,各个doc的相似性分数一致:
上述需求可以通过短语匹配match_phrase
的方式来实现,因为elasticsearch底层调用的是lucene,lucene做短语匹配时会根据term之间的距离进行打分,如图,可以看到匹配顺序和我们直观感觉保持一致:
进一步探究,我们打开explain
模式,查看打分细节,可以看到一个phraseFreq
的得分项,该项为和短语相关的评分:
在进行短语匹配,并考虑位置因素打分时,有一个比较重要的参数slop
,该参数定义了term之间最大的距离差异,在一个doc中,如果query中两个term间的距离超过了该值,则认为该doc与query不相关,具体可参见短语模糊匹配。在紧密度排序实践中,可以根据实际情况合理设定该值,则在term距离未超过该值的doc中,term的距离也是相似性分数的一部分,初步实现了一个简单版本的紧密度排序。