【问题标题】:Variety on search result搜索结果的多样性
【发布时间】:2016-05-05 01:08:28
【问题描述】:

首先:抱歉,这篇文章太长了,我试图以一种简单的方式解释一个困难的情况,同时,我试图提供尽可能多的信息。

我有一个算法试图在搜索过程中确定用户的期望。有几种方法可以使用它,而且我对它们都有同样的问题,所以,可以说我用它来消除歧义。好吧,使用像这样的数据库结构(或任何其他允许工作的):

发帖

ID | TITLE
---+----------------------------------------------
1  | Orange developed the first 7G phone
2  | Orange: the fruit of gods
3  | Theory of Colors: Orange
4  | How to prepare the perfect orange juice

关键字

ID | WORD     | ABOUT   
---+----------+---------
1  | orange   | company 
2  | orange   | fruit   
3  | orange   | color   

post_keywords

ID | POST  | KEYWORD
---+-------+---------
1  |   1   |   1 
2  |   2   |   2
3  |   3   |   3
4  |   4   |   2

.

如果用户在搜索框中搜索“橙色”一词,算法会认为orange 可能指的是公司、颜色或水果,并且通过回答几个问题,它试图确定用户正在寻找哪个。毕竟我得到了一个像这样的数组:

$e = array(
    'fruit' => 0.153257,
    'color' => 0.182332,
    'company' => 0.428191,
);

在这一点上,我知道用户可能正在寻找有关水果的信息(因为fruit 的值更接近0),如果我错了,我的第二个赌注是color。在列表底部,company

所以,通过 Join 和 ORDER BY FIELD(keywords.id, 2,3,1) 我可以给结果(几乎)完美的顺序:

- Orange: the fruit of gods
- How to prepare the perfect orange juice
- Theory of Colors: Orange
- Orange developed the first 7G phone

.

嗯...你可以想象,如果一切都那么好,我不会来寻求帮助的。所以,问题是在前面的例子中,我们只有 4 个可能的结果,所以,如果用户真的在寻找 company,他可以在第 4 个位置找到这个结果,一切都很好。但是...如果我们有 200 个关于水果的帖子和 100 个关于颜色的帖子,那么第一个关于公司的帖子排在第 301 位。

我正在寻找一种交替顺序的方法(以可预测和可重复的方式),因为我知道用户可能必须寻找fruit,然后是color,最后是公司。我希望能够在第一个位置(可能是第二个)显示关于fruit 的帖子,然后是关于color 的帖子,然后是company,然后再次开始这个循环,直到结果结束.

编辑:我会对 MySQL 技巧或改变方法的想法感到满意,但我不能接受第三方解决方案。

【问题讨论】:

  • 事实上,我会按类别分组并返回每个类别的最佳结果,并允许此时用户单击该类别以查看该类别的所有其他链接。
  • 看起来您正在使用关键字表在 MySQL 中构建倒排索引。你有一些查询理解能力。您是否考虑过使用 Elasticsearch 代替?我的这次谈话可能会帮助您了解如何使用 Elasticsearch elastic.co/elasticon/conf/2016/sf/…
  • ^ 我同意.. ElasticSearch 在这里会很有帮助.. 这样您就可以对搜索结果和许多其他与搜索相关的很酷的东西进行排名...
  • @Eric 我不能使用那个选项,因为我没有准确解释我在做什么,因为它有点复杂,所以,我发明了一个更容易解释的情况(博客示例) 但保持相同的原则。但是,足以说在用户眼中,我们所做的那种分类看起来很荒谬,但是,在对算法的测试中,他们说“现在所有好的信息都在一起了,必须在第一时间页面,但如果我在第 1 页找不到它,我会在第 20 页或其他地方找到它”。
  • @DougT。是的,我使用倒排索引,但我将阅读有关 Elasticsearch 的文章,看看它的使用情况如何。

标签: php mysql algorithm


【解决方案1】:

您可以使用变量来提供自定义排序字段。

SELECT
  p.*,
  CASE k.about
    WHEN 'company' THEN @sort_company := @sort_company + 1
    WHEN 'color' THEN @sort_color := @sort_color + 1
    WHEN 'fruit' THEN @sort_fruit := @sort_fruit + 1
    ELSE NULL
  END AS sort_order,
k.about
FROM post p
  JOIN post_keywords pk ON (p.id = pk.post)
  JOIN keywords k ON (pk.keyword = k.id)
  JOIN (SELECT @sort_fruit := 0, @sort_color := 0, @sort_company := 0) AS vars
ORDER BY sort_order, FIELD(k.id, 2, 3, 1)

结果将如下所示:

| id | title                                   | sort_order | about   |
|---:|:----------------------------------------|-----------:|:--------|
|  2 | Orange: the fruit of gods               |          1 | fruit   |
|  3 | Theory of Colors: Orange                |          1 | color   |
|  1 | Orange developed the first 7G phone     |          1 | company |
|  4 | How to prepare the perfect orange juice |          2 | fruit   |

【讨论】:

  • 这个看起来可行。我现在无法尝试,但我会在几个小时后尝试。 =D
  • 我只想说:它奏效了。我很欣赏这个解决方案的简单性。你简直就是个天才。
  • 谢谢 :-) 很高兴听到它对您有帮助。
【解决方案2】:

我认为您确实需要某种分类方式,或者,我更愿意说,对答案进行聚类。如果你能做到这一点,那么你可以首先向用户展示每个集群中得分最高的答案。嘿,有时为了自身的利益而最大限度地提高多样性确实值得!

我认为您应该能够对答案进行聚类。您有某种评分公式可以告诉您文档对用户查询的回答有多好,可能基于“词袋”模型。我建议您通过将另一个文档视为查询来使用它来判断一个文档与另一个文档的接近程度。如果您确实这样做,您可能希望将每个文档视为一个查询,另一个作为答案并将两个分数平均,以便分数 d(a, b) 具有 d(a, b) = d 的属性(b, a)。

现在您有了一个分数(不幸的是可能不是距离:也就是说,有了分数,高值意味着靠近)并且您需要一个聚类算法。理想情况下,您想要一个快速的,但也许它必须足够快,才能比人类阅读答案的速度更快。

一种快速聚类算法是跟踪 N 个(对于某些参数为 N)聚类中心。将这些初始化为检索到的前 N ​​个文档,然后一次考虑每个其他文档。在每个阶段,您都试图减少在集群中心的任何两个文档之间找到的最大分数(这相当于让文档尽可能地分开)。当您考虑一个新文档时,计算该文档与 N 个当前聚类中心中的每一个之间的分数。如果这些分数的最大值小于 N 当前聚类中心之间的当前最大分数,则该文档与聚类中心的距离比它们彼此之间的距离更远,因此您需要它。将其与 N 个集群中心之一交换 - 以新的 N 个集群中心之间的最高得分最低者为准。

这不是一个完美的聚类算法 - 一方面,结果取决于文档呈现的顺序,这是一个不好的迹象。然而,它对于小 N 来说相当快,并且它有一个很好的特性:如果你有 k

【讨论】:

    猜你喜欢
    • 2016-03-17
    • 2015-09-11
    • 2020-05-03
    • 1970-01-01
    • 1970-01-01
    • 2012-08-23
    • 2018-12-10
    • 2015-03-22
    • 2012-01-24
    相关资源
    最近更新 更多