【问题标题】:Optimizing mysql fulltext search优化mysql全文搜索
【发布时间】:2011-08-29 14:01:12
【问题描述】:

我想在我的网络中进行全文搜索。我需要分页搜索。我的数据库每张表有 50,000 多行。我已经改变了我的表并将(title,content,date) 设为索引。该表始终在更新,仍有一列id 是自动增加的。最新的date 总是在表的末尾。

date  varchar(10)
title  text
content  text

但整个查询时间将花费1.5+ seconds。我通过google搜索了很多文章,有的写道只限制Index字段字长可以帮助搜索更快。但作为text 类型,它can not 改变了一定的长度(我试过ALTER TABLE table_1 CHANGEtitletitleTEXT(500) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,不起作用)

date  varchar(10)
title  text(500)
content  text(1000)

所以,除了Sphinx 和第三方脚本。如何仅使用 sql 优化全文搜索?此处查询代码:

(SELECT 
title,content,date 
FROM table_1 
WHERE MATCH (title,content,date) 
AGAINST ('+$Search' IN BOOLEAN MODE)) 
UNION 
(SELECT 
title,content,date 
FROM table_2 
WHERE MATCH (title,content,date) 
AGAINST ('+$Search' IN BOOLEAN MODE)) 
Order By date DESC

谢谢。

【问题讨论】:

  • 表中的数据是否经常发生变化?还是这里根本改变?倒排索引总是会难以置信地加速全测试搜索,对于静态数据,它非常容易实现/应用。如果有更新,这可能会变得更加复杂
  • @b.buchhold,是的,表中的数据经常更新,变化。所以这很困难……至少我没有什么好主意。如果有人有明智的方法,请寻求帮助。
  • 是(标题、内容、日期)的全文索引,还是 btree 索引?
  • @Denis,只是alter table table_1 ADD INDEX title(title)
  • 你不能使用像 Lucene 这样的东西的原因是什么?它通过 Zend 框架在纯 PHP 中实现

标签: php mysql full-text-search


【解决方案1】:

根据问题的后续 cmets,您的列上有一个 btree 索引,而不是全文索引。

对于针对搜索的 MATCH(标题、内容),您需要:

CREATE FULLTEXT INDEX index_name ON tbl_name (title,content);

我不确定它会接受那里的日期字段(后者可能无论如何都不相关)。

【讨论】:

  • 我认为在这种情况下将日期添加到 FULLTEXT 索引是可以的,因为日期是 varchar(10) 而不是日期时间字段。此外,从一开始就没有全文是一个死的赠品。为你 +1 !!!
  • 抱歉稍后回复。这将比alter table table_1 ADD INDEX title(title) 更快我还有一些问题。 1.查询变成SELECT title,content,date FROM table_1 WHERE MATCH (index_name) AGAINST ('+$Search' IN BOOLEAN MODE)还是MATCH (title,content,date)index_name 的用法是什么? 2.如果我创建了一个新表,像这样? CREATE TABLE table_1 ( id INT AUTO_INCREMENT NOT NULL PRIMARY KEY, title TEXT, content TEXT, date VARCHAR(10), FULLTEXT (title,content,date) ); 再次感谢。
  • @Yuli:只需在当前表上创建索引:create fulltext index yourtable_fulltext_idx on yourtable(title,content,date);,然后运行当前查询。
【解决方案2】:

我有一个全面的计划让您尽可能彻底地优化 MySQL 以实现 FULLTEXT 索引

您应该做的第一件事是:摆脱停用词列表

这多年来一直惹恼一些人,因为他们不知道over 600 words are excluded from a FULLTEXT index

Here is tabular view of those stopwords.

有两种方法可以绕过这个

绕过选项 1) 创建自定义停用词列表。

您实际上可以向 mysql 提交您首选的停用词列表。这是默认值:

mysql> show variables like 'ft%';
+--------------------------+----------------+
| Variable_name            | Value          |
+--------------------------+----------------+
| ft_boolean_syntax        | + -><()~*:""&| |
| ft_max_word_len          | 84             |
| ft_min_word_len          | 4              |
| ft_query_expansion_limit | 20             |
| ft_stopword_file         | (built-in)     |
+--------------------------+----------------+
5 rows in set (0.00 sec)

好的,我们不要创建停用词列表。我通常将英文文章设置为唯一的停用词。

echo "a"    > /var/lib/mysql/stopwords.txt
echo "an"  >> /var/lib/mysql/stopwords.txt
echo "the" >> /var/lib/mysql/stopwords.txt

接下来,将选项添加到 /etc/my.cnf 加上允许 1 个字母、2 个字母和 3 个字母的单词

[mysqld]
ft_min_word_len=1
ft_stopword_file=/var/lib/mysql/stopwords.txt

最后重启mysql

service mysql restart

如果您有任何已存在 FULLTEXT 索引的表,则必须删除这些 FULLTEXT 索引并重新创建它们。

绕过选项2)重新编译源代码

文件名为 storage/myisam/ft_static.c。只需更改包含 600 多个单词的 C 结构,使其为空。重新编译开心!!!

现在 FULLTEXT 配置已经固化,这是另一个需要考虑的主要方面:

编写适当的重构查询,以便 MySQL 查询优化器正常工作!!!

我现在提到的实际上没有记录:每当您执行执行 JOIN 的查询并且 WHERE 子句包含用于 FULLTEXT 搜索的 MATCH 函数时,它往往会导致 MySQL 查询优化器在查询时将查询视为全表扫描开始搜索 FUL​​LTEXT 索引中涉及的列。如果您计划使用 FULLTEXT 索引查询表,ALWAYS refactor your query to have the FULLTEXT search return only keys in a subquery and connect those keys to your main table。否则,FULLTEXT 索引将使 MySQL 查询优化器陷入混乱。

【讨论】:

  • 选项一总是一个好主意,因为每个语料库(要查询的文本元素的集合)都有自己的停用词要求以及查询的目标。
  • 选项二不是一个好主意,原因有很多,其中最重要的原因是在推荐的过程之后,您将运行自定义的、不可升级的 Mysql 版本。
【解决方案3】:

有关 MySQL 中全文搜索优化的更多想法,请参阅How to optimize MySQL Boolean Full-Text Search? (Or what to replace it with?) - C#

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-19
    • 1970-01-01
    • 2010-12-01
    • 2019-05-16
    • 2011-09-24
    • 1970-01-01
    • 2018-01-19
    相关资源
    最近更新 更多