【问题标题】:MySQL - FULLTEXT in BOOLEAN mode + Relevance using views fieldMySQL - BOOLEAN 模式下的 FULLTEXT + 使用视图字段的相关性
【发布时间】:2012-12-19 16:15:03
【问题描述】:

我有下表:

CREATE TABLE IF NOT EXISTS `search`
(
    `id` BIGINT(16) NOT NULL AUTO_INCREMENT PRIMARY KEY,
    `string` TEXT NOT NULL,
    `views` BIGINT(16) NOT NULL,
    FULLTEXT(string)
) ENGINE=MyISAM;

总共有 5,395,939 个条目。要对某个词(如“a”)执行搜索,我使用以下查询:

SELECT * FROM `search` WHERE MATCH(string) AGAINST('+a*' IN BOOLEAN MODE) ORDER BY `views` DESC LIMIT 10

但是真的很慢=(。上面的查询耗时15.4423秒。显然不用views排序就快了,不到0.002秒。

我正在使用 ft_min_word_len=1 和 ft_stopword_file=

有什么方法可以在全文搜索中使用视图作为相关性,而不会使其太慢?例如,我希望搜索词“a b”匹配“big apple”,但不匹配“ibg apple”(只需要匹配搜索前缀)。

谢谢

【问题讨论】:

  • 要了解您的问题,为您的查询提供 EXPLAIN 输出会很有帮助。返回的行数和索引的基数可能也会有所帮助。
  • 谢谢,但不再需要了 =D。问题是它匹配了大约 46 万行的“+a*”。当我将其限制为 10 个结果时,它不再是问题,因为它只需要返回 10 个第一个结果。但是如果我要求 MySQL 按视图排序,它仍然需要得到所有这 46 万个结果,排序,然后只返回 10 个。如果不将它们全部排序,它就无法知道 10 个最好的结果是什么=/。我想没有使用 MySQL 的解决方案。我已经搜索和研究了很多尝试这样做,但没有找到解决方案。

标签: mysql database-design full-text-search


【解决方案1】:

由于没有人回答我的问题,所以我发布了我的解决方案(如果我在谷歌上搜索,我希望看到的不是那个,因为它不像简单的数据库设计那样容易应用,但它是仍然是这个问题的解决方案)。 我无法用 MySQL 使用的任何引擎或函数真正解决它。对不起=/。

因此,我决定开发自己的软件来完成它(使用 C++,但您可以将其应用到任何其他语言中)。 如果您要寻找的是一种在小字符串中搜索某些单词前缀的方法(我的字符串的平均长度是15),那么您可以使用以下算法:

1. Create a trie. Each word of each string is put on the trie.
   Each leaf has a list of the ids that match that word.
2. Use a map/dictionary (or an array) to memorize the informations
   for each id (map[id] = information).

搜索字符串: 注意:字符串的格式为“word1 word2 word3...”。如果它有一些符号,如#、@、$,您可能会将它们视为“”(空格)。 示例:“拉斐尔·佩雷拉”

1. Search for the prefix "Rafael" in the trie. Put all the ids you
   get in a set (a Binary-Search Tree that ignores repeated values).
   Let's call this set "mainSet".
2. Search for the prefix "Perrella" in the trie. For each result,
   put them in a second set (secSet) if and only if they are already
   in the mainSet. Then, clear mainSet and do mainSet = secSet.
3. IF there are still words lefting to search, repeat the second step
   for all those words.

完成这些步骤后,您将拥有一个包含所有结果的集合。使用 (views, id) 对创建一个向量,并按降序对向量进行排序。所以,只要得到你想要的结果...我限制为 30 个结果。

注意:您可以先对单词进行排序以删除具有相同前缀的单词(例如,在“Jan Ja Jan Ra”中您只需要“Jan Ra”)。算法很明显,我就不解释了。

这个算法有时可能很糟糕(例如,如果我搜索“a b c d e f ... z”,我会搜索整个 trie...)。所以,我做了改进。

1. For each "id" in your map, create also a small trie, that will
   contain the words of the string (include a trie for each m[id]...
   m[id].trie?).

然后,进行搜索:

1. Choose the longest word in the search string (it's not guaranteed,
   but it is probably the word with the fewest results in the trie...).
2. Apply the step 1 of the old algorithm.
3. Make a vector with the ids in the mainSet.
4. Let's make the final vector. For each id in the vector you've created
   in step 3, search in the trie of this id (m[id].trie?) for all words
   in the search string. If it includes all words, it's a valid id and
   you might include it in the final vector; else, just ignore this id.
5. Repeat step 4 until there are no more ids to verify. After that, just
   sort the final vector for <views, id>.

现在,我将数据库用作轻松存储和加载数据的一种方式。该表中的所有查询都直接向该软件询问。当我添加或删除一条记录时,我会同时发送到数据库和软件,所以我总是保持更新。加载所有数据花费了我大约 30 秒,但是查询很快(最慢的查询为 0.03 秒,平均为 0.001 秒;使用我自己的笔记本,没有在专用主机中尝试过,可能很多更快)。

【讨论】:

    猜你喜欢
    • 2014-08-29
    • 2013-06-04
    • 2023-03-14
    • 1970-01-01
    • 2013-09-22
    • 1970-01-01
    • 1970-01-01
    • 2012-05-21
    • 1970-01-01
    相关资源
    最近更新 更多