0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

MySQL5.6 InnoDB支持全文检索

jf_ro2CN3Fa 来源:稀土掘金 作者:_沸羊羊 2022-11-12 15:14 次阅读

前言

我们都知道 InnoDB 在模糊查询数据时使用 "%xx" 会导致索引失效,但有时需求就是如此,类似这样的需求还有很多,例如,搜索引擎需要根基用户数据的关键字进行全文查找,电子商务网站需要根据用户的查询条件,在可能需要在商品的详细介绍中进行查找,这些都不是B+树索引能很好完成的工作。

通过数值比较,范围过滤等就可以完成绝大多数我们需要的查询了。但是,如果希望通过关键字的匹配来进行查询过滤,那么就需要基于相似度的查询,而不是原来的精确数值比较,全文索引就是为这种场景设计的。

全文索引(Full-Text Search)是将存储于数据库中的整本书或整篇文章中的任意信息查找出来的技术。它可以根据需要获得全文中有关章、节、段、句、词等信息,也可以进行各种统计和分析。

在早期的 MySQL 中,InnoDB 并不支持全文检索技术,从 MySQL 5.6 开始,InnoDB 开始支持全文检索。

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

项目地址:https://gitee.com/zhijiantianya/ruoyi-vue-pro

视频教程:https://doc.iocoder.cn/video/

倒排索引

全文检索通常使用倒排索引(inverted index)来实现,倒排索引同 B+Tree 一样,也是一种索引结构。它在辅助表中存储了单词与单词自身在一个或多个文档中所在位置之间的映射,这通常利用关联数组实现,拥有两种表现形式:

inverted file index:{单词,单词所在文档的id}

full inverted index:{单词,(单词所在文档的id,再具体文档中的位置)}

9ebc324c-5c4e-11ed-a3b6-dac502259ad0.png倒排索引

上图为 inverted file index 关联数组,可以看到其中单词"code"存在于文档1,4中,这样存储再进行全文查询就简单了,可以直接根据 Documents 得到包含查询关键字的文档;而 full inverted index 存储的是对,即(DocumentId,Position),因此其存储的倒排索引如下图,如关键字"code"存在于文档1的第6个单词和文档4的第8个单词。

相比之下,full inverted index 占用了更多的空间,但是能更好的定位数据,并扩充一些其他搜索特性。

9ec8b8d2-5c4e-11ed-a3b6-dac502259ad0.png搜索特性

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

项目地址:https://gitee.com/zhijiantianya/yudao-cloud

视频教程:https://doc.iocoder.cn/video/

全文检索

创建全文索引

「1、创建表时创建全文索引语法如下:」

CREATETABLEtable_name(
idINTUNSIGNEDAUTO_INCREMENTNOTNULLPRIMARYKEY,
authorVARCHAR(200),
titleVARCHAR(200),
contentTEXT(500),
FULLTEXTfull_index_name(author,title,content)
)ENGINE=InnoDB;

输入查询语句:

SELECTtable_id,name,space
fromINFORMATION_SCHEMA.INNODB_TABLES
WHEREnameLIKE'test/%';
9ecfa980-5c4e-11ed-a3b6-dac502259ad0.png辅助索引表

上述六个索引表构成倒排索引,称为辅助索引表。当传入的文档被标记化时,单个词与位置信息和关联的DOC_ID,根据单词的第一个字符的字符集排序权重,在六个索引表中对单词进行完全排序和分区。

「2、在已创建的表上创建全文索引语法如下:」

CREATEFULLTEXTINDEXfull_index_nameONtable_name(col_name);

使用全文索引

MySQL 数据库支持全文检索的查询,全文索引只能在 InnoDB 或 MyISAM 的表上使用,并且只能用于创建 char,varchar,text 类型的列。

其语法如下:

MATCH(col1,col2,...)AGAINST(expr[search_modifier])
search_modifier:
{
INNATURALLANGUAGEMODE
|INNATURALLANGUAGEMODEWITHQUERYEXPANSION
|INBOOLEANMODE
|WITHQUERYEXPANSION
}

