文档目录
从这里开始
优化搜索结果
如何优化搜索结果设置可搜索字段排序器设置卡拉搜索的排序策略排序器(Ranker)多层排序算法设置排序器搜索结果分页搜索结果过滤结果高亮返回字段设置

排序器设置

用户在你的应用中搜索时,他们的目的就是想要在你的网站、APP 或者小程序里快速找到他们想要的内容。

为了给他们提供最佳的用户体验,搜索引擎必须同时做好两件事情

  1. 针对用户的查询,准确地找到他们要找的内容 - 不能漏掉,也不能找到太多不相关的内容
  2. 针对这些找到的内容,把与用户查询词最“相关”的内容放在前面

在文档前一节设置可搜索字段中,我们介绍了如何用可搜索字段来让用户的搜索可以准确地找到他们想找的内容。

在本文中,我们着重讲怎样设置排序器,可以将为用户将最相关的结果排在前面。

卡拉搜索的排序策略

当用户输入一个搜索词,比如说 "iPhone" 时,卡拉搜索的引擎先找出所有含有 "iPhone" 这个词的待选对象。

这些待选再被放到一系列排序器中,经过排序,引擎会把与 "iPhone" 最相关的结果放在前面。那么,什么是排序器呢?排序器又是怎样被结合在一起,最终的排序顺序是怎样被决定的?

排序器(Ranker)

在卡拉搜索的后台,你可以为你的索引设置一系列排序器。

排序器的作用,是将文档按一个分数,整理好并排列好顺序,这里我们仍然用电影搜索来作例子。

假设现在你想找电影《无间道》,但忘了电影的名字,只依稀记得这是刘德华演的卧底片,那么你可能会搜索 “刘德华 卧底”。

直觉上,对于电影描述中,如果“刘德华”这个词与“卧底”这个词靠得越近,那么这个对象就应该更符合用户的查询。而“词距近似排序器”实现的就是这个效果。词距近似排序器计算出多个词语在对象中的距离(包括跨字段的情况),然后根据距离将对象进行排序。

目前,卡拉搜索中内置了以下几种排序器可供设置

  • 词距近似排序器
  • 最佳字段排序器
  • 业务排序器
  • 过滤匹配排序器(beta)

那么,如果有多个排序器时,排序结果是怎样产生的,以及你应该如何根据你的业务需要来设置多个排序器呢?

多层排序算法

传统的搜索引擎会为每个对象计算一个分数,并用这个分数进行排序。但这样做有个非常致命的缺点:因为搜索结果的评分由一个单一函数决定,这个函数如果稍微复杂的话,搜索结果将变得几乎无法解释和调试。

而如果评分函数过于简单,常常又无法准确地为用户调整出最好的搜索体验。

比如说,一个评分函数可能是这样的

num_likes^2 + 3*num_comments * log(content_length)

这个假想的评分是由点赞数的平方,加上评论数的 3 次方及文章长度的对数的积。这个函数会导致当给定一个用户查询,比如 "iPhone" 时,很难甚至无法解释为什么一些特定的对象排在更前面。

卡拉搜索使用更先进的多层排序算法,以下这个算法的过程:

  • 先按第一个排序器,为每个对象进行评分并排序。并将评分相同的对象分到同一个组里
  • 在上一步分出来的各个组,再按第二个排序器分别对每个对象进行评分并排序,同时将评分相同的对象分到新的组里
  • 反复进行下去直到所有的排序器用完

用一个例子来说明这个过程:

第一步

初始时,用户查询返回 8 个对象 {1, 2, 3, 4, 5, 7, 9, 10} 集合,此时的结果集是无序的

第二步

经过第一个排序器,其中 {1, 2, 4, 5} 四个对象得分为 1, {3, 7, 9, 10} 四个对象得分为 2。此时,第一层的排序结果即为 [[3, 7, 9, 10], [1, 2, 4, 5]]

第三步

分别在两个分组中,用第二个排序器对每个对象进行评分排序。{3, 7} 得分为 1, {9, 10} 得分为 2,因此第一个分组中进一步排序为 [[9, 10], [3, 7]]]

同样的逻辑,在第上一步的第二组中,我们得到 [[1, 4], [2, 5]]

那么至此,整个排序顺序变为 [[9, 10], [3, 7]] [[1, 4], [2, 5]]。我们假设索引只设定了两个排序器,那么这就是对象的最终排序。如果用户指定只返回前 5 个结果的话,这次查询返回的对象顺序就是 [9, 10, 3, 7, 1]

设置排序器

在了解了卡拉搜索的多层排序算法后,我们就可以开始为索引设置排序器了。

请注意,由于多层排序算法的存在,排序器的顺序对排序结果有着非常重要的影响。同时,有的排序器可以设置多个,但有的排序器仅推荐设置一个。如果希望获得最佳的排序结果,请详细阅读以下排序器的介绍。

词距近似排序器

词距近似排序器仅会在查询中分词后超过 2 个词语时开始生效,可以极大地增强搜索召回率和帮助模糊查询。

比如说,如果你的对象中含有文本 “中国人民解放军”,那么用户在搜索 “中国解放军“ 时,即使这个词本身不存在,但用户的意图是明显的,因此智能的搜索引擎应该可以帮助用户找到这个对象。

