如何使用 MySQL 做全文检索这件事

MySQL 全文检索的实现 这有朋友聊到他们的系统中要接入全文检索,这让我想起了很久以前为一个很古老的项目添加搜索功能的事儿。一提到全文检索,我们首先就会想到搜索引擎。也就是用一个词、一段文本搜索出匹配的内容。一般这种技术都有对应的实现方式,ES(ElasticSearch)就是专门干这个的,如果你们的业务中明确需要全文检索,或者简单一点说,需要根据关键词搜索出匹配的内容,那就直接用 ES 就好了。无论你怎么调研,都不推荐使用 MySQL 实现这种需求,显而易见,MySQL 作为关系型数据库,本身就不适合做搜索这种需求。 阅读详情

​前言

这有朋友聊到他们的系统中要接入全文检索,这让我想起了很久以前为一个很古老的项目添加搜索功能的事儿。

一提到全文检索,我们首先就会想到搜索引擎。也就是用一个词、一段文本搜索出匹配的内容。一般这种技术都有对应的实现方式,ES(ElasticSearch)就是专门干这个的,如果你们的业务中明确需要全文检索,或者简单一点说,需要根据关键词搜索出匹配的内容,那就直接用 ES 就好了。

无论你怎么调研,都不推荐使用 MySQL 实现这种需求,显而易见,MySQL 作为关系型数据库,本身就不适合做搜索这种需求。

但是,奈何,今天我们就要用 MySQL 来做这件事儿。

背景

有一个很古老的业务采集了大量的信息,当然是合法采集了。系统用的人已经不多了,并且在平稳地运行,那就不要动它了就好了嘛。可偏偏为数不多的人非要加一个搜索功能,根据一个关键词来搜索。

这项目直接没接触过,咱也不敢随意改呀,通过和少有的还有了解这个系统的同事沟通,发现有一类角色本来就有搜索功能,只不过这功能基本没法用,从来搜不出内容。现象就是点完搜索按钮,后台接口就一直 pending,不用说了,那肯定是因为数据量太大了,或者某种很傻的原因,比如直接在大数据量、大段文本的字段中使用了 like模糊查询。

经过一番查看,发现这个准备要支持搜索的字段是 text类型的, 字段本身是不参与业务计算的,只是用来展示。而要搜索的内容还不止一个字段,好几个字段,这些字段的内容是什么呢,就是一段描述内容,里面有各种各样的专业名词,每一行记录中这个字段最大长度可能有几十到上千个字不等。

这张表由于数据量较大,并且字段很多,所以进行了分表,根据某个上层类型进行拆分,这样分出来的表,大的有上百万,小的有几十万。业务运算的时候,也是固定类型后,在这个类型下的分表中进行增删改查。

一看代码,果然,一条查询好几个 like,在几十万数据量的表中like好几个字段,不慢才怪,能查出来就是奇迹了。

于是勇敢地在数据库中尝试了一下一条查询的完整 SQL,在10分钟之后,还是果断结束了任务,一条SQL执行10分钟,就算用户能接受,我们自己也接受不了,好不好。

分析并思考解决方案

有需求就要处理,这种搜索的需求很明显就要用 ES 嘛,下载ES,准备本地搭建环境。

开玩笑的,加上 ES 不知道何年何年了,况且这么老的项目,能少动就少动,能不碰就不碰。这个法则,每个程序员都应该掌握。

思考

如果用户想要的不是通过任意关键字检索,而是通过指定一些我们为他预设好的关键词查询,就类似于抽出一些标签,可以按照标签组合搜索,那可以将需要搜索的字段中的内容拿出来分词、归类,抽取出相关的标签。这又是分词、又是分析的,想想也不比直接上 ES 简单。

还好,用户不想要这种的,就要不做限制,直接用关键词搜索。

务实主义

目前的处境是这样的:

1、不要做大的改动,因为项目老旧,并且不熟悉,用的人也不多了;

2、逻辑很明晰,就是模糊查询,但是目前性能极低;

3、直接在 MySQL 层做优化,确实是有办法的,具体效果只能试过之后才知道;

直接的优化手段其实也是非常简单的,MySQL 5.6版本后,MyISAM 和InnoDB 引擎已经全部支持全文索引了。还好,目前使用的数据库在5.6版本之后。

为了演示,我将最小的一张 296,560 表缩小了10倍变成了 2万9千多条,没有做任何处理,直接在一个最长的 text类型的字段上做 like查询,最后的查询时间是 1秒左右,偶尔慢的时候能达到2、3秒。

