mysql中的全文本搜索用在啥情况下?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mysql中的全文本搜索用在啥情况下?相关的知识,希望对你有一定的参考价值。

如题,mysql中的全文本搜索用在什么情况下?

在老版本的MySQL 3.22中,MySQL的单表限大小为4GB,当时的MySQL的存储引擎还是ISAM存储引擎。但是,当出现MyISAM存储引擎之后,也就是从MySQL 3.23开始,MySQL单表最大限制就已经扩大到了64PB了(官方文档显示)。也就是说,从目前的技术环境来看,MySQL数据库的MyISAM存储 引擎单表大小限制已经不是有MySQL数据库本身来决定,而是由所在主机的OS上面的文件系统来决定了。

  而MySQL另外一个最流行的存储引擎之一Innodb存储数据的策略是分为两种的,一种是共享表空间存储方式,还有一种是独享表空间存储方式。
  当使用共享表空间存储方式的时候,Innodb的所有数据保存在一个单独的表空间里面,而这个表空间可以由很多个文件组成,一个表可以跨多个文件存在,所 以其大小限制不再是文件大小的限制,而是其自身的限制。从Innodb的官方文档中可以看到,其表空间的最大限制为64TB,也就是说,Innodb的单 表限制基本上也在64TB左右了,当然这个大小是包括这个表的所有索引等其他相关数据。
  而当使用独享表空间来存放Innodb的表的时候,每个表的数据以一个单独的文件来存放,这个时候的单表限制,又变成文件系统的大小限制了。
参考技术A 全文检索在MySQL里面很早就支持了,只不过一直以来只支持英文。缘由是他从来都使用空格来作为分词的分隔符,而对于中文来讲,显然用空格就不合适,需要针对中文语义进行分词。这不,从MySQL5.7开始,MySQL内置了ngram全文检索插件,用来支持中文分词,并且对MyISAM和InnoDB引擎有效。

在使用中文检索分词插件ngram之前,先得在MySQL配置文件里面设置他的分词大小,比如,
[mysqld]
ngram_token_size=2

这里把分词大小设置为2。要记住,分词的SIZE越大,索引的体积就越大,所以要根据自身情况来设置合适的大小。

示例表结构:
CREATE TABLE articles (
id INTUNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
titleVARCHAR(200),
body TEXT,
FULLTEXT (title,body) WITH PARSER ngram
) ENGINE=InnoDBCHARACTER SET utf8mb4;

示例数据,有6行记录。
mysql> select * from articles\G
***************************1. row ***************************
id: 1
title: 数据库管理
body: 在本教程中我将向你展示如何管理数据库
***************************2. row ***************************
id: 2
title: 数据库应用开发
body: 学习开发数据库应用程序
***************************3. row ***************************
id: 3
title: MySQL完全手册
body: 学习MySQL的一切
***************************4. row ***************************
id: 4
title: 数据库与事务处理
body: 系统的学习数据库的事务概论
***************************5. row ***************************
id: 5
title: NoSQL精髓
body: 学习了解各种非结构化数据库
***************************6. row ***************************
id: 6
title: SQL 语言详解
body: 详细了解如果使用各种SQL
6 rows inset (0.00 sec)

显式指定全文检索表源
mysql> SETGLOBAL innodb_ft_aux_table="new_feature/articles";
Query OK, 0 rows affected (0.00 sec)

通过系统表,就可以查看到底是怎么划分articles里的数据。
mysql> SELECT *FROM information_schema.INNODB_FT_INDEX_CACHE LIMIT 20,10;
+------+--------------+-------------+-----------+--------+----------+
| WORD | FIRST_DOC_ID | LAST_DOC_ID | DOC_COUNT | DOC_ID| POSITION |
+------+--------------+-------------+-----------+--------+----------+
| 中我 | 2 | 2 | 1 | 2 | 28 |
| 习m | 4 | 4 | 1 | 4 | 21 |
| 习了 | 6 | 6 | 1 | 6 | 16 |
| 习开 | 3 | 3 | 1 | 3 | 25 |
| 习数 | 5 | 5 | 1 | 5 | 37 |
| 了解 | 6 | 7 | 2 | 6 | 19 |
| 了解 | 6 | 7 | 2 | 7 | 23 |
| 事务 | 5 | 5 | 1 | 5 | 12 |
| 事务 | 5 | 5 | 1 | 5 | 40 |
| 何管 | 2 | 2 | 1 | 2 | 52 |
+------+--------------+-------------+-----------+--------+----------+
10 rows in set (0.00 sec)

这里可以看到,把分词长度设置为2,所有的数据都只有两个一组。上面数据还包含了行的位置,ID等等信息。
接下来,我来进行一系列检索示范,使用方法和原来英文检索一致。

