mysql/mariadb 实现全文检索

为什么要使用全文检索

有很多业务都有根据某关键字或者某短语去模糊搜索结果的情况,比如文章或者博客标题,内容,等关键字搜索,或者根据多个词语组合搜索,比如搜索“nba 湖人 科比”找到匹配度最高的内容等,因此全文检索在各场景的应用还是很广的

都有哪些方式实现全文检索

就我个人实际项目应用中搭建以及落地的项目情况来说,早期主要用solr,后期主要用elasticsearch
,其实这些都是很不错的第三方全文检索应用,但是如果规模量级很小的项目,用这些就有点杀鸡用牛刀了,而且为了保证solr 或者es
高可用,一般都会进行集群搭建与维护,这就额外的增加了开发和部署以及维护成本,所以这里主要介绍一下中小项目下直接用mysql5.6+/mariadb10.0.6+
实现全文检索功能

如何用mysql实现全文检索

由于mariadb 全文检索模式需要适用Mroonga 存储引擎,但此引擎不支持事务,所以选择了择中方案,先调用分词器,将内存分解为自然语言分词,然后保存在一个独立字段中,本文只是创建了个测试表用来演示,暂不涉及分词器部分,后续篇章中会有独立介绍以及全部分词器代码项目demo 链接如下:

java字符串分词参考我另一篇文章《java应用集成HanLP进行中文自然语言分词详细完整案例以及demo》

like 方式

like 方式左关联like %xx 会导致索引失效,然后大部分业务都需要左右模糊匹配查询,因此大数据两情况下会造成极大性能耗费

match 方式(仅限于mysql >=5.6)

match 基于fulltext 索引机制需要查询字段必须先创建fulltext 索引,否则无法使用,而且一起查询的列也都必须一同做关联索引,不然一样无法使用

match 全文检索分为三种类型,如下:

1.自然语言搜索(IN NATURAL LANGUAGE MODE)
查询关键字表达式会被解析器分解为若干个单词,把每个单词匹配的行都查询出来。
2.布尔搜索 (IN BOOLEAN MODE) 查询关键字表达式中可以包含特定的修饰字符,通过修饰字符,来满足特殊的查询条件。

修饰符

说明

+

加号,结果中必需包含

-

减号,结果中不能包含

空格,结果中,至少包含一个由空格连接的单词

*

星号,作为通配符匹配

3.查询扩展搜索(WITH QUERY EXPANSION)

使用场景以及语法demo

准备测试数据以及创建索引

mariadb 查询json字段 mariadb全文检索_mariadb


mariadb 查询json字段 mariadb全文检索_mysql_02

注意:如果要同时查询多个字段的匹配情况,需要创建独立字段的索引以及多个字段一起的索引

比如我有title和body两个字,可能需要各自独立查询,也需要同时查询,那么就得创建独立索引的同时也要创建一起的关联索引,如下

查询对应匹配项数量

select count(*) from test where MATCH(title,body) AGAINST ('开发' IN BOOLEAN MODE)

查询含有’开发‘字样的匹配项行内容

select * from test where MATCH(title,body) AGAINST ('开发' IN BOOLEAN MODE)

mariadb 查询json字段 mariadb全文检索_mariadb_03

查询匹配度

select MATCH(title,body) AGAINST ('+开发' IN BOOLEAN MODE) from test

mariadb 查询json字段 mariadb全文检索_mysql 全文检索_04

查询含有’开发‘字样且不含有‘入门‘字样的匹配项行内容

select * from test where MATCH(title,body) AGAINST ('+开发 -入门' IN BOOLEAN MODE)

查询含有’世界’为开头的匹配项,和like’xx%’ 右匹配相同,比如如 lik*,表示可以是 lik,like,likes

select * from test where MATCH(title,body) AGAINST ('世界*' IN BOOLEAN MODE)

mariadb 查询json字段 mariadb全文检索_mysql 全文检索_05

查询确切含有’入门课程‘字样短语的匹配项行内容

select * from test where MATCH(title,body) AGAINST ('"入门课程"' IN BOOLEAN MODE)

mariadb 查询json字段 mariadb全文检索_全文检索_06