全文搜索使用 MATCH() AGAINST()语法进行,其中,MATCH() 采用逗号分隔的列表,命名要搜索的列。AGAINST()接收一个要搜索的字符串,以及一个要执行的搜索类型的可选修饰符。

全文检索分为三种类型:自然语言搜索、布尔搜索、查询扩展搜索,下面将对各种查询模式进行介绍。

Natural Language

自然语言搜索将搜索字符串解释为自然人类语言中的短语,MATCH()默认采用 Natural Language 模式,其表示查询带有指定关键字的文档。

接下来结合demo来更好的理解Natural Language

SELECT
count(*)AScount
FROM
`fts_articles`
WHERE
MATCH(title,body)AGAINST('MySQL');

9ef502ca-5c4e-11ed-a3b6-dac502259ad0.pngNatural Language

上述语句,查询 title,body 列中包含 'MySQL' 关键字的行数量。上述语句还可以这样写:

SELECT
count(IF(MATCH(title,body)
against('MySQL'),1,NULL))AScount
FROM
`fts_articles`;

上述两种语句虽然得到的结果是一样的,但从内部运行来看,第二句SQL的执行速度更快些,因为第一句SQL(基于where索引查询的方式)还需要进行相关性的排序统计,而第二种方式是不需要的。

还可以通过SQL语句查询相关性:

SELECT
*,
MATCH(title,body)against('MySQL')ASRelevance
FROM
fts_articles;
9efa8f6a-5c4e-11ed-a3b6-dac502259ad0.png

SQL语句查询相关性

相关性的计算依据以下四个条件:

word 是否在文档中出现

word 在文档中出现的次数

word 在索引列中的数量

多少个文档包含该 word

对于 InnoDB 存储引擎的全文检索,还需要考虑以下的因素:

查询的 word 在 stopword 列中,忽略该字符串的查询

查询的 word 的字符长度是否在区间 [innodb_ft_min_token_size,innodb_ft_max_token_size] 内

如果词在 stopword 中,则不对该词进行查询,如对 'for' 这个词进行查询,结果如下所示:

SELECT
*,
MATCH(title,body)against('for')ASRelevance
FROM
fts_articles;
9f0cd526-5c4e-11ed-a3b6-dac502259ad0.png

InnoDB 存储引擎的全文检索

可以看到,'for'虽然在文档 2,4中出现,但由于其是 stopword ,故其相关性为0

参数 innodb_ft_min_token_size 和 innodb_ft_max_token_size 控制 InnoDB 引擎查询字符的长度,当长度小于 innodb_ft_min_token_size 或者长度大于 innodb_ft_max_token_size 时,会忽略该词的搜索。

在 InnoDB 引擎中,参数 innodb_ft_min_token_size 的默认值是3,innodb_ft_max_token_size的默认值是84

Boolean

布尔搜索使用特殊查询语言的规则来解释搜索字符串,该字符串包含要搜索的词,它还可以包含指定要求的运算符,例如匹配行中必须存在或不存在某个词,或者它的权重应高于或低于通常情况。

例如,下面的语句要求查询有字符串"Pease"但没有"hot"的文档,其中+和-分别表示单词必须存在,或者一定不存在。

select*fromfts_testwhereMATCH(content)AGAINST('+Pease-hot'INBOOLEANMODE);

「Boolean 全文检索支持的类型包括:」

+:表示该 word 必须存在

-:表示该 word 必须不存在

(no operator)表示该 word 是可选的,但是如果出现,其相关性会更高

@distance表示查询的多个单词之间的距离是否在 distance 之内,distance 的单位是字节,这种全文检索的查询也称为 Proximity Search,如 MATCH(context) AGAINST('"Pease hot"[@30](https://my.oschina.net/u/3380933)' IN BOOLEAN MODE)语句表示字符串 Pease 和 hot 之间的距离需在30字节内

>:表示出现该单词时增加相关性

<:表示出现该单词时降低相关性

~:表示允许出现该单词,但出现时相关性为负

* :表示以该单词开头的单词,如 lik*,表示可以是 lik,like,likes

" :表示短语

下面是一些demo,看看 Boolean Mode 是如何使用的。

「demo1:+ -」