1. 自然语言模式下检索:
A,得到符合条件的个数,
mysql>SELECT COUNT(*) FROM articles
-> WHERE MATCH (title,body) AGAINST ('数据库' IN NATURALLANGUAGE MODE);
+----------+
| COUNT(*) |
+----------+
| 4 |
+----------+
1 row in set (0.05 sec)

B,得到匹配的比率,

mysql>SELECT id, MATCH (title,body) AGAINST ('数据库' IN NATURAL LANGUAGE MODE)
AS score FROM articles;
+----+----------------------+
| id| score |
+----+----------------------+
| 1 | 0.12403252720832825 |
| 2 | 0.12403252720832825 |
| 3 | 0 |
| 4 | 0.12403252720832825 |
| 5 | 0.062016263604164124 |
| 6 | 0 |
+----+----------------------+
6rows in set (0.00 sec)

2. 布尔模式下搜索,这个就相对于自然模式搜索来的复杂些:
A,匹配既有管理又有数据库的记录,
mysql> SELECT * FROM articles WHERE MATCH (title,body)
-> AGAINST ('+数据库 +管理' IN BOOLEAN MODE);
+----+------------+--------------------------------------+
| id| title | body |
+----+------------+--------------------------------------+
| 1 | 数据库管理 | 在本教程中我将向你展示如何管理数据库
|
+----+------------+--------------------------------------+
1 rowin set (0.00 sec)

B,匹配有数据库,但是没有管理的记录,
mysql> SELECT * FROM articles WHERE MATCH (title,body)
-> AGAINST ('+数据库 -管理' IN BOOLEAN MODE);
+----+------------------+----------------------------+
| id| title | body |
+----+------------------+----------------------------+
| 2 | 数据库应用开发 | 学习开发数据库应用程序 |
| 4 | 数据库与事务处理 | 系统的学习数据库的事务概论 |
| 5 | NoSQL 精髓 | 学习了解各种非结构化数据库 |
+----+------------------+----------------------------+
3rows in set (0.00 sec)

C,匹配MySQL,但是把数据库的相关性降低,
mysql> SELECT * FROM articles WHERE MATCH (title,body)
-> AGAINST ('>数据库 +MySQL' INBOOLEAN MODE);
+----+---------------+-----------------+
| id| title | body |
+----+---------------+-----------------+
| 3 | MySQL完全手册 |学习MySQL的一切 |
+----+---------------+-----------------+
1 rowin set (0.00 sec)

3,查询扩展模式,比如要搜索数据库,那么MySQL,oracle,DB2也都将会被搜索到,

mysql> SELECT * FROM articles
-> WHERE MATCH (title,body)
-> AGAINST ('数据库' WITH QUERY EXPANSION);
+----+------------------+--------------------------------------+
| id| title | body |
+----+------------------+--------------------------------------+
| 1 | 数据库管理 | 在本教程中我将向你展示如何管理数据库
| 4 | 数据库与事务处理 | 系统的学习数据库的事务概论
| 2 | 数据库应用开发 | 学习开发数据库应用程序 |
| 5 | NoSQL 精髓 | 学习了解各种非结构化数据库 |
| 6 | SQL 语言详解 | 详细了解如果使用各种SQL|
| 3 | MySQL完全手册 | 学习MySQL的一切 |
+----+------------------+--------------------------------------+
6rows in set (0.01 sec)

当然,我这里只是功能演示,更多的性能测试,大家有兴趣可以进行详细测试。由于N-grm是中文检索常用的分词算法,已经在互联网大量使用,这次集成到mysql中,想必效果上不会有太大的问题。

mysql 文本搜索

全文本搜索

MySQL支持几种基本的数据库引擎,但并非所有的引擎都支持全文本搜索。两个最常使用的引擎为MyISAM和InnoDB,前者支持全文本搜索,后者就不支持。

理解全文本搜索

在前面的学习中,我们都知道有两种方式来匹配文本。一种是使用like关键字来进行匹配,另外一种就是使用正则表达式来进行匹配。

虽然使用正则表达式就可以编写查找所需行的足够复杂的匹配模式。但是,这些存在几个重要的限制影响:

1、性能:通配符和正则表达式时尝试匹配表中所有行,而这些搜索极少使用了表索引,因此,相当慢

2、明确控制:在匹配过程中,我们很少会相当的明确的知道我们想匹配什么,不匹配什么。

3、具有优先级的结果:在使用通配符和正则表达式进行匹配时,只是返回包含该匹配条件的结果,而不区分匹配程度(多个匹配和单个匹配的区别,在前面就匹配和在后面匹配的区别)。

上面提到的这些限制,都可以利用全文本搜索来进行解决。

使用全文本搜索

为了进行全文本搜索,必须索引被搜索的列,而且要随着数据的改变不断地重新索引。

在对表进行适当的设计之后,MySQL会自动进行所有的索引和重新索引。

在索引之后,select可与match() 和against()一起使用以实际执行索引。

