INDEX

  由于性能、智能结果等多方面原因,在搜索文本时,全文搜索一般要优于通配符和正则表达式,前者为指定列建立索引,以便快速找到对应行,并且将结果集智能排序。启用查询扩展可以让我们得到未必包含关键字的相关行,启用布尔模式可以让我们指定搜索内容不应包含的单词、各个关键词的权重等。

  全文索引使用说明。

  不要在导入数据前进行全文索引。

WARNING

不是所有数据库引擎都支持全文搜索。MyISAM 支持全文索引,InnoDB 不支持全文索引。

PS. 据说 MySQL 5.6 以上版本的 InnoDB 支持全文索引,语法格式和 MyISAM 的全文索引类似。

Understanding Full-Text Searching

通配符和正则表达式都很强大,但是它们有几个很严重的缺点:

  • 性能:通配符和正则表达式总是和表中的每一行匹配,因此当行数增加时这两种匹配方式非常耗时。
  • 精确控制:通配符和正则表达式很难精确控制匹配什么不匹配什么。
  • 智能结果:例如说,不论字段内容中有一个匹配还是多个匹配,通配符和正则表达式都一视同仁的返回该行;如果字段内容不包含匹配,但包括相关(相近)词不会返回该行。

上述的缺点都可以通过全文索引来解决。当使用全文搜索的时候, MySQL 不需要单独地匹配每行,而是创建单词(在指定的列中)的索引,这样 MySQL 就可以快速而有效地确定哪些词匹配,哪些不匹配等等。

可以理解为 MySQL 为指定列生成了一个目录,该目录标注了 包含 xxx 单词的行是第1、4、8、9行(假设),借助这个目录,搜索 xxx 单词时就可以很快找到对应行1、4、8、9了,类似于用空间换取时间。

Using Full-Text Searching

CREATE TABLE productnotes
(
note_id int NOT NULL AUTO_INCREMENT,
prod_id char(10) NOT NULL,
note_date datetime NOT NULL,
note_text text NULL ,
PRIMARY KEY(note_id),
FULLTEXT(note_text)
) ENGINE=MyISAM;

PS. 全文索引多个字段也是可以的!

一旦定义了全文索引,MySQL 会自动维护这个索引,当增加记录、删除记录,索引会相应的变化

Don't Use FULLTEXT When Importing Data

Updating indexes takes timenot a lot of time, but time nonetheless. If you are importing data into a new table, you should not enable FULLTEXT indexing at that time. Rather, first import all of the data, and then modify the table to define FULLTEXT. This makes for a much faster data import (and the total time needed to index all data will be less than the sum of the time needed to index each row individually).

Performing Full-Text Searches

mysql> SELECT note_text
-> FROM productnotes
-> WHERE Match(note_text) Against('rabbit');
+----------------------------------------------------------------------------------------------------------------------+
| note_text |
+----------------------------------------------------------------------------------------------------------------------+
| Customer complaint: rabbit has been able to detect trap, food apparently less effective now. |
| Quantity varies, sold by the sack load.
All guaranteed to be bright and orange, and suitable for use as rabbit bait. |
+----------------------------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)

Match(colunm_name必须和定义为 FULLTEXT的列一致) 和 Against('xxx') ,记住这两个函数!另外,搜索是大小写不敏感的!

事实上,利用通配符也可以很方便地达到上面的效果,不过性能和结果都会有不同:

mysql> SELECT note_text
-> FROM productnotes
-> WHERE note_text LIKE '%rabbit%';
+----------------------------------------------------------------------------------------------------------------------+
| note_text |
+----------------------------------------------------------------------------------------------------------------------+
| Quantity varies, sold by the sack load.
All guaranteed to be bright and orange, and suitable for use as rabbit bait. |
| Customer complaint: rabbit has been able to detect trap, food apparently less effective now. |
+----------------------------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)

我们很震惊地发现,虽然行数是没错,不过顺序却不一致 。 。 。

这是因为 全文搜索有一个重要特性:结果排名(the ranking of results),排名高的优先返回。查看列的排名:

