mysql从大到小搜索_关于搜索,从Like到Match Against到搜索引擎

2023-10-21 19:40

本文主要是介绍mysql从大到小搜索_关于搜索,从Like到Match Against到搜索引擎,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

最近在弄Mysql搜索相关的东西,走了很多坑,总结一下How to search。

一、使用like模糊查询

9db40debdfa0f08b2c86443da00fe2ab.png大家常用的搜索方式,莫过于使用mysql自带的模糊查询like,where like “%xxx%”搜索简单粗暴,屡试不爽。对于小几万数据量的数据库来说,这个方式是很好用的,很符合当下快节奏的生活方式。(测试数据库有近20W条)

CDBCD0126E92473EBCD2980049FD8D09

似乎看起来是很快的,但是

269FB0ADD37E4A14A0F5DCC9657EB554

6d5b213f35170df4747da37a25e5ad37.png

一加上order by 排序的话,花费时间成指数增长,而且

C4420619E2EB403487EC1DD2692B39B2

9e04e3043d3e02ab72eeec326869a497.png

随着like要匹配的词长度增加,查询速度也是程指数下降,14秒,才20W数据,就用了14.5秒的时间,简直不能忍,要是增长到百万,不得爆炸。like貌似真的不行~于是,上全文索引。

二、使用match against 全文索引search

由于实在不能忍like的缓慢,于是乎就上Mysql自带的全文索引。mysql自5.6以后innodb支持fulltext index。嗯,刚好我们的服务器上是5.7,撸起袖子,换match。但是第一个问题出现了,分词?由于英语句子都有空格作为分隔符,而中文是没有空格的,怎么样才能分词呢?两种解决办法,一种是中文转拼音塞个新字段进去;再就是把中文分词后用符号隔开塞个新字段进去。我用了第二种方式:

E0E2853DEC4144DE8F99B312BF5A990F

bc15dd5ba0ceeb28e8998b70bf022f30.png

然后修改mysql配置文件:mysql> SHOW VARIABLES LIKE 'ft%';ft_boolean_syntax    + ->

ft_min_word_len一定要改小,改为1或者2.因为中文分词最小就是一个字或两个字,4的话显然是不行的。然后创建全文索引:

B1BC64E70F044618880D17EE2343EF83

11d9bca8a6f463d0fe9e7780e5404b71.png

ps:有三点要说一下:

1.全文索引match的字段和建索引时的字段必须一致,联合索引同理。

2.against要匹配的中文,需要加上“+”号参数+:表示必须包含。 -:表示必须不包含 *:表示任意字符

3.两种匹配方式    自然语言检索:IN NATURAL LANGUAGE MODE    布尔检索: IN BOOLEAN MODE

剔除一半匹配行以上都有的词,譬如说,每个行都有this这个字的话,那用this去查时,会找不到任何结果,这在记录条数特别多时很有用,

原因是数据库认为把所有行都找出来是没有意义的,这时,this几乎被当作是stopword(中断词);但是若只有两行记录时,是啥鬼也查不出来的,

因为每个字都出现50%(或以上),要避免这种状况,请用IN BOOLEAN MODE。现在就可以使用全文索引了,来试试看吧:

120AFE40E8CE457BA94AA8DF72C675CF

c14935730fab62222249049e39a2b7e9.png

卧槽,貌似比like慢多了啊,什么玩意?加上排序之后呢?

78EC2E90F4E449ABA4E31FBACAC65379

a166a9dd154847c83573a8aa90ef6ed9.png

再试试多几个词

2A468D3BDE1F4D46B6D3F77B594AB3A1虽然说比起like来,多一点的匹配词并没有增加额外的时间,但是只要一order by ,不管你order by 的字段有没有创建索引,都要对结果集进行重排序。观察mysql性能分析后发现:

65d7b5de3a5e8ff181d4132e4abfc7d5.png

全文索引稳定只用了300到500毫秒的时间,剩下的80%~90%时间全在排序上了。这也是不能忍啊,于是乎找了各种解决办法,再stackexchange上找到一个回答。

在使用全文索引之后要进行排序操作的话需要这样:

SUGGESTION

Refactor the Query so that the MATCH ...AGAINST collects keys only

EXAMPLE #1SELECT a.id FROM a

WHERE

MATCH ('search1','search2') AGAINST ('aaaa' IN BOOLEAN MODE)

ORDER BY a.id DESC

LIMIT 5;

should become something likeSELECT N.id FROM

(SELECT id FROM a WHERE

MATCH ('search1','search2') AGAINST ('aaaa' IN BOOLEAN MODE)) M