那么,在建表的时候,如何启用全文本搜索支持呢???

如下: 
技术分享

上面就这样通过fulltext 为指定行建立的相应的索引,如果,想指定多个列,将多个列都放入fulltext里面即可。

在定义之后,MySQL会自动维护该索引。无论是在增加、更新还是删除,索引也会随之更新。

进行全文本搜索

上面在建表后此表就有了全文本搜索的能力了,下面我们开始尝试下全文本搜索。 
在索引之前,我为test_text表增加了如下内容: 
技术分享

当我们想利用全文本搜索得到 包含MySQL内容的数据。

如下:

select * from test_text where match(content) against(‘MySQL‘);

上面语句中 match(content) 指示MySQL针对指定的列进行搜索,注意:传递给match()的值必须与fulltext()定义中的相同。against(‘MySQL’)指定词MySQL作为搜索文本。

技术分享

从结果可以看出,我们得到了两行包括MySQL字符串的数据。

上面的搜索利用我们学过的Like也可以完成,如下:

技术分享

这两种方法的结果是一样的。次序也一样,理论上来说,利用全文本搜索会对出来的结果按照优先级来进行排序输出,但是从结果可以看出,在第一条语句中MySQL出现的位置相比第二条语句中的MySQL的位置还要滞后,为什么会出现在前面呢??,与MySQL必知必会上面介绍的有一点出入

为了验证上面出现的问题,我们可以查下结果的优先级。在查看优先级之前,我又加入了一个以MySQL开头的行数据。下面举来看下优先级。

select id,content,match(content) against(‘MySQL‘) from test_text ;

技术分享

从结果可以看出,确实是id=7的行的优先级大于id=8的优先级,原因在于优先级并不至于出现的先后位置有关系,还与诸如文本长度等因素也有关系。 

在增加了一行以MySQL开头的行数据之后,我们来一起观察下上面这两种方法的结果。

技术分享

技术分享

从上面两图可以明显看出,确实,利用全文本搜索对搜索到的内容进行一定的排序,而通配符却没有进行排序。至于全文本搜索对搜索到的内容进行排序由很多因素来进行决定,比如:出现的位置、出现的次数、文本自身的长度等等。

等级越高,出现的位置就越靠前,在我们生活中使用的搜索引擎(例如百度、google等)进行搜索东西的时候,我相信也是按照这样的逻辑来出现结果,当然除了百度公司收了别人钱把不匹配的内容人为的放在更前面。

使用查询扩展:with query expansion

前面介绍的只是普通的全文本搜索。

但是,我们在生活中常常有更严格的要求,例如,我希望搜索 的内容包括MySQL字符串,你还想得到与MySQL相关的内容(即使没有出现MySQL字眼),应该怎么来做呢??

这就需要我们使用查询扩展了。

用法 :在against(关键字 with query expansion) 即可 
技术分享

从结果可以看出,当我们使用了查询扩展之后,就得到了更多相关的内容,即使这些内容不包括MySQL字眼。

至于MySQL是如何根据MySQL来得到与之相关的关键字,目前我还不清楚。

布尔文本搜索

MySQL支持全文本搜索的另外一种形式,称为布尔方式。以布尔方式,可以提供如下内容的细节:

  • 要匹配的词;
  • 要排斥的词、
  • 排列提示(指定某些词比其他词更重要,更重要的词等级更高)
  • 表达式分组。

要说明的是:即使没有fulltext索引也可以使用,只是速度相当相当的慢。

为显示 in boolean mode的作用,以一个简单的例子来进行说明。

select * from test_text where match(content) against(‘MySQL -interesting‘ in boolean mode);//返回必须包含MySQL不能包含interesting内容的数据。

技术分享

关于全文本布尔操作符,见下表(来源于:《MySQL必知必会》这本书)

技术分享

关于全文本布尔操作符的具体使用实例,与上面的例子类似,这里不在进行具体介绍。

全文本搜索的使用说明

1、MySQL带有一个内建的非用词列表。这些词在索引全文本数据时总是被忽略。如果需要,可以覆盖这个列表。

2、许多词出现的频率很高,搜索他们没有用处(因为返回太多的结果)。因此,MySQL规定了一条50%规则,如果一个词出现在50%以上的行中,则将它作为一个非用词忽略。50%规则不用于in boolean mode.

3、如果表中的数据的行数小于3行,则全文本搜索不返回结果。因此每个词要么不出现,出现就至少为50%。

4、忽略词中的单引号。例如:don’t 索引为dont。






以上是关于mysql中的全文本搜索用在啥情况下?的主要内容,如果未能解决你的问题,请参考以下文章

MySQL数据检索+查询+全文本搜索

Mysql基础第二十一天,全文本搜索

全文本搜索

全文本搜索

MySql学习之全文检索

MySQL ------ 全文本搜索( match和Against),以及查询扩展和 布尔方式(十七)