select * from case_data where case_name like '%侵权责任%'; 复制代码

用explain分析一下,发现是全表扫描。

​这只是查询了将近3万条数据,并且只查询了一个字段,并且没有其他逻辑,真实环境中的逻辑要复杂得多。

全文索引简单原理

MySQL 5.6之后的版本支持对 char、varchar、text 类型的字段创建全文索引。

当添加了全文索引之后,数据库引擎就会对添加索引的列进行语法语义的分析,并对它进行分词,之后对这些分出的短语进行索引,每个短语对应包含它的行的集合。

短语

包含的行的集合

合同

第1行、第5行、第10行、第n行

项目管理

第2行、第3行、第22行、第1999行、第n+1行

产品研发

第500行、第3899行、第8899行、第n+2行

这样当我们搜索某个关键词后,如果正好对应了某个短语,就可以直接命中包含它的行。

有几个参数是控制全文索引的, ft(FullText) 开头的。用下面的命令可以查看。

show variables like '%ft%' 复制代码

​ft_boolean_syntax

表示布尔查询时的可以用的符号,改变IN BOOLEAN MODE的查询字符,一会儿下面会演示用法。

innodb_ft_min_token_size

对与 innodb 引擎,最短的索引字符串,默认值为84,修改后要重建索引

innodb_ft_max_token_size

对与 innodb 引擎,最长的索引字符串,默认值为3,修改后要重建索引

创建全文检索

下面这两种方式都可以对已经存在地表创建全文索引。

CREATE FULLTEXT INDEX <index_name> on tableName(字段名); ALTER TABLE tableName ADD FULLTEXT <index_name>(字段名); 复制代码

当然,如果你不想用SQL语句创建,也可以直接使用客户端工具创建。

比如我测试用的这个表叫做 case_data,要支持全文检索的字段叫做 case_name,使用下面的 SQL 创建索引,索引名称为 inde_case_name。

ALTER TABLE case_data ADD FULLTEXT index_case_name(`case_name`); 复制代码

创建索引的过程比较缓慢,对于大数据量的表更慢,尤其是全文索引,这3万条数据对这一个字段创建索引的过程差不多10秒钟左右,如果是线上正在使用的服务,创建这种耗时索引就要酌情考虑一下什么时机创建比较合适了。

再次查询测试性能

全文索引创建好之后,就可以测试一下效果如何了,执行一下,等着见证奇迹。

select * from case_data where case_name like '%侵权责任%'; 复制代码

咦,怎么不仅没快,反而慢了一点儿。

​别慌,姿势不太对。全文索引有专门对应的查询关键字。使用 match和against配合查询,match 表示要匹配的列名称,against 表示要查询的关键词。比如下面这样:

select * from case_data where match(case_name) against('侵权责任'); 复制代码

确实是快了,通过分析可以看出已经开始走全文索引了,扫描的行数已经是常数行了。

​但是,一顿操作猛如虎,一看结果啥都没有啊。

因为全文检索是有精度的,是按照分词出来的关键词进行完全匹配的,也就是说当前的分词短语中并不存在侵权责任这个词,但是可能存在人身侵权责任、无故侵权责任人等短语。最简单的办法就是在查询侵权责任这个短语时,也要命中人身侵权责任、无故侵权责任人这两个短语,又类似于模糊查询了。

怎么办呢,这样写就可以了。

select * from case_data where match(case_name) against('*侵权责任*' in boolean mode); 复制代码

这样再次查询,结果就出来了。为什么会这样呢,前面我们提到一个变量,叫做ft_boolean_syntax,这个变量中的符号就类似于正则表达式里支持的规则符号。

常见的匹配模式有下面这些:

空格:可选的,包含该词的顺序较高

"text":全词匹配查找

text*:通配符查找,*只能放在后面

+text:必须包含,+只能放在词前面

