题
我有一个 web 应用程序开发问题,我已经开发了一种解决方案,但我正在尝试寻找其他想法来解决我所看到的一些性能问题。
问题陈述:
- 用户输入多个关键字/标记
- 应用程序搜索与令牌的匹配项
- 每个令牌需要一个结果
- 即,如果一个条目有 3 个令牌,我需要条目 ID 3 次
- 对结果进行排名
- 为令牌匹配分配 X 点
- 根据点对条目 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 向数据库引擎发送查询并接收结果。使用这种技术,这只发生一次,而不是每个令牌一次,因此性能会提高,我只是不知道这是否足够。
其他提示
我知道这并不是您所问问题的严格答案 但如果你的表有数千行而不是数百万行, ,那么全文解决方案可能是最好的方法。
在 MySQL 中,当您在索引列上使用 MATCH 时,您提供的每个关键字都会获得一个相关性分数(根据每个关键字被提及的次数大致计算),这将比您的方法更准确,并且对于多个关键字来说肯定更有效。
看这里:http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html
如果您使用 UNION ALL 模式,您可能还需要在查询中包含以下部分:
SELECT COUNT(*) AS C
...
GROUP BY ID
ORDER BY c DESC
虽然这是一个非常简单的示例,但它确实可以让您了解每个结果的匹配频率,并且这可能是一个伪排名。