Sphinx查询性能非常厉害,亿级数据下输入关键字,大部分能在0.01~0.1秒,少部分再5秒之内查出数据。
由C++编写的高性能全文搜索引擎的开源组件,C/S架构,跨平台(支持Linux、Windows、MacOS),支持分布式部署,并可直接适配MySQL。
因为MySQL的 like %keyword% 不走索引,且全文索引不支持中文,所以需要借助其它组件。适用于不经常更新的数据的全文搜索。
ElasticSearch、Solr、Lucene、Algolia、XunSearch。
发送给Sphinx关键字,然后Sphinx返回id给PHP,PHP再调用MySQL根据id查询。也就是帮着MySQL找id的,MySQL走主键索引,查询性能很高。
Sphinx附带了三种不同的API,SphinxAPI、SphinxSE和SphinxQL。SphinxAPI是一个可用于Java、PHP、Python、Perl、C和其他语言的原生库。SphinxSE是MySQL的一个可插拔存储引擎,支持将大量结果集直接发送到MySQL服务器进行后期处理。SphinxQL允许应用程序使用标准MySQL客户端库和查询语法查询Sphinx。
Sphinx不仅限于关键字搜索。在全文搜索结果集之上,您可以计算任意算术表达式、添加WHERe条件、排序依据、分组依据、使用最小值/最大值/AVG值/总和、聚合等。本质上,支持成熟的SQL SELECt。
- 决策分析:
亿级的数据量,还都得是中文,如果是52个大小写字母和10个数字可以随机,中文随机效果差,最好是有能阅读通畅的数据源,而不是随机汉字数据源。 - 尝试寻找:
尝试看了txt版的《三国演义》,发现行数太少,所以转变思维,更大的数据量,只能是长篇小说,翻看了最长的小说,也才22万行,1行小说对应1条MySQL数据,数据量还是太少,虽然循环小说内容插入也行,但还是差点意思。 - 资源整合:
程序员天天玩的就是数据,这点小事难不倒我,去网盘找txt小说资源合集https://www.aliyundrive.com/s/LBBg4ZvWip2/folder/63a138e95845afd3baa947db96342937033c254f
找到了如下35000本txt的小说。 - 数据合并:
下载了几千个txt小说,需要用命令把这些合并成一个文件,使用方便PHP程序逐行读取。整合后的单个txt文件9.57个G。 - 数据入库:
大数据文件一次加载会把内存撑爆,所以需要使用去逐行读取文件。 -
性能调优:
MyISAM引擎:
insert 发现1秒才1400行的插入速度,不行得调整。
。
优化后,每秒2万的插入速度。如果是InnoDB引擎
可以调整redo log 刷盘策略,。
并添加缓冲池。
,就行了。 数量检查:
两万年后,用一看,数据量109 450 000,搞定。性能测试:
SELECT count(*) FROM articles where content like '%晴空万里%',找出来了1931个,花了242秒。- 官方文档:https://sphinxsearch.com/docs/current.html#matching-modes
- 调用方法:
- 分词举例:假设关键字“白色衣服”,词语被分成了“白色”和“衣服”。
服务器配置:CentOS7.6 16核4G内存
实测亿级数据下搜索晴空万里只花费0.011秒,上文提到MySQL则需要242秒,性能差了22000倍。或许是受或分词器影响,Sphinx查询出来1898条,MySQL查询数据为1931条
多次测试:在109450000条数据中,从不同角度测试Sphinx SPH_MATCH_PHRASE匹配模式,相当于mysql where field like '%关键字%':
- 对于Sphinx:当需要新增增量索引时,读取这个表中的数据,获取到这个值,使其创建索引的起始点,为max_id字段的值。
- 对于max_id字段的业务作用:可以封装一个方法,可以让这个值载入Redis,redis有值就读取,无值就查询然后载入Redis。
- 对于业务代码:例如100万行数据创建了Sphinx索引,然后又新增了1000条,这1000条数据没有sphinx索引,可以在业务代码中使用mysql union或者其它方式,让这1000条数据,做查询。
伪代码如下:
装好之后配置它,汉字是提示,记得运行环境要删掉
开启服务
PHP SphinxClient手册:http://docs.php.net/manual/tw/class.sphinxclient.php
这是二次改过的test_coreseek.php,对于新手有很友好的提示。
详解:SPH_MATCH_FULLSCAN
SPH_MATCH_FULLSCAN,强制使用全扫描模式。注意,任何查询项都将被忽略,这样过滤器、过滤器范围和分组仍然会被应用,但不会进行文本匹配。
当满足以下条件时,将自动激活SPH_MATCH_FULLSCAN模式来代替指定的匹配模式:
查询字符串为空(即:它的长度是0)。
Docinfo存储设置为extern。
在完全扫描模式下,所有索引的文档都被认为是匹配的。这样的查询仍然会应用过滤器、排序和分组,但不会执行任何全文搜索。这对于统一全文和非全文搜索代码或卸载SQL服务器很有用(在某些情况下,Sphinx扫描比类似的MySQL查询执行得更好)。
压测方式 :ab -c 1 -n 10~1000 192.168.3.180/test_coreseek.php
中文定值关键字为华盛顿,英文定值关键字为XYZ,30位随机中文或英文字符,由代码生成。
对于update很多数据,sphinx不会自动更新索引,所以可以选择在公司业务空闲时间重建索引。
对于insert,可以使用增量索引,创建一个表用于存储已经新增sphinx索引记录的最大值。
这块需要承接上文。
这个也好办,直接在csft.conf配置文件内source段和index段复制粘贴,根据上文的两段文章,该创建索引的创建索引,该重启的重启。
不需要引入多个文件,就和MySQL一样,只需要一个/etc/my.cnf就行了,相加配置,接着往下续就行了。
新创建索引后不会生效,需要关闭searchd进程后重新启动。
方案1:
使用composer安装新的包,PHP8.0及以上不会报错。
记得要搜索sphinx client或sphinxapi,不要搜素sphinx,这会把SphinxQL的解决方案也给搜出来。
用这个包就行,composer require nilportugues/sphinx-search
用法与自带的完全一致,而且遇到PHP8不报错。
方案2:
使用原生自带的包,PHP8.0及以上会报错。
sphinxapi.php放置到app/Libs/Others目录下,并添加自己的命名空间AppLibsOthersSphinxApi。
app/Libs/helper.php存放了自定义封装的方法,并使用composer dump-autoload配置,跟随框架自动加载。