-text:必须不包含,不能单独使用,如`+aaaa-cccc

>text:如果含有该词,提高词的相关性

<text:如果含有该词,降低词的相关性

():条件组,如aaaa+(bbbb cccc)表示必须包含 bbbb 或 cccc

本来就叫全文检索了,结果又整个模糊查找,一点儿也不彻底呀,还有没有别的办法了。

有一个,在5.7版本开始就内置了中文分词插件 ngram,我们将刚才创建的索引删掉,然后重新用 ngram做分词重新建立索引。

ALTER TABLE case_data ADD FULLTEXT index_case_name(`case_name`) WITH PARSER ngram; 复制代码

等个十几秒中,然后再执行第一次差不到数据的SQL。

select * from case_data where match(case_name) against('侵权责任'); 复制代码

再看查询结果,已经有数据了。

性能提升

我的测试数据只有2万多条,这种少量数据的情况下,性能是看不到提升的。并且还由于创建了索引,增大了存储空间。

但是将数据量提升十倍,到二十多万,会看到性能明显提升了几十倍。我在线上测试了 200万的表,用全文索引的方式0.5秒内能出结果,用 like 的话,喝完一杯茶,发现还在跑着。

因为全文检索本来就是适用于大数据量的场景,所以对于小样本的数据量,直接用 like也查不到哪儿去。

对于大数据量的场景,如果不引入ES等全文检索的中间件的情况下,用全文索引可以说是最快最划算的方式了。

MySQL 5.7 中文全文检索ngram使用总结 在MySQL 5.7.6之前,全文索引只支持英文全文索引,不支持中文全文索引,需要利用分词器把中文段落预处理拆分成单词,然后存入数据库。 从MySQL 5.7.6开始,MySQL内置了ngram全文解析器,用来支持中文、日文、韩文分词。 本文使用的MySQL 版本是5.7.22,InnoDB数据库引擎。 ngram全文解析器 ngram就是一段文字里面连续的n个字的序列。ngram全文解析器能... 阅读详情

相关推荐

Unipush2.0 App消息推送(在线+离线推送)

使用unipush2.0进行消息推送,包含在线跟离线

weixin_50251467的博客 3699

如何使用 MySQL 全文检索

全文检索是一种专门为处理文本数据而设计的查询技术,能够快速地从大量文本数据中查找和提取相关信息。与传统的 LIKE 查询相比,全文检索不仅速度更快,还支持更复杂的搜索功能,例如布尔模式搜索。MySQL 从版本 5.6 开始支持 InnoDB 上的全文索引,5.7.6 开始,内置了 ngram 全文解析器。

全球首个被优快云气死的程序员:阿小信 816

鼎捷T100二次开发实战:如何给开窗功能加上权限锁(附完整代码)

本文详细解析了鼎捷T100二次开发中开窗功能权限锁的实现方法,提供了两种技术方案:开窗程序重构法和动态WHERE条件注入法,并附上完整代码示例。通过真实案例,帮助开发者解决数据权限细粒度控制的难题,提升ERP系统的安全性和实用性。

weixin_28454475的博客 442

MySQL 的全文搜索功能详解

MySQL 的全文搜索功能允许用户在数据库表中的文本列中进行复杂的文本搜索。它可以快速找到包含特定关键词或短语的记录,而无需进行逐行的字符串匹配。这对于处理大量文本数据的应用程序来说非常有用,比如博客平台、新闻网站、文档管理系统等。例如,在一个博客系统中,使用全文搜索功能可以快速找到包含特定主题关键词的文章,为用户提供更高效的搜索体验。MySQL 的全文搜索功能为处理文本数据提供了强大的工具。通过开启全文索引并使用语句,我们可以快速、高效地在数据库中进行复杂的文本搜索。

我爱娃哈哈的专栏 2353

用 ABAP RAP + XCO 把 Excel 导入业务对象:从弹窗 Action 到 EML 落库与附件清理的完整实践

摘要:本文介绍了在SAP RAP框架下实现Excel批量导入功能的完整方案。通过XCO库的XLSX模块解析Excel文件,结合RAP的行为定义和Fiori Elements界面集成,构建了一个支持试运行、数据校验和自动合并的业务导入功能。方案采用RAP标准范式,包括Action参数设计、EML事务处理、附件管理以及异常消息反馈,实现了从文件上传到数据落库的端到端流程,既保证了系统稳定性,又提升了业务用户体验。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 276

使用R语言实现循环神经网络RNN进行文本生成

首先,让我们回顾一下循环神经网络(Recurrent Neural Networks,RNN)的基本概念。RNN是一种深度学习技术,特别适合处理序列数据,如时间序列和文本数据。RNN的关键特性是它的隐藏状态,这个状态可以捕捉到当前输入之前的信息。这使得RNN能够利用前面的信息来影响后续的输出,从而对序列数据进行有效的处理。

斌擎科技 725

MySQL中的全文检索功能如何使用?

全文检索就像是我们在一本书里查找某个关键词,想要找到这个词出现的所有位置。在MySQL中,全文检索可以帮助我们在大量的文本数据中快速找到包含特定关键词的记录。

长风破浪会有时的博客 820

水文仿真软件:HEC-RAS (Hydrologic Engineering Center‘s River Analysis System)_(7).一维非稳态水力模型

自定义脚本是通过编程语言(如 Python)编写的一系列自动化任务,可以帮助用户更高效地处理数据和运行模型。编写脚本:使用 Python 或其他编程语言编写自定义脚本。集成脚本:将脚本集成到 HEC-RAS 中,实现自动化数据处理和模型运行。

kkchenjj的博客 932

如何使用全文索引

在MySQL中,全文索引(Full-Text Index)主要用于对文本字段进行全文搜索,它对于像LIKE '%keyword%'这样的模式匹配查询特别有用,因为传统的B树索引在处理这种前缀未知的查询时效率很低。这里,'40’是你想要搜索的关键词。总之,虽然全文索引是处理文本字段全文搜索的强大工具,但在决定是否使用它之前,你需要仔细评估你的具体需求、数据模型和查询模式。对于像car_number这样的短字段,全文索引的效果可能不如预期,因为全文索引主要是为处理长文本和复杂的自然语言查询而设计的。

m0_50272029的博客 584

正确解决Authentication plugin ‘caching _sha2_password’ cannot be loaded:异常的有效解决方法

正确解决Authentication plugin ‘caching _sha2_password’ cannot be loaded:异常的有效解决方法

wbajsjhhhhh的博客 1万+

Docker(八):Docker Compose(容器编排) 管理多容器应用—实战案例演示

🟢 Docker(八):Docker Compose(容器编排) 管理多容器应用—实战案例演示

✨ 欢迎来到【Seal ^_^ 的优快云博客】!✨ 6万+

为什么MySQL不适合大数据文本检索

我们为什么不用MySQL作为大数据文本搜索,而是要选用搜索引擎,跟他们底层采用的结构有关系

凝神遐想的博客 730

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

mysql的全文检索

1.使用Mysql全文检索fulltext的先决条件 表的类型必须是MyISAM 建立全文检索的字段类型必须是char,varchar,text 2.建立全文检索先期配置 由于Mysql的默认配置是索引的词的长度是4,所以要支持中文单字的话,首先更改这个. *Unix用户要修改my.cnf,一般此文件在/etc/my.cnf,如果没有找到,先查找一下find / -name ‘my.cnf’ 在 [mysqld] 位置内加入: ft_min_word_len = 2 其它属性还有 ft_wordli

qq_38665250的博客 6381

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

总结用 MySQL 做全文检索功能时遇到的坑

全文检索 存储引擎 存储引擎记得设置为 InnoDB 创建倒排索引 ALTER TABLE 表名 ADD FULLTEXT INDEX 索引名称 (字段1,字段2,字段3) WITH PARSER ngram; 注意:后面要加上WITH PARSER ngram 才可以进行中文检索,ngram是一个全文解析器 且建立MySQL倒排索引时,尽量用一条语句去创建多个字段的倒排索引,比如你需要将三个...

马旭辉博客 3062

mysql 全文检索_MySQL全文检索

一、概述MySQL全文检索是利用查询关键字和查询列内容之间的相关度进行检索,可以利用全文索引来提高匹配的速度。二、语法MATCH (col1,col2,...) AGAINST (expr [search_modifier])search_modifier: {IN BOOLEAN MODE | WITH QUERY EXPANSION }例如:SELECT * FROM tab_name WHE...

weixin_31597865的博客 899

【MySQL技术内幕】32-全文检索

全文检索(Full-Text Search)是将存储于数据库中的整本书或整篇文章中的任意内容信息查找出来的技术。它可以根据需要获得全文中有关章、节、段、句、词等信息,也可以进行各种统计和分析。在之前的 MySQL数据库中, InnoDB存储引擎并不支持全文检索技术。大多数的用户转向 MyISAM存储引擎,这可能需要进行表的拆分,并将需要进行全文检索的数据存储为 MyISAM表。这样的确能够解决逻辑业务的需求,但是却丧失了 InnoDB存储引擎的事务性,而这在生产环境应用中同样是非常关键的。

smart_an的专栏 1444

mysql 中文全文检索_MySQL中文全文检索

一、概述MySQL全文检索是利用查询关键字和查询列内容之间的相关度进行检索,可以利用全文索引来提高匹配的速度。二、语法例如:SELECT * FROM tab_name WHERE MATCH ('列名1,列名2...列名n') AGAINST('词1 词2 词3 ... 词m');即:MATCH 相当于要匹配的列,而 AGAINST 就是要找的内容。这里的table需要是MyISAM类型的表,c...

weixin_35414437的博客 928

使用ElasticSearch实现全文检索

​ 上述代码将json文件的数据封装成对象,然后调用MP的批量增加方法(deviceService.saveBatch(list);),将其添加到hanchuan数据库中。这篇博客,完成从MySQL到ES的数据同步。下面是其中的一张表的 .conf文件(几张表就对应几个conf文件)根据前端传递的id值,进行解析,找到对应的数据库表,进行详情查看。【注】Logstash、ES以及Kibana必须版本一致。最终我们ES中的数据结构就是下面这个样子。在业务逻辑代码写好之后在控制层暴露接口。

JAvavvvvv的博客 4612

MySQL中的全文检索(1)

一、概述      MySQL中的全文检索是利用查询关键字和查询列内容之间的相关度进行检索,可以利用全文索引来提高匹配的速度。二、语法      MATCH (col1,col2,...) AGAINST (expr [search_modifier])      search_modifier: { IN BOOLEAN MODE | WITH QUERY EXPANSION }      例如

navygong的专栏 2万+

关于在 MySQL 排序中使用索引这件事!

我们来梳理下:只有当索引的顺序和 order by 子句的顺序完全一致,并且所有列的排序方向也都一致的情况下,MySQL 才能通过索引来对结果进行排序,同时,如果是联合索引,order by 子句也需要满足最左匹配原则。可以看到,在这个查询中,优化器将 ta 表作为了第一张表,tc 表作为了第二张表,那么根据前面的结论,如果使用第一个表中的索引排序,就会用到索引排序,第二张表的则用不了,我们来验证一下。如果是第二张表的索引,就没有用到索引排序,如果两张表的索引都用了,也不会使用索引排序。

江南一点雨的专栏 3035

MySQL高级特性篇(3)-全文检索的实现与优化

MySQL数据库的全文检索功能可以帮助我们实现快速的文本搜索,提高用户体验。通过合理调整参数、使用布尔模式和提高查询性能等手段,可以进一步优化全文检索的效果和性能。在实际使用过程中,还可以根据具体的需求和场景进行进一步的优化和调整。

俞兆鹏的博客 9804

MySQL 全文检索

MySQL 全文检索支持MySQL 全文检索支持 MyISAM 40以上 InnoDB564以上 全文检索语法 检索方式 简单示例 MySQL全文索引相关配置 注意事项 MyISAM (4.0以上)从MySQL 4.0以上 myisam引擎就支持了full text search 全文搜索。 那么怎么使用了,简单看看: 1.创建一个表,指定支持fulltext的列 CREATE TABLE a

Moxiao__墨箫 1277

MySQL的全文检索

概述 版本说明 MySQL5.5中,只有MyISAM支持全文检索。 MySQL5.6中,InnoDB开始支持全文检索。 MySQL5.7中,可以使用N-Gram插件支持全文检索。此插件支持中/日/韩文。 全文检索的使用限制 只能在类型为CHAR、VARCHAR或者TEXT的字段上创建全文索引。 只支持InnoDB和MyISAM引擎。 一个表只能建立一个全文检索字段。如需要检索多个字段,需要将多个字段一起创建一个索引。 N-Gram全文解析器 MySQL中使用全局变量"ngram_token_siz

just4you的博客 1149

mysql全文检索性能

Lucene可以对MYSQL进行全文检索吗 Lucene是可以的,它常见的用例就是在一个或者多个数据库表进行全文检索。虽然MySql有全文检索的功能,但是如果字段和数据量增加,MySql的性能会减低很快。 本回答由网友推荐 Lucene可以对MYSQL进行全文检索吗 Lucene是可以的,它常见的用例就是在一个...

计算机毕业论文源码,学生个人网页制作html源码。贴近用户做网络推广和互联网优化。 677

MySQL全文检索介绍

MySQL的全文检索功能是一种高效搜索和匹配文本字段的方法,特别适用于处理大量文本数据的应用场景。

rock365的博客 658
上一篇: 抗住大批量请求的高并发架构设计经验
下一篇: 在项目中这样写代码的时候,请搭配红花油、跌打损伤酒一起使用
Java_LingFeng
博客等级 码龄4年 505粉丝 259原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值