更多的情况是跨字段查询,比如对于一件商品,你的对象可能是这样的:

{
"name": "香奈尔小牛皮包",
"model": "Chanel 255"
"color": "红色",
"price": 2888
}

用户可能不会直接搜索类似 “Chanel 255" 这样过于专业的词汇(香奈尔这款包的内部型号名)。相反,他们更可能搜索类似 ”红色 小牛皮 香奈尔“ 这样的关键词。词距近似排序器会对这样的查询计算一个词语在对象中出现的近似距离,然后以此为基础进行排序。

可以看到,词距近似排序器是可以增强召回的,我们通常建议将它列在排序器顺序的开头。同时,一个索引多数情况下仅推荐设置一个词距近似排序器。

最佳字段排序器

你上传的对象中,可能有多个字段,比如

{
"name": "无间道",
"actors": "刘德华",
"story": "1991年,香港黑帮三合会会员刘健明(刘德华)听从老大韩琛(曾志伟)的吩咐,加入警察部队成为黑帮卧底,韩琛许诺刘健明会帮其在七年后晋升为见习督察"
}

在用户搜索时,查询 “刘德华” 会匹配到字段 actors(演员) 和 story(故事简介)。那么匹配演员的对象应该排前面还是匹配故事简介的对象排前面呢?

这个特定的例子中,似乎匹配演员是个更好的选择。但也有可能,你根据业务需要,必须将匹配某个字段的对象放在匹配另一些字段的前面。比如说,对绝大多数文章类型的数据来说,匹配标题的重要程度远大于正文。

你可以用最佳字段排序器来实现这样的需求,它会按照 可排序字段 中设置的顺序,来决定字段的重要性。比如说,在下图的可搜索字段设置下,最佳字段排序器会将匹配了 name 的对象优先于 actors 的对象。

\u53EF\u6392\u5E8F\u5B57\u6BB5\u5BF9\u6700\u4F73\u5B57\u6BB5\u6392\u5E8F\u5668\u7684\u5F71\u54CD

最佳字段排序器通常建议放置在词距排序器后,同时一个索引仅设置一个词距排序器。

业务排序器

卡拉搜索的引擎可以在绝大多数情况下,处理好文本查询的相关度。

但是没有人比你更了解你的用户,你当然也希望结合你的业务特点,给你的用户最佳的搜索体验。比如说,如果你的用户搜索“刘德华 电影”时,你也许希望将评分更高的刘德华电影排得更前面。

如果你是电商的话,你可能会希望将一些历史转化率更高的商品排到更前面,以促成购买。

同样,如果你是社交 APP 的话,当用户搜索时,你可能希望将一些更加受欢迎的帖子、视频排到前面。

要达到这个目的,你需要设置一系列业务排序器。我们用一个电影搜索的实例来作例子

[
{
"name": "大话西游之月光宝盒",
"rating": 8.8,
"rating_for_ranking": 2
},
{
"name": "大话西游之仙履奇缘",
"rating": 8.9,
"rating_for_ranking": 2
},
{
"name": "大话西游3",
"rating": 3.1,
"rating_for_ranking": 1
}
]

对于用户输入的查询 “大话”,三部电影都可以被文本匹配上。然而,显然前两部旧的大话西游评价更高,因此在用户搜索大话时,我们希望优先展示它们。在配置中,你可以添加一个业务排序器:

\u6309\u8BC4\u5206\u6392\u5E8F\u7684\u4E1A\u52A1\u6392\u5E8F\u5668

业务排序器可以添加任意多个,但在有多个业务排序器时,需要注意排序字段的精度问题。

业务排序器精度

我们在之前卡拉搜索的排序策略中介绍过多层排序算法。由于多级排序算法的存在,如果某个排序器的排序过于精确,那么在它其后的排序器会失去作用。

举例来上,在这里的电影排序里,我们有一个字段 rating 表示用户对电影的评分。由于 rating 的分布是 0 - 10 之间的小数,那么如果我们不作任何处理,添加一个在 rating 上的业务排序器后,整个排序就已经大致固定了。原因是在这个业务排序器后的排序器接受到的对象已经被分到了很小的组中,而多层排序算法只会对同一个组里的对象进行再排序,因此后面的排序器不再有发挥作用的空间。

要让多层排序算法的效果更好,我们建议将一些业务排序器降低精度。比如说,对于上面用评分排序的业务排序器来说,我们建议生成另一个用于排序的字段,如 rating_for_ranking,这个字段的取值来源于 (rating / 3) 后取整。

这样做的意义是,将 0 - 10 的评分段变成四个评分,即 0, 1, 2, 3。直觉上,这相当于把电影评分分为四段,即 [0-3) 烂片,[3, 6) 一般电影,[6-9) 好电影,[9, 10) 佳片。

当然这里的精度处理需要结合对业务的理解来进行,常见的去精度方式有

  • 用值除以 10,100,1000 等,并取整
  • 用 math.sqrt 函数对数字进行开根号,并取整
  • 用 math.log2 函数对数字进行取 log,并取整

取整在多数情况下是必要的,以免造成在去精度的过程中又制造出一个精度较高的浮点数。

友情链接更新日志© 2020, 卡拉搜索, Built with ❤️ in San Francisco + Beijing

京ICP备15049164号-3