我有一个 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

虽然这是一个非常简单的示例,但它确实可以让您了解每个结果的匹配频率,并且这可能是一个伪排名。

如果您使用专为搜索任务设计的数据结构而不是数据库,您可能会获得更好的性能。例如,您可以尝试构建一个 倒排索引. 。然而,您可能还想研究类似的内容,而不是自己编写 卢塞恩 它为您完成了大部分工作。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top