作者回复: 是的。静态质量得分不考虑相关性,因此只需要对文档自身进行打分就好。写成函数形式就是f(d),d代表文档。
而精确打分要考虑查询词和文档的相关性。如果文档是d,查询词是q,那么打分函数就是f(q,d)。由于查询词是动态的,因此只能在实时环节进行打分,无法在离线环节打分。(注意:查询词可能有多个词项,比如同时有“极客”和“时间”两个词项,因此只能实时计算相加。否则如果查询词只有一个词项,那么是可以用胜者表的方法离线计算相关性的)。
作者回复: 1.你提了很好的一个问题,静态质量分不好的是否会被活活饿死?其实,不管是静态质量得分还是动态的相关性打分,既然是排序,肯定会有优胜劣汰,只是在大数据的场景下,所谓的劣汰不是完全封杀,而是降低出现的概率。
首先,如果快速截断采取的是静态质量分,那么粗排的时候肯定就是换一种打分机制了,比如说采用bm25进行粗排,或者使用简化版的机器学习(为了保证效率,用在粗排阶段的机器学习模型会比较简单,而不是和用在精排阶段的机器学习模型完全一样)。
另一方面,为了保证结果的多样性,我们应该加入exploit &explore机制,就是保证有小比例的流量可以采用随机的方式选择检索结果,而不是靠打分排序,从而给一些初始打分不高的检索结果证明自己的机会。但如果数据依然不好,那么接下来这些低质量的结果被选出来的概率就会越来越低。
2.在搜索引擎和推荐引擎中,使用tf-idf,bm25,甚至是简化的逻辑回归模型来做非精准top k检索,都是常见的使用方案。此外,就像你说的一样,可以用一些简单算法算一遍,快速排除掉一些数据项。这方面其实也有许多研究和论文,比如说雅虎有一篇wand(weak and)算法的论文,就是讲如何根据相似度的上限来快速截断。
其实,使用非精准检索思路的场景非常多,我文中的简历筛选的过程就是一个例子。下一篇你也会看到另一个例子。
作者回复: 从某种角度角度来说,计算机世界和我们的生活的确都是蛮相似的,其实都是在针对目标,做各种优化和平衡,我们的学习,其实也是应该触类旁通,不仅仅是学习技术本身,也在学习做事的方式。
问题1: posting list的确是用链表或数组降序排序好的。而不是用堆。因为用堆的话,取出堆顶元素,就需要调整堆,代价是log n。但posting list只要是只读的就好,我们没必要要读第二大的元素的时候还要实时调整,这样效率反而会低。包括posting list如果插入新元素,其实我们可以使用第九讲索引更新的技术实现,而不是实时插入。因此,posting list目前的实现还是跳表或数组。
2.你举的这些例子都很好,都是先初步筛选,再精确筛选的。如果我们要实现人工智能的话,其实也是可以按照这个思路来设计实现的。
作者回复: 就如你说的,分层索引大概率只扫描第一层就能得到top k。因此,在第一层索引候选集充足的情况下,采用静态质量分降序,能更快进行top k截断,而不需要完整检索完第一层索引,从而达到检索加速的目的。
作者回复: 你思考了一些细节和案例,这个习惯很好。你也会发现:高质量索引的“极客”和低质量索引的“时间”求交集,这个方法感觉不太对是不是? 分层索引的确不是这么实现的。
分层索引不是根据词频类似的打分方式来对文档进行分层,它更多的还是根据静态质量分来区分。
比如说,来自门户网站的文章会被打上更高的质量分,而个人站点的类似文章会被打上较低的质量分。它们分别被划分到了高质量文档集合a,以及普通文档集合b中。
我们在建立倒排索引时,会针对a建立一个倒排索引,针对b建立一个倒排索引。
在检索时,先检索a索引,得到x个文档。如果不满足k个结果,那么再去索引b中,以“极客”和“时间”为key,单独在索引b中找到符合条件的y个文档,然后将x个文档和y个文档合并,再取top k。
那为什么不是在索引a中用“极客”检索posting list,再在索引b中用“时间”检索出posting list然后合并呢?因为这两个posting list的文档集合是空。(索引a和索引b中的文档是无交集的)。
作者回复: 实际中是有的。其实就是一个加权的表达式:
w1*tf + w2*静态质量分。
具体w1和w2的权重,可以看你的应用诉求,手动调整。
作者回复: 1.是的。还是为了快速截断。如果在高质量文档的索引中也有足够的候选集,那么其实我们也不需要检索完全部文档,因此对于高质量索引,依然采用根据静态质量降序,是能有加速效果的。
2.的确是这样的,现在的召回环节中,就有用逻辑回归进行截断的,当然,这个环节也有人叫做“粗排”环节。不过历史是相似的,在机器学习出来之前,bm25就是精排;在机器学习出来后,bm25就变成粗排了;同理,在深度学习出来以后,机器学习就可以变成粗排了。说不定未来哪天,深度学习也会变成粗排。