搜索业务中的经验总结
一些业内概念
- ctr和cqr
- ctr在大部分场景是点击率的意思。在搜索中也有“query和片段(doc field)的交集占片段的比例”的意思。
- cqr是query与片段的交集占query的比例。
- tightness的两种概念
- query命中doc的所有term,计算前后两个term在doc中的距离,距离远,tightness越低。
- 两个紧密度概念,一个是单个term的,一个是term之间的tightscore。如query 是下载深海大作战,经分词工具被切分成“下载 深海 大 作战”,但其实“大”和“作战”的紧密度很高,从文本相关性角度来看,召回“喵星大作战”app要一定程度比“大人物作战”会更相关。单个term的紧密度代表了这个term被认为需要跟它的前后词紧密相连。
- omit: 省略惩罚score,如果query中的term在doc没有出现,进行算分惩罚。
- 召回策略的思路、手段
- ES:传统的term检索,侧重于ctr、cqr、紧密度等基础相关性,侧重于表面匹配
- bert向量召回:语义召回,更好的对query中用户意图的理解(同义词,一词多义问题)
- session向量召回:用户行为 or query行为召回,搜了又看 or 看了又看
一些遇到的问题
两次相同查询排序不同
- 现象:这会导致两种badcase,1是用户搜完看到的结果顺序不同,2是用户在翻页/loadmore后看到有重复数据
- 原因:ES多分片的查询模式导致。
- 解决方案:考虑dfs_query_then_fetch,这个配置能让一次search请求路由到其他分片,同时获得全局的tf-idf,来避免仅在本地数据计算分数时的局限性。另外,也要考虑给ES查询时带上with-preference,但这不是一个完整的解决方案,因为会导致热点问题(可以通过preference=uid来解决)
query=文章title时 排序不佳
- 现象:用户搜索的query与文章title完全相等,但对应的文章却没有排到第一位。
- 原因:搜索中要对query进行切词,去除低权重分词,并检索每个分词的相关性,所以检索结果的top结果并不一定对原title全匹配。
- 解决方案:后置强插。对每个搜索结果的title和query进行匹配,全命中时强插到第一位。
在线和离线分词是否该统一
- 做统一有什么好处? 两侧分词统一,系统收敛,所有遇到的case都能归结为分词库的问题。
- 不做统一有什么好处? 很多场景里,写入的时候尽可能多的分词,方便匹配,搜索的时候尽可能少的分词,减少过度匹配,这种方式最佳实践。
- 不做统一有什么坏处? 一种是分词粒度带来的紧密度问题,分的细了导致多了很多细分词:“人民 利 利益”,导致间隔大,紧密度匹配分低。 另一种是切词不一致导致term方式匹配不到
单维度排序怎么做
经典场景是query相关性搜索后按时间最新排序。 如果按单页20个召回后排序,用户会发现第二页和第一页的排序不是时间严格的。 如果按全量500个召回后排序,用户会发现排在前面的doc相关性很差。 目前做法是增加相关性截断,比如分数必须大于0.3,然后大约有50个,再按时间严格排序,用户体验较好。唯一的缺点是同query下“默认排序”和“时间排序”的结果个数不同。