Mysql实现简易版搜索引擎的示例代码

目录
  • 前言
  • 简介
  • ngram 全文解析器
  • 创建全文索引
  • 检索方式
    • 1、自然语言检索(NATURAL LANGUAGE MODE)
    • 2、布尔检索(BOOLEAN MODE)
  • 与 Like 对比
  • 总结

前言

前段时间,因为项目需求,需要根据关键词搜索聊天记录,这不就是一个搜索引擎的功能吗?

于是我第一时间想到的就是 ElasticSearch 分布式搜索引擎,但是由于一些原因,公司的服务器资源比较紧张,没有额外的机器去部署一套 ElasticSearch 服务,而且上线时间也比较紧张,数据量也不大,然后就想到了 Mysql 的全文索引。

简介

其实 Mysql 很早就支持全文索引了,只不过一直只支持英文的检索,从5.7.6 版本开始,Mysql 就内置了 ngram 全文解析器,用来支持中文、日文、韩文分词。

Mysql 全文索引采用的是倒排索引的原理,在倒排索引中关键词是主键,每个关键词都对应着一系列文件,这些文件中都出现了这个关键词。这样当用户搜索某个关键词时,排序程序在倒排索引中定位到这个关键词,就可以马上找出所有包含这个关键词的文件。

本文测试,基于 Mysql 8.0 版本,数据库引擎采用的是 InnoDB

ngram 全文解析器

ngram 就是一段文字里面连续的 n 个字的序列。ngram 全文解析器能够对文本进行分词,每个单词是连续的 n 个字的序列。例如,用 ngram 全文解析器对“你好靓仔”进行分词:

n=1: '你', '好', '靓', '仔'
n=2: '你好', '好靓', '靓仔'
n=3: '你好靓', '好靓仔'
n=4: '你好靓仔'

MySQL 中使用全局变量 ngram_token_size 来配置 ngram 中 n 的大小,它的取值范围是1到10,默认值是 2。通常 ngram_token_size 设置为要查询的单词的最小字数。如果需要搜索单字,就要把 ngram_token_size 设置为 1。在默认值是 2 的情况下,搜索单字是得不到任何结果的。因为中文单词最少是两个汉字,推荐使用默认值 2。

可以通过以下命令查看 Mysql 默认的 ngram_token_size 大小:

show variables like 'ngram_token_size'

有两种方式可以设置全局变量 ngram_token_size 的值:

1、启动 mysqld 命令时指定:

mysqld --ngram_token_size=2

2、修改 Mysql 配置文件 my.ini,末尾增加一行参数:

ngram_token_size=2

创建全文索引

1、建表时创建全文索引