SELECT note_text,
Match(note_text) Against('rabbit') AS rank
FROM productnotes;

rank 越高的排名越前,这个与关键字出现与否、出现在前面还是后面等因素有关。

Using Query Expansion

When query expansion is used, MySQL makes two passes through the data and indexes to perform your search:

  • First, a basic full-text search is performed to find all rows that match the search criteria.

  • Next, MySQL examines those matched rows and selects all useful words (we'll explain how MySQL figures out what is useful and what is not shortly).

  • Then, MySQL performs the full-text search again, this time using not just the original criteria, but also all of the useful words.

Using query expansion you can therefore find results that might be relevant, even if they don't contain the exact words for which you were looking.

mysql> SELECT note_text
-> FROM productnotes
-> WHERE Match(note_text) Against('rabbit' WITH QUERY EXPANSION);
+----------------------------------------------------------------------------------------------------------------------------------------------------------+
| note_text |
+----------------------------------------------------------------------------------------------------------------------------------------------------------+
| Quantity varies, sold by the sack load.
All guaranteed to be bright and orange, and suitable for use as rabbit bait. |
| Customer complaint: rabbit has been able to detect trap, food apparently less effective now. |
| Customer complaint:
Circular hole in safe floor can apparently be easily cut with handsaw. |
| Customer complaint:
Sticks not individually wrapped, too easy to mistakenly detonate all at once.
Recommend individual wrapping. |
| Customer complaint:
Not heavy enough to generate flying stars around head of victim. If being purchased for dropping, recommend ANV02 or ANV03 instead. |
| Multiple customer returns, anvils failing to drop fast enough or falling backwards on purchaser. Recommend that customer considers using heavier anvils. |
+----------------------------------------------------------------------------------------------------------------------------------------------------------+
6 rows in set (0.00 sec)

Boolean Text Searches

SELECT note_text
FROM productnotes
WHERE Match(note_text) Against('+rabbit +bait"' IN BOOLEAN MODE);

更多操作参见原书第 18 章,通过各种符号来指明关键词优先级、包含什么单词、排除什么单词等。

Full-Text Search Usage Notes

重要的说明:

  1. MySQL 不会给短单词建立索引,短单词默认定义为三个字母以内的。
  2. MySQL 有一个内建的停用词列表,它的下场和短单词一样,当然这个也是可以手动修改的,具体方法可以搜索资料、查查文档。
  3. 许多单词出现频繁,以至于搜索它们将毫无用处(返回的结果太多)。 因此,MySQL授予50%的规则,一个单词出现在50%或更多的行中,它被视为一个停用词并被有效地忽略。 (50%的规则不用于IN BOOLEAN模式)。
  4. 如果表中的行少于三行(也就是两行或者两行以下,因为每个但凡出现的单词的出现次数总是至少为行数的50%),全文搜索不返回任何结果。
  5. 单词内的单引号会被忽略,例如 don't 的索引为 dont
  6. 没有单词分隔符(包括日语和中文)的语言将不会正确返回全文结果。

那么如何实现中文分词&全文索引呢?待更新

MySQL Crash Course #12# Chapter 18. Full-Text Searching的更多相关文章

  1. MySQL Crash Course #05# Chapter 9. 10. 11. 12 正则.函数. API

    索引 正则表达式:MySQL only supports a small subset of what is supported in most regular expression implemen ...

  2. MySQL Crash Course #13# Chapter 21. Creating and Manipulating Tables

    之前 manipulate 表里的数据,现在则是 manipulate 表本身. INDEX 创建多列构成的主键 自动增长的规定 查看上一次插入的自增 id 尽量用默认值替代 NULL 外键不可以跨引 ...

  3. MySQL Crash Course #11# Chapter 20. Updating and Deleting Data

    INDEX Updating Data The IGNORE Keyword Deleting Data Faster Deletes Guidelines for Updating and Dele ...

  4. MySQL Crash Course #10# Chapter 19. Inserting Data

    INDEX BAD EXAMPLE Improving Overall Performance Inserting Multiple Rows INSTEAD OF Inserting a Singl ...

  5. MySQL Crash Course #06# Chapter 13. 14 GROUP BY. 子查询

    索引 理解 GROUP BY 过滤数据 vs. 过滤分组 GROUP BY 与 ORDER BY 之不成文的规定 子查询 vs. 联表查询 相关子查询和不相关子查询. 增量构造复杂查询 Always ...

  6. MySQL Crash Course #04# Chapter 7. 8 AND. OR. IN. NOT. LIKE

    索引 AND. OR 运算顺序 IN Operator VS. OR NOT 在 MySQL 中的表现 LIKE 之注意事项 运用通配符的技巧 Understanding Order of Evalu ...

  7. MySQL Crash Course #21# Chapter 29.30. Database Maintenance & Improving Performance

    终于结束这本书了,最后两章的内容在官方文档中都有详细介绍,简单过一遍.. 首先是数据备份,最简单直接的就是用 mysql 的内置工具 mysqldump MySQL 8.0 Reference Man ...

  8. MySQL Crash Course #20# Chapter 28. Managing Security

    限制用户的操作权限并不是怕有人恶意搞破坏,而是为了减少失误操作的可能性. 详细文档:https://dev.mysql.com/doc/refman/8.0/en/user-account-manag ...

  9. MySQL Crash Course #17# Chapter 25. 触发器(Trigger)

    推荐看这篇mysql 利用触发器(Trigger)让代码更简单 以及 23.3.1 Trigger Syntax and Examples 感觉有点像 Spring 里的 AOP 我们为什么需要触发器 ...

随机推荐

  1. ubuntu16.04 下 卸载CUDA9.1

    网上很多教程删除都全  安装其他还会出错 在这把它删除,在命令行中输入 sudo apt-get remove cuda sudo apt-get autoclean sudo apt-get rem ...

  2. Oracle字符串连接的方法

    Oracle数据库中,使用“||”进行字符串连接,下面就让我们一起了解一下Oracle数据库中字符串连接的方法,希望对您能有所帮助. 和其他数据库系统类似,Oracle字符串连接使用“||”进行字符串 ...

  3. inaccessible

    $w = (object)array('key0'=>'a','key1'=>'b',0,1,2,0=>'0w',1=>'1w','11'=>'11str'); var_ ...

  4. Jmeter(十一)_针对响应信息不明确的接口做关联

    下午写一个新功能的接口脚本,遇到几个技术问题,现在将解决方案写出来 1:做接口关联的时候,发现接口响应没有可以利用的信息.如下图只返回了一个成功的标识,这样的接口如何与之关联? 通过抓包观察后续的修改 ...

  5. CentOS 7显卡驱动问题

    CentOS 7 KDE桌面安装后有时会出现nouveau 驱动问题,导致系统不定时死机或者重启,那么这时只能禁用nouveau 1. 在配置文件中禁用nouveauvi /etc/modprobe. ...

  6. Javascript异步执行时要小心的变量作用域

    function asyncFunction(callback){ setTimeout(function(){ callback() },200); } var color = 'blue'; // ...

  7. 把web项目部署到阿里云linux服务器上

    最近弄了个试用阿里云服务器倒腾了半天终于部署好,分享一下. 1.登入阿里云打开你申请的是云服务器的实例: 点击重置密码---重置密码后重启服务器才能生效(一般需要重置密码.这里设置的密码是使用xhel ...

  8. unity3d之 C# WaitFOrSeconds()

    学习unity3d不久.在使用WaitFOrSeconds()时,遇到了不少麻烦,故记录,以警示后人. 首先介绍C#和javascript 在使用它有非常大的差别. javascript能够直接使用 ...

  9. query:callback

    function getName(callback) { setTimeout(function() { callback('Aaron') }, 1000) } //等待callback回调 get ...

  10. 001-nginx基础配置-location

    一.基础语法 Location block 的基本语法形式是: location [=|~|~*|^~|@] pattern { ... } [=|~|~*|^~|@] 被称作 location mo ...