搜索结果的多样性

时间:2016-05-05 01:08:28

标签: php mysql algorithm

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

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

发表

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”,则算法会看到orange可能指的是公司,颜色或水果,并通过回答几个问题,它试图确定用户正在寻找什么。毕竟我得到了这样一个数组:

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

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

所以,通过加入和company,我可以给出(几乎)完美顺序的结果:

ORDER BY FIELD(keywords.id,  2,3,1)

嗯......你可以想象,如果一切都那么美好,我就不会来寻求帮助。所以,问题在于前面的例子我们只有4个可能的结果,所以,如果用户真的在寻找- Orange: the fruit of gods - How to prepare the perfect orange juice - Theory of Colors: Orange - Orange developed the first 7G phone ,他可以在第4个位置找到这个结果,一切都没问题。但是......如果我们有关于水果的200个帖子和关于颜色的100个帖子,关于公司的第一篇帖子就在第301位。

我正在寻找一种方法来交替订单(以可预测和可重复的方式),因为我知道用户必须寻找company,然后是fruit和公司在末尾。我希望能够在第一个位置(可能是第二个位置)显示关于color的帖子,然后是关于fruit的帖子,然后是color,并启动此帖子再循环直到结果结束。

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

2 个答案:

答案 0 :(得分:2)

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

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   |

答案 1 :(得分:0)

我认为你确实需要一些分类方法,或者我更愿意说,将答案聚类。如果您可以这样做,则可以首先向用户显示每个群集的最高得分答案。嘿,有时候最大化多样性真的值得为它本身而做!

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

现在你有一个分数(遗憾的是可能不是距离:也就是说,分数,高值意味着靠近),你需要一个聚类算法。理想情况下,你想要一个快速的,但它可能只需要足够快,比人类阅读答案更快。

一种快速聚类算法是跟踪N(对于某些参数N)聚类中心。将这些文档初始化为检索到的前N个文档,然后一次一个地考虑每个其他文档。在每个阶段,您都在尝试降低群集中心中任意两个文档之间的最大分数(这相当于使文档尽可能远离)。考虑新文档时,请计算该文档与N个当前集群中心之间的分数。如果这些分数的最大值小于N个当前聚类中心之间的当前最大分数,那么此文档远离聚类中心,而不是彼此之间,因此您需要它。将其与N个聚类中心之一交换 - 无论哪一个使得新N聚类中心之间的最大分数最少。

这不是一个完美的聚类算法 - 首先,结果取决于文档的显示顺序,这是一个不好的信号。然而,它对于小N来说相当快,并且它具有一个很好的特性:如果你有k <= N个簇,并且(从分数切换到距离),簇内的每个距离都小于两个点之间的每个距离从不同的簇中,最后的N个簇中心将包括来自每个k簇的至少一个点。第一次看到您之前从未见过的群集成员时,它将成为群集中心,您永远不会减少所持群集中心的数量,因为您将弹出一个与其他群集不同的群集。其他中心,不会增加作为聚类中心的任意两点之间的最小距离(减少任何两个这样的点之间的最大分数)。