CREATE TABLE `article` (
  `id` bigint NOT NULL,
  `url` varchar(1024) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  `title` varchar(256) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  `source` varchar(32) COLLATE utf8mb4_general_ci DEFAULT '',
  `keywords` varchar(32) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `publish_time` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  FULLTEXT KEY `title_index` (`title`) WITH PARSER `ngram`
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

2、通过 alter table 方式

ALTER TABLE article ADD FULLTEXT INDEX title_index(title) WITH PARSER ngram;

3、通过 create index 方式

CREATE FULLTEXT INDEX title_index ON article (title) WITH PARSER ngram;

检索方式

1、自然语言检索(NATURAL LANGUAGE MODE)

自然语言模式是 MySQL 默认的全文检索模式。自然语言模式不能使用操作符,不能指定关键词必须出现或者必须不能出现等复杂查询。

示例

select * from article where MATCH(title) AGAINST ('北京旅游' IN NATURAL LANGUAGE MODE);

// 不指定模式,默认使用自然语言模式
select * from article where MATCH(title) AGAINST ('北京旅游');

可以看出,该模式下根据“北京旅游”搜索,可以搜索出包含“北京”的或者包含“旅游”的内容,因为它是根据自然语言分成了两个关键词。

上面示例中返回的结果会自动按照匹配度排序,匹配度高的在前面,匹配度是一个非负浮点数。

示例

// 查看匹配度
select * , MATCH(title) AGAINST ('北京旅游') as score from article where MATCH(title) AGAINST ('北京旅游' IN NATURAL LANGUAGE MODE);

2、布尔检索(BOOLEAN MODE)

布尔检索模式可以使用操作符,可以支持指定关键词必须出现或者必须不能出现或者关键词的权重高还是低等复杂查询。

示例

// 无操作符
// 包含“约会”或“攻略”
select * from article where MATCH(title) AGAINST ('约会 攻略' IN BOOLEAN MODE);

// 使用操作符
// 必须包含“约会”,可包含“攻略”
select * from article where MATCH(title) AGAINST ('+约会 攻略' IN BOOLEAN MODE);

更多操作符示例:

'约会 攻略'
无操作符,表示或,要么包含“约会”,要么包含“攻略”

'+约会 +攻略'
必须同时包含两个词

'+约会 攻略'
必须包含“约会”,但是如果也包含“攻略”的话,匹配度更高。

'+约会 -攻略'
必须包含“约会”,同时不能包含“攻略”。

'+约会 ~攻略'
必须包含“约会”,但是如果也包含“攻略”的话,匹配度要比不包含“攻略”的记录低。

'+约会 +(>攻略 <技巧)'
查询必须包含“约会”和“攻略”或者“约会”和“技巧”的记录,但是“约会 攻略”的匹配度要比“约会 技巧”高。

'约会*'
查询包含以“约会”开头的记录。

'"约会攻略"'
使用双引号把要搜素的词括起来,效果类似于like '%约会攻略%',
例如“约会攻略初级篇”会被匹配到,而“约会的攻略”就不会被匹配。

与 Like 对比

全文索引和 like 查询对比,有以下优点:

  • like 只是进行模糊匹配,全文索引却提供了一些语法语义的查询功能,会将要查的字符串进行分词操作,这决定于 Mysql 的词库。
  • 全文索引可以自己设置词语的最小、最大长度,要忽略的词,这些都是可以设置的。
  • 用全文索引去某个列查一个字符串,会返回匹配度,可以理解为匹配的关键字个数,是个浮点数。

而且全文检索的性能也是优于 like 查询的

以下是以 50w 左右数据进行的测试:

// like 查询
select * from article where title like '%北京%';

// 全文索引查询
select * from article where MATCH(title) AGAINST ('北京' IN BOOLEAN MODE);

可以看出 like 查询是 1.536s,全文索引查询是 0.094s,快了16倍左右。

总结

全文索引能快速搜索,但是也存在维护索引的开销。字段长度越大,创建的全文索引也越大,会影响DML语句的吞吐量。数据量不大的情况下可以采用全文索引来做搜索,简单方便,但是数据量大的话还是建议用专门的搜索引擎 ElasticSearch 来做这件事。

到此这篇关于Mysql实现简易版搜索引擎的示例代码的文章就介绍到这了,更多相关Mysql 搜索引擎内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详细介绍基于MySQL的搜索引擎MySQL-Fullltext

    本文涵盖了一个简单的C实现的搜索引擎的搭建始末. 我通常使用SQL Server和C #,但我教C/C++的朋友要远离微软.在过去,MySQL不是我想要的数据库,因为标准安装版不支持事务,但它变得越来越成熟.我使用64位InnoDB引擎的MySQL 5.6,使用Unicode(utf8)编码,这是我新数据库的默认设置. Freetext是InnoDB的新特征,它在MySQL5.6版中被首次推出. 与C相比我通常更喜欢C++,即使在小项目中:不用知道所有的函数名,而且有一些内置的常用操作和漂亮的I

  • MySQL全文索引实现简单版搜索引擎实例代码

    前言 只有Innodb和myisam存储引擎能用全文索引(innodb支持全文索引是从mysql5.6开始的) char.varchar.text类型字段能创建全文索引(fulltext index type) 全文索引的基于关键词的,如何区分不同的关键词了,就要用到分词(stopword) 英文单词用空格,逗号进行分词:中文分词不方便(一个句子不知道怎样区分不同的关键词) 内置分词解析器ngram支持中文,日文,韩文(将句子分成固定数字的短语) 当对表写入大量数据时,写入数据后再创建全文索引的

  • Mysql实现简易版搜索引擎的示例代码

    目录 前言 简介 ngram 全文解析器 创建全文索引 检索方式 1.自然语言检索(NATURAL LANGUAGE MODE) 2.布尔检索(BOOLEAN MODE) 与 Like 对比 总结 前言 前段时间,因为项目需求,需要根据关键词搜索聊天记录,这不就是一个搜索引擎的功能吗? 于是我第一时间想到的就是 ElasticSearch 分布式搜索引擎,但是由于一些原因,公司的服务器资源比较紧张,没有额外的机器去部署一套 ElasticSearch 服务,而且上线时间也比较紧张,数据量也不大,

  • 基于 Mysql 实现一个简易版搜索引擎

    目录 基于 Mysql 实现一个搜索引擎 一.ngram 全文解析器 二.创建全文索引 1.建表时创建全文索引 2.通过 alter table 方式 3.通过 create index 方式 三.检索方式 1.自然语言检索(NATURAL LANGUAGE MODE) 四.与 Like 对比 基于 Mysql 实现一个搜索引擎 前言: 其实 Mysql 很早就支持全文索引了,只不过一直只支持英文的检索,从5.7.6 版本开始,Mysql 就内置了 ngram 全文解析器,用来支持中文.日文.韩

  • Centos7实现MySQL基于日志还原数据的示例代码

    简介 Binlog日志,即二进制日志文件,用于记录用户对数据库操作的SQL语句信息,当发生数据误删除的时候我们可以通过binlog日志来还原已经删除的数据,还原数据的方法分为传统二进制文件还原数据和基于GTID的二进制文件还原数据 前期准备 准备一台Centos7虚拟机,关闭防火墙和selinux,配置IP地址,同步系统时间,安装MySQL数据库 传统二进制日志还原数据 修改配置文件 [root@localhost ~]# vi /etc/my.cnf server-id=1 log-bin=b

  • Python连接Mysql进行增删改查的示例代码

    Python连接Mysql 1.安装对应的库 使用Python连接Mysql数据库需要安装相应的库 以管理员身份运行cmd,输入命令 pip install mysql.connector 安装完成后建立 test.py 写入 import mysql.connector 保存后运行 python test.py 用以测试模块库是否安装完成,如果不报错,说明安装完成 2.进行连接测试 编写connectTest.py文件 文件内容: import mysql.connector connect

  • C#实现简易画图板的示例代码

    编程环境 VS2019.C# 画板功能演示 实现简单画图 打开功能 可打开jpg格式的文件 保存功能 可将绘画的内容保存为jpg文件 颜色选择功能 用户可自由选择所需的颜色 粗细选择功能 提供四种型号的画笔供用户选择 清空画布功能 点击清空后提示是否清空 选择确定则将画布清空,效果如下图所示 功能实现过程 定义公共变量 用于多个窗体之间共同使用数据 public class TempData { //用于多个窗体共同使用的数据 public static int size=5; public s

  • MySQL 日期时间加减的示例代码

    目录 1.MySQL加减某个时间间隔 2.日期相减 最近在复习MySQL,正好看到了MySQL 日期时间,本文就给自己留个笔记,顺便分享给大家 now (); 当前具体的日期和时间 curdate (); 当前日期 curtime(); 当前时间 1.MySQL加减某个时间间隔 设置当前日期变量 set @dt = now(); //设置当前日期 select @dt; //查询变量值 加减某个时间间隔函数date_add()与date_sub() date_add('某个日期时间',inter

  • 基于Go语言实现的简易api网关的示例代码

    浏览器的请求去请求目标地址,然后获得结果它再发送给浏览器.对于Go语言来说,实现转发只需要简单的一行代码即可实现,如下所示: httputil.NewSingleHostReverseProxy(address) 基于此功能,进行简单包装,实现从远端admin管理中心获取需要转发的路由信息或者可以从本地配置文件中获取,实现动态转发.后续可以根据业务情况,可以实现如下功能: 开发接口,实现动态添加代理规则,进行转发 过滤不合法的接口 接口限流 统一日志记录 - 代码如下: package main

  • Java实现泡泡堂对战版游戏的示例代码

    目录 前言 主要设计 功能截图 代码实现 游戏启动类 核心监听类 核心线程类 总结 前言 <泡泡堂II>是一个基于java的自制游戏,使用了MVC模式,分离了模型.视图和控制器,使得项目结构清晰易于扩展,使用配置文件来设置游戏基本配置,扩展地图人物道具等.同时,该程序编写期间用了单例模式.工厂模式.模板模式等设计模式.为了游戏的可玩性,特意设计了平滑碰撞以及机器人. 主要设计 设计游戏界面,用swing实现 绘制游戏启动界面.结束界面.地图.主角.道具 实现泡泡爆炸 为了尽量复原泡泡堂游戏,初

  • python区块链简易版交易实现示例

    目录 说明 引言 比特币交易 交易输出 发送币 余额查看 总结 说明 本文根据https://github.com/liuchengxu/blockchain-tutorial的内容,用python实现的,但根据个人的理解进行了一些修改,大量引用了原文的内容.文章末尾有"本节完整源码实现地址". 引言 交易(transaction)是比特币的核心所在,而区块链唯一的目的,也正是为了能够安全可靠地存储交易.在区块链中,交易一旦被创建,就没有任何人能够再去修改或是删除它.今天,我们将会开始

  • Qt实现简易毛玻璃效果的示例代码

    目录 现有功能 运行结果 源码 frosted_glass_label.h frosted_glass_label.cpp main.cpp 现有功能 1.用模糊功能实现简易的毛玻璃效果. 2.鼠标移动无边框窗口. 运行结果 源码 frosted_glass_label.h #ifndef FROSTEDGLASSLABEL_H #define FROSTEDGLASSLABEL_H #include <QWidget> #include <QLabel> #include <

随机推荐