INNER JOIN a N USING (id)

ORDER BY N.id DESC LIMIT 5;

EXAMPLE #2SELECT a.id,a.popularity FROM a

WHERE

MATCH ('search1','search2') AGAINST ('aaaa' IN BOOLEAN MODE)

ORDER BY a.popularity DESC

LIMIT 5;

should become something likeSELECT N.id,N.popularity FROM

(SELECT id FROM a WHERE

MATCH ('search1','search2') AGAINST ('aaaa' IN BOOLEAN MODE)) M

INNER JOIN a N USING (id)

ORDER BY N.popularity DESC LIMIT 5;

CONCLUSION

The main idea: Collect the keys using MATCH ...AGAINST and join it back to the source table

好吧,看到了零时表。。。。继续

C2D2CD6CD3F546D584D4DAF8F06B9552

6b51b0168e43008e55af01d9ef653aa4.png

B2D226E119944E58BDA7BA2A41E88533

貌似跟原来一样,并没有提升什么。。。。

DBD533D2902E4F8C9616DAF22C273868

0d1a320eb071c63622fc048a18df40f1.png

6df3c4c48e18f77693978548e7a371ac.png

这样做虽然sorting result的时间变短了,但是copy to tmp table 的时间增加了很多。。。。这样的话,对优化来说并无卵用,再次google,stackexchange:You may need to try setting certain variables within your sessionYou may need to try setting certain variables within your session

These particular values may be too small for your DB Connection to fulfill the query efficiently. These can be set within as follows:To see what values these settings have currently do the following:SHOW VARIABLES LIKE 'max_heap_table_size';SHOW VARIABLES LIKE 'tmp_table_size';

To set max_heap_table_size to 64M do the following:SET max_heap_table_size = 1024 * 1024 * 64;

To set tmp_table_size to 32M do the following:SET tmp_table_size = 1024 * 1024 * 32;

If you cannot set these values within your own session, contact your hosting provider to dynamically set them in your my.cnf.

好吧,改配置文件。。。。修改配置文件之后Copy to temp table 的时间就大幅下降了

D654E0FD5EF94247A3EADDFC51E56758

f4387386174a4e575c2015045483c456.png

至此,全文索引告一段落。这个数据量下,在有排序的情况下,检索速度能保持在1秒以内。然后这远远不够,怎么办?上搜索引擎~

三、使用搜索引擎

sphinx,coreseek,xunsearch 三种选一个吧。

sphinx名气比较大,但是中文文档比较少。

coreseek,反正官网我是访问不了了。

xunsearch 中文文档够用,而且一直在更新。所以就选xunsearch吧。

顺着教程来:

1、下载安装xunsearch

wget http://www.xunsearch.com/download/xunsearch-full-latest.tar.bz2

tar -xjf xunsearch-full-latest.tar.bz2

cd xunsearch-full-1.3.0/

sh setup.sh

2、开启和重启

xunsearch /usr/local/xunsearch/bin/xs-ctl.sh restart

3、检测运行环境和修改配置文件

/usr/local/xunsearch/sdk/php/util/RequiredCheck.php

0A306791570F484580262B38A0E5682D3、修改索引配置文件demo.ini这个ini配置文件是很重要的,如果不会写的话,推荐使用官方的模板自动生成:http://www.xunsearch.com/tools/iniconfig

4DE06DF5BB98408F9440B44993CF39D7

2977f4f1337c1a515317f841d8278497.png

b56da6538d990e0908cea1aa7c7167ba.png

E7CDE6C7958F4264A0DF5CA2F204138B

e62102e8555f4415dbb0c188684cce44.png

4、导入数据生成索引(支持json,mysql,CSV)一般使用mysql

# 清空 demo 项目的索引数据

util/Indexer.php --clean demo

# 导入 JSON 数据文件 file.json 到 demo 项目

util/Indexer.php --source=json demo file.json

# 导入 MySQL 数据库的 dbname.tbl_post 表到 demo 项目中,并且平滑重建

util/Indexer.php --rebuild --source=mysql://root:pass@localhost/dbname --sql="SELECT * FROM common_plat_goods" --project=demo

# 查看 demo 项目在服务端的相关信息

util/Indexer.php --info -p demo

# 强制刷新 demo 项目的搜索日志

util/Indexer.php --flush-log --project demo

# 强制停止重建

util/Indexer.php --stop-rebuild demo

这里我使用的是mysql,只需要goods_id,plat_id,goods_name 三个字段。导入脚本如下:

