首先:很抱歉发了这么长的帖子,我试图用一种简单的方式解释困难的情况,同时尽可能多地提供信息。
我有一个算法,试图确定用户在搜索过程中的期望值。我有几种方法可以使用它,而且我对这两种方法都有同样的问题,所以,比方说我用它来消除歧义。好吧,有了像这样的数据库结构(或任何其他允许工作的结构):
张贴
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的技巧或改变方法的想法感到满意,但我不能接受第三方解决方案。
您可以使用变量来提供自定义排序字段。
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(a,b)就具有d(a、b)=d(b、a)的性质。
现在你有了一个分数(不幸的是,可能不是距离:也就是说,有了分数,高值意味着接近),你需要一个聚类算法。理想情况下,你想要一个快速的,但也许它必须足够快,才能比人类阅读答案更快。
一种快速聚类算法是跟踪N个(对于某些参数N)聚类中心。将这些文档初始化为检索到的前N个文档,然后一次一个地考虑其他文档。在每个阶段,您都试图降低集群中心任意两个文档之间的最大分数(这相当于使文档尽可能远离)。当您考虑一个新文档时,计算该文档与N个当前集群中心中的每个中心之间的分数。如果这些分数中的最大值小于N个当前集群中心之间的当前最大值,则此文档与集群中心的距离比它们彼此的距离更远,因此您需要它。将其与N个集群中心中的一个交换-以新的N个集群中得分最小的一个为准。
这不是一个完美的聚类算法-首先,结果取决于文档的呈现顺序,这是一个坏兆头。然而,对于小N来说,它相当快,并且它有一个很好的特性:如果你有k<N个聚类,并且(从分数切换到距离)聚类内的每个距离小于来自不同聚类的两点之间的每个距离,则末端的N个聚类中心将包括来自k个聚类中的每个聚类的至少一个点。当你第一次看到一个你以前没有见过的集群的成员时,它将成为一个集群中心,你永远不会减少持有的集群中心的数量,因为你会弹出一个点,该点位于与其他中心不同的集群中,这不会增加作为聚类中心的任何两个点之间的最小距离(减少任何两个这样的点之间的最大得分)。