SELECT
*
FROM
`fts_articles`
WHERE
MATCH(title,body)AGAINST('+MySQL-YourSQL'INBOOLEANMODE);

上述语句,查询的是包含 'MySQL' 但不包含 'YourSQL' 的信息

9f1a0246-5c4e-11ed-a3b6-dac502259ad0.png

Boolean Mode

「demo2:no operator」

SELECT
*
FROM
`fts_articles`
WHERE
MATCH(title,body)AGAINST('MySQLIBM'INBOOLEANMODE);

上述语句,查询的 'MySQL IBM' 没有 '+','-'的标识,代表 word 是可选的,如果出现,其相关性会更高。

9f279b0e-5c4e-11ed-a3b6-dac502259ad0.png

相关性

「demo3:@」

SELECT
*
FROM
`fts_articles`
WHERE
MATCH(title,body)AGAINST('"DB2IBM"@3'INBOOLEANMODE);

上述语句,代表 "DB2" ,"IBM"两个词之间的距离在3字节之内

9f5192d8-5c4e-11ed-a3b6-dac502259ad0.png

「demo4:> <」

SELECT
*
FROM
`fts_articles`
WHERE
MATCH(title,body)AGAINST('+MySQL+(>database

上述语句,查询同时包含 'MySQL','database','DBMS' 的行信息,但不包含'DBMS'的行的相关性高于包含'DBMS'的行。

9f56f912-5c4e-11ed-a3b6-dac502259ad0.png

相关性

「demo5: ~」

SELECT
*
FROM
`fts_articles`
WHERE
MATCH(title,body)AGAINST('MySQL~database'INBOOLEANMODE);

上述语句,查询包含 'MySQL' 的行,但如果该行同时包含 'database',则降低相关性。

9f5d09ec-5c4e-11ed-a3b6-dac502259ad0.png

降低相关性

「demo6:」 *

SELECT
*
FROM
`fts_articles`
WHERE
MATCH(title,body)AGAINST('My*'INBOOLEANMODE);

上述语句,查询关键字中包含'My'的行信息。

9f69b200-5c4e-11ed-a3b6-dac502259ad0.png

「demo7:"」

SELECT
*
FROM
`fts_articles`
WHERE
MATCH(title,body)AGAINST('"MySQLSecurity"'INBOOLEANMODE);

上述语句,查询包含确切短语 'MySQL Security' 的行信息。

9f735620-5c4e-11ed-a3b6-dac502259ad0.png

Query Expansion

查询扩展搜索是对自然语言搜索的修改,这种查询通常在查询的关键词太短,用户需要 implied knowledge(隐含知识)时进行,例如,对于单词 database 的查询,用户可能希望查询的不仅仅是包含 database 的文档,可能还指那些包含 MySQL、Oracle、RDBMS 的单词,而这时可以使用 Query Expansion 模式来开启全文检索的 implied knowledge

通过在查询语句中添加 WITH QUERY EXPANSION / IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION 可以开启 blind query expansion(又称为 automatic relevance feedback),该查询分为两个阶段。

第一阶段:根据搜索的单词进行全文索引查询

第二阶段:根据第一阶段产生的分词再进行一次全文检索的查询

接着来看一个例子,看看 Query Expansion 是如何使用的。

--创建索引
createFULLTEXTINDEXtitle_body_indexonfts_articles(title,body);
--使用NaturalLanguage模式查询
SELECT
*
FROM
`fts_articles`
WHERE
MATCH(title,body)AGAINST('database');

使用 Natural Language 查询结果如下:

9f9943e4-5c4e-11ed-a3b6-dac502259ad0.png

Natural Language 查询结果

--当使用QueryExpansion模式查询
SELECT
*
FROM
`fts_articles`
WHERE
MATCH(title,body)AGAINST('database'WITHQUERYexpansion);

使用 Query Expansion 后查询结果如下:

9fbe6c1e-5c4e-11ed-a3b6-dac502259ad0.png

Query Expansion 后查询结果

由于 Query Expansion 的全文检索可能带来许多非相关性的查询,因此在使用时,用户可能需要非常谨慎。

删除全文索引

「1、直接删除全文索引语法如下:」

DROPINDEXfull_idx_nameONdb_name.table_name;

「2、使用 alter table 删除全文索引语法如下:」

ALTERTABLEdb_name.table_nameDROPINDEXfull_idx_name;

小结

本文从理论与实践结合的角度对 fulltext index 做了介绍。






审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • IBM
    IBM
    +关注

    关注

    3

    文章

    1670

    浏览量

    74270
  • MySQL
    +关注

    关注

    1

    文章

    775

    浏览量

    25999
  • RBAC
    +关注

    关注

    0

    文章

    43

    浏览量

    9891

原文标题:MySQL 模糊查询再也不用like+%了

文章出处:【微信号:芋道源码,微信公众号:芋道源码】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    使用mysql出现Access denied for user 'root'@'localhost' (us,请问如何解决?

    ; 如果MySql5.6操作时报错: You must SET PASSWORD before executing this statement 请执行下面的命令解决: mysql>SET
    发表于 07-03 03:07

    使用mysql的时出现Access denied for user 'root'@'localhost' (us错误,请问这是为什么?如何解决?

    ; 如果MySql5.6操作时报错: You must SET PASSWORD before executing this statement 请执行下面的命令解决: mysql>SET
    发表于 07-09 09:29

    使用docker安装的mysql5.6实例的恢复方法

    2018-12-23 从aliyun的drs全备恢复数据库到docker的mysql
    发表于 03-14 11:26

    详解Mysql数据库InnoDB存储引擎事务

    关于Mysql数据库InnoDB存储引擎事务的一点理解
    发表于 05-13 10:11

    InnoDB锁的特点和状态查询

    MySQL探秘(五)InnoDB锁的类型和状态查询
    发表于 08-07 11:45

    分布式MySQLInnoDB cluster

    分布式MySQL——InnoDB cluster和性能测试
    发表于 04-15 08:43

    全文检索技术实现的原理

    全文检索技术原理
    发表于 06-03 07:05

    MySQL存储引擎简析

    MySQL存储引擎InnoDB  InnoDB 的存储文件有两个,后缀名分别是.frm和.idb,其中.frm是表的定义文件,而.idb是数据文件。InnoDB 中存在表锁和行锁,不过
    发表于 09-06 06:07

    基于压缩倒排文件的中文全文检索仿真系统

    探讨基于压缩倒排文件的中文全文检索技术,包括数据压缩方法、存储、检索与排名机制。借助中科院的高精度ICTCLAS中文分词系统,采用C++/STL语言仿真实现了一个中文全文
    发表于 04-23 10:15 28次下载

    开放源代码的全文检索引擎 Lucene

    开放源代码的全文检索引擎 Lucene――介绍、系统结构与源码实现分析 第一节 全文检索系统与Lucene简介 一、    
    发表于 02-10 15:09 5次下载

    Windows下MySQL 5.6安装及配置详细图解

    讲解Windows下MySQL 5.6安装及配置详细图解,图文并茂,方便大家安装
    发表于 12-09 16:00 0次下载

    MySql5.6性能优化最佳实践

    MySql5.6性能优化最佳实践
    发表于 09-08 08:47 13次下载
    <b class='flag-5'>MySql5.6</b>性能优化最佳实践

    最有用的mysql问答

    想进大厂,mysql不会那可不行,来接受mysql面试挑战吧,看看你能坚持到哪里? 1. 能说下myisam 和 innodb的区别吗? myisam引擎是5.1版本之前的默认引擎,支持
    的头像 发表于 09-30 17:43 1512次阅读
    最有用的<b class='flag-5'>mysql</b>问答

    MySQL中的InnoDB是什么?

    有许多强大的MySQL存储引擎可供我们使用,而InnoDB无疑是最受欢迎的存储引擎之一。它高度可靠和高效,因此它成为5.5版本以后所有MySQL的默认存储引擎也就不足为奇了。
    的头像 发表于 04-13 09:09 507次阅读

    记一次SQL优化经历

    用的数据库是mysql5.6,下面简单的介绍下场景。
    的头像 发表于 09-11 14:39 240次阅读
    记一次SQL优化经历