3

你好stackoverflow的人,

我们有一个不断增长的 Rails 项目,现在我们在搜索中遇到了第一个性能问题,因为我们不知道如何正确地利用 sphinx 来满足我们的需求。我们有像“Java PHP Software developer”这样的搜索查询。我们现在的问题是排名应该适用于多种情况。

作为搜索字段,我们有标签列表、描述和标题。如果其中一个术语在其中一个字段内,它应该得到例如 2 分。如果它在多个字段中,则为更多点,但如果它在同一字段中不止一次,则不是多个点。下一个问题是我有一个包含同义词的大文件,也应该检查它。它看起来像这样:

Java > Java
Java-EE > Java
...

因此,如果发现 Java-EE,它也应该得到一些分数,但会因为成为同义词而受到惩罚。

最大点数将是 5,如显示的 5 颗星。任何快速的解决方案都会很好,因为目前它是用普通的 ruby​​ 完成的,而且速度很慢,因为我们无法在 sphinx 中正确排名。

如果有另一个搜索引擎的解决方案也很好,因为它可以改变。

提前感谢所有的努力。欢迎所有拼写更正和问题以清除问题。

4

2 回答 2

2

大多数性能问题都可以通过改变使用 sphinx 的方式来解决。首先,您需要解决如何索引 sphinx 中的数据。在索引期间进行一些处理将使搜索更快并且结果更相关。其次,处理搜索词,最后但并非最不重要的是,决定要使用的排名算法。

我将使用“标题”字段作为示例,但可以为所有字段复制逻辑。

索引

向 sphinx 添加两个字段(“title”和“title_synonyms”)。对于数据库中的每条记录,请执行以下操作:-

  • 对单词执行 DISTINCT 以删除重复项(“Ruby Developer / Java Developer”将变为“Ruby Developer / Java”。这将阻止记录在搜索时获得两个重复分数。这进入“title”

  • 从上面取 DISTINCT 标题并将所有单词替换为其扩展的同义词等效项。我建议将同义词放在数据库中以使扩展更容易。然后文本将变为“Ruby Developer / Java-EE”。每个单词都必须替换为所有同义词。如果 Java 有两个同义词,则它们都必须在该字段中。这进入“title_synonyms”

搜索

因为现在 sphinx 中有两个字段,我们可以给它们分别赋予不同的权重;“title”可以获得“10”的权重,“title_synonyms”可以获得“3”的权重。这意味着一条记录必须匹配 4 个同义词才能排名高于原始标题的一个。您可以根据自己的需要调整重量。

假设用户正在搜索“Java Developer”。对于搜索短语,请执行以下操作:-

  • 删除重复的单词
  • 获取搜索词组中每个单词的同义词
  • 将 Sphinx 中的匹配模式设置为 SPH_MATCH_EXTENDED

上述规则将意味着 sphinx 中的搜索如下所示:-

@title "Java 开发者" | @title_synonyms "Java-EE"

如果您想对精确匹配进行排名高于词位,则搜索查询将如下所示:-

@title ("Java 开发者" | "=Java =开发者") | @title_synonyms ("Java-EE" | "=Java-EE")

您将需要使用 SPH_RANK_PROXIMITY_BM25 或 SPH_RANK_SPH04 才能使其正常工作。

排行

您可以尝试任何内置的排名算法,看看结果如何。我推荐 SPH_RANK_MATCHENY 或 SPH_RANK_WORDCOUNT 作为开始。

对于接近度和精确匹配排名,请使用 SPH_RANK_PROXIMITY_BM25、SPH_RANK_SPH04 或 SPH_RANK_EXPR,您可以在其中使用自己的算法。

结论

您现在应该有一个既快速又准确的搜索。Ruby 应用程序需要做的工作很少,大部分工作都在 sphinx 中完成(它应该在哪里)。

希望这可以帮助...

于 2012-04-15T08:13:35.523 回答
1

这个性能问题是一个算法问题。

如果您无法以使用后端工具(如 sphinx 或数据库引擎)的方式表达问题,那么您正在使用 ruby​​ 进行处理,这很容易出现性能问题。

首先,尽可能多地使用 sphinx(或任何其他搜索引擎)和数据库。进入 ruby​​ 的数据越预先消化,您在 ruby​​ 代码中要做的事情就越少,而且这可能会更快,因为在过去半个世纪中数据库已经高度优化。

因此,例如,在关键字上运行 sphinx。还要在同义词上运行 sphinx。将所有答案限制在排名靠前的结果,然后合并结果。这样,您的 ruby​​ 代码将仅限于可能的高结果,而不必考虑整个条目数据库。

一旦进入 ruby​​,最重要的是避免使用高阶算法,即确保您使用的是低阶算法。

在处理原始数据时,如果您将最重要的结果保存在一个数组中并尝试对数组进行排序或扫描,您将得到一个 N 平方顺序。也就是说,您的订单将是原始条目数和您保留在数组中的元素数的乘积。

解决您的问题的最佳算法是由类似堆的容器或 b 树实现的优先级队列。两者都有 N-log-N 顺序(N 乘以 N 的 log),或者原始数据记录的数量乘以您将保留在容器中的项目数量的 log。

堆是一棵二叉树,树中的每个节点(不仅是叶子,还有每个节点)都有一个评级记录。每条记录下方的节点都具有较低的等级。这称为堆条件。

有一些算法可以添加元素,取出排名最高的元素,并替换保持堆状态的最低排名元素。在维基百科中查找二进制堆

假设您的网站将显示排名前 100 的结果。维护根排名最低的帮助。通过添加您正在处理的前 100 条原始记录来填充堆。

现在对于记录 101 及之后的记录,将其排名与根进行比较。如果新记录的排名更高,请使用删除算法将堆减少到 99 个节点(这将删除堆中排名最低的记录)并将新记录添加到堆中。

浏览完所有记录后,您将获得排名前 100 的结果。堆删除算法将以相反的顺序将它们拉出。

于 2012-04-14T14:40:54.830 回答