MySQL - BOOLEAN模式下的FULLTEXT +使用视图字段的相关性

时间:2013-01-05 09:31:21

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

我有下表:

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”匹配“大苹果”,但不是“ibg apple”(只需要搜索前缀匹配)。

由于

1 个答案:

答案 0 :(得分:0)

由于没有人回答我的问题,我正在发布我的解决方案(不是我希望看到的,如果我是谷歌搜索,因为它不是那么容易应用作为一个简单的数据库设计,但它是仍然是这个问题的解决方案)。 我无法使用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 ...”。如果它有一些符号,比如#,@,$,你可以将它们视为“”(空格)。 示例:“Rafael Perrella”

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.

完成这些步骤后,您将拥有一个包含所有结果的集合。使用一对(视图,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秒;使用我自己的笔记本,没有在专用托管中尝试它,它可能很多快)。