/usr/local/xunsearch/sdk/php/util/Indexer.php --rebuild --source=mysql://root:123456@127.0.0.1/search --sql="select goods_id,plat_id,goods_name from common_plat_goods order by goods_id desc" --project=demo

PS:

localhost不行就换成127.0.0.1

--project=demo是配置文件的名称

EA6D1B8559904F7CA06E200728A62F4A

971001592d07cba83da7fb9f6a5c9043.png

速度还是很快的,近18W条数据几秒钟索引就重建好了。试试看官方提供的测试搜索:

74E2F2AF5D58482FBE5AA0BEB19470B0

0c1e7bfbde11559ddeafb7e46bfec4fc.png

你没看错,0.0098秒就完成了检索,大功告成~什么like,match aginst都是浮云,搜索引擎才是王道啊。

接下来就可以结合xunsearch的SDK写相应的业务了,具体可以看官方的文档。比起直接使用like或者match against,搜索引擎的确很爽

这篇关于mysql从大到小搜索_关于搜索,从Like到Match Against到搜索引擎的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/256545

相关文章

SQL中的外键约束

外键约束用于表示两张表中的指标连接关系。外键约束的作用主要有以下三点: 1.确保子表中的某个字段(外键)只能引用父表中的有效记录2.主表中的列被删除时,子表中的关联列也会被删除3.主表中的列更新时,子表中的关联元素也会被更新 子表中的元素指向主表 以下是一个外键约束的实例展示

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

如何去写一手好SQL

MySQL性能 最大数据量 抛开数据量和并发数,谈性能都是耍流氓。MySQL没有限制单表最大记录数,它取决于操作系统对文件大小的限制。 《阿里巴巴Java开发手册》提出单表行数超过500万行或者单表容量超过2GB,才推荐分库分表。性能由综合因素决定,抛开业务复杂度,影响程度依次是硬件配置、MySQL配置、数据表设计、索引优化。500万这个值仅供参考,并非铁律。 博主曾经操作过超过4亿行数据

认识、理解、分类——acm之搜索

普通搜索方法有两种:1、广度优先搜索;2、深度优先搜索; 更多搜索方法: 3、双向广度优先搜索; 4、启发式搜索(包括A*算法等); 搜索通常会用到的知识点:状态压缩(位压缩,利用hash思想压缩)。

hdu1240、hdu1253(三维搜索题)

1、从后往前输入,(x,y,z); 2、从下往上输入,(y , z, x); 3、从左往右输入,(z,x,y); hdu1240代码如下: #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#inc

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

MySQL数据库宕机,启动不起来,教你一招搞定!

作者介绍:老苏,10余年DBA工作运维经验,擅长Oracle、MySQL、PG、Mongodb数据库运维(如安装迁移,性能优化、故障应急处理等)公众号:老苏畅谈运维欢迎关注本人公众号,更多精彩与您分享。 MySQL数据库宕机,数据页损坏问题,启动不起来,该如何排查和解决,本文将为你说明具体的排查过程。 查看MySQL error日志 查看 MySQL error日志,排查哪个表(表空间

MySQL高性能优化规范

前言:      笔者最近上班途中突然想丰富下自己的数据库优化技能。于是在查阅了多篇文章后,总结出了这篇! 数据库命令规范 所有数据库对象名称必须使用小写字母并用下划线分割 所有数据库对象名称禁止使用mysql保留关键字(如果表名中包含关键字查询时,需要将其用单引号括起来) 数据库对象的命名要能做到见名识意,并且最后不要超过32个字符 临时库表必须以tmp_为前缀并以日期为后缀,备份

[MySQL表的增删改查-进阶]

🌈个人主页:努力学编程’ ⛅个人推荐: c语言从初阶到进阶 JavaEE详解 数据结构 ⚡学好数据结构,刷题刻不容缓:点击一起刷题 🌙心灵鸡汤:总有人要赢,为什么不能是我呢 💻💻💻数据库约束 🔭🔭🔭约束类型 not null: 指示某列不能存储 NULL 值unique: 保证某列的每行必须有唯一的值default: 规定没有给列赋值时的默认值.primary key:

hdu 4517 floyd+记忆化搜索

题意: 有n(100)个景点,m(1000)条路,时间限制为t(300),起点s,终点e。 访问每个景点需要时间cost_i,每个景点的访问价值为value_i。 点与点之间行走需要花费的时间为g[ i ] [ j ] 。注意点间可能有多条边。 走到一个点时可以选择访问或者不访问,并且当前点的访问价值应该严格大于前一个访问的点。 现在求,从起点出发,到达终点,在时间限制内,能得到的最大