方法:对搜索结果进行排名
我遇到了一个Webapp开发问题,为此我开发了一个解决方案,但是我试图找到其他可能解决我所遇到的性能问题的想法。
问题陈述:
- 用户输入几个关键字/令牌
- 应用程序搜索与令牌的匹配项
- 根据分数对条目ID进行排序
- 如果点值相同,则使用日期对结果进行排序
我想要做的但没有弄清楚的是,发送1个查询,该查询返回类似于in()结果的内容,但为每个标记匹配的每个令牌ID返回一个重复的条目ID。
是否有比我正在做的更好的方法,即使用多个,每个令牌运行一个查询的单个查询?如果是这样,实现这些目的最简单的方法是什么?
编辑
我已经标记了条目,例如," see spot run"的条目ID为1,三个标记" see"," spot"," run"位于单独的标记表中,具有与它们相关的条目ID,因此该表可能如下所示:
'see', 1 'spot', 1 'run', 1 'run', 2 'spot', 3
解决方案
回答
我们可以在MySQL中使用" UNION ALL"在一个查询中实现此目标。
只需遍历PHP中的令牌即可为每个令牌创建UNION ALL:
例如,如果标记是" x"," y"和" z",则查询可能看起来像这样
SELECT * FROM `entries` WHERE token like "%x%" union all SELECT * FROM `entries` WHERE token like "%y%" union all SELECT * FROM `entries` WHERE token like "%z%" ORDER BY score ect...
order子句应作为一个整体在整个结果集上运行,这就是我们所需要的。
就性能而言,它并不会那么快(我猜是这样),但是对于数据库而言,在速度方面的主要开销通常是将查询从PHP发送到数据库引擎并接收结果。使用这种技术,每个令牌只会发生一次,而不是一次,因此性能会提高,我只是不知道是否足够。
回答
如果使用的是UNION ALL模式,则可能还需要在查询中包括以下部分:
SELECT COUNT(*) AS C ... GROUP BY ID ORDER BY c DESC
虽然这是一个非常琐碎的示例,但它确实为我们提供了每个结果的匹配频率,并且这可能是一个伪排名。
回答
如果使用为搜索任务设计的数据结构而不是数据库,则可能会获得更好的性能。例如,我们可以尝试构建反向索引。但是,我们可能不希望自己编写它,而是希望研究像Lucene这样的东西,它可以为我们完成大部分工作。
回答
我知道这并不是我们要问的问题的严格答案,但是如果表是数千行而不是数百万行,那么FULLTEXT解决方案可能是到达此处的最佳方法。
在MySQL中,当我们在索引列上使用MATCH时,将为我们提供的每个关键字赋予一个相关性分数(大致由提及每个关键字的次数计算),该分数将比方法更准确,并且对于多个关键字肯定更为有效。
看这里:
http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html