看大数据最大技术难关之模糊检索,PostgreSQL如何攻克!

Posted 人工智能与大数据技术

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了看大数据最大技术难关之模糊检索,PostgreSQL如何攻克!相关的知识,希望对你有一定的参考价值。

链接:https://yq.aliyun.com/articles/7444


大数据正在向我们奔来。尽管业务场景不会完全相同,但在其中一个最典型场景——模糊检索中,技术需求却出奇的一致。


比如说:


物联网,往往会产生大量的数据,除了数字数据,还有字符串类的数据,例如条形码,车牌,手机号,邮箱,姓名等。假设用户需要在大量的传感数据中进行模糊检索,甚至规则表达式匹配,有什么高效的方法呢?


医药,市面上发现了一批药品可能有问题,需要对药品条码进行规则表达式查找,找出复合条件的药品流向。但怎么才能在如此复杂的系统中,用高效方法来实现?



相同的需求还有很多。几乎每一个模糊匹配的场景下,都需要正则表达式匹配,这和人脸拼图有点类似,我们已经看到强烈的需求已经产生。但技术方面,要怎么做更好?


在我看来:正则匹配和模糊匹配通常是搜索引擎的特长,但是如果你使用的是PostgreSQL数据库照样能实现,并且性能不赖,加上分布式方案 (譬如 plproxy, pg_shard, fdw shard, pg-xc, pg-xl, greenplum),处理百亿以上数据量的正则匹配和模糊匹配效果杠杠的,同时还不失数据库固有的功能,绝对是一举多得。


首先对应用场景进行一下分类,以及现有技术下能使用的优化手段。


1、带前缀的模糊查询,例如 like 'ABC%',在PG中也可以写成 ~ '^ABC'
可以使用btree索引优化,或者拆列用多列索引叠加bit and或bit or进行优化(只适合固定长度的端字符串,例如char(8))。


2、带后缀的模糊查询,例如 like '%ABC',在PG中也可以写成 ~ 'ABC$'

可以使用reverse函数btree索引,或者拆列用多列索引叠加bit and或bit or进行优化(只适合固定长度的端字符串,例如char(8))。


3、不带前缀和后缀的模糊查询,例如 like '%AB_C%',在PG中也可以写成 ~ 'AB.C'


可以使用pg_trgm的gin索引,或者拆列用多列索引叠加bit and或bit or进行优化(只适合固定长度的端字符串,例如char(8))。


4、正则表达式查询,例如 ~ '[\d]+def1.?[a|b|0|8]{1,3}'

可以使用pg_trgm的gin索引,或者拆列用多列索引叠加bit and或bit or进行优化(只适合固定长度的端字符串,例如char(8))。


PostgreSQL pg_trgm插件自从9.1开始支持模糊查询使用索引,从9.3开始支持规则表达式查询使用索引,大大提高了PostgreSQL在刑侦方面的能力。
代码见 https://github.com/postgrespro/pg_trgm_pro

pg_trgm插件的原理,将字符串前加2个空格,后加1个空格,组成一个新的字符串,并将这个新的字符串按照每3个相邻的字符拆分成多个token。


当使用规则表达式或者模糊查询进行匹配时,会检索出他们的近似度,再进行filter。


GIN索引的图例:




从btree检索到匹配的token时,指向对应的list, 从list中存储的ctid找到对应的记录。

因为一个字符串会拆成很多个token,所以没插入一条记录,会更新多条索引,这也是GIN索引需要fastupdate的原因。

正则匹配是怎么做到的呢?
详见 https://raw.githubusercontent.com/postgrespro/pg_trgm_pro/master/trgm_regexp.c

实际上它是将正则表达式转换成了NFA格式,然后扫描多个TOKEN,进行bit and|or匹配。

正则组合如果转换出来的的bit and|or很多的话,就需要大量的recheck,性能也不能好到哪里去。


下面针对以上四种场景,实例讲解如何优化。


1、带前缀的模糊查询,例如 like 'ABC%',在PG中也可以写成 ~ '^ABC'
可以使用btree索引优化,或者拆列用多列索引叠加bit and或bit or进行优化(只适合固定长度的端字符串,例如char(8))。


例子,1000万随机产生的MD5数据的前8个字符。

看大数据最大技术难关之模糊检索,PostgreSQL如何攻克!


带前缀的模糊查询,不使用索引需要5483毫秒。


带前缀的模糊查询,使用索引只需要0.5毫秒。


2、带后缀的模糊查询,例如 like '%ABC',在PG中也可以写成 ~ 'ABC$'

可以使用reverse函数btree索引,或者拆列用多列索引叠加bit and或bit or进行优化(只适合固定长度的端字符串,例如char(8))。


带后缀的模糊查询,使用索引只需要0.5毫秒。


3、不带前缀和后缀的模糊查询,例如 like '%AB_C%',在PG中也可以写成 ~ 'AB.C'

可以使用pg_trgm的gin索引,或者拆列用多列索引叠加bit and或bit or进行优化(只适合固定长度的端字符串,例如char(8))。

前后模糊查询,使用索引只需要3.8毫秒。


4、正则表达式查询,例如 ~ '[\d]+def1.?[a|b|0|8]{1,3}'


可以使用pg_trgm的gin索引,或者拆列用多列索引叠加bit and或bit or进行优化(只适合固定长度的端字符串,例如char(8))。


前后模糊查询,使用索引只需要108毫秒。


时间主要花费在排他上面。


检索了14794行,remove了14793行。大量的时间花费在无用功上,但是比全表扫还是好很多。


优化:

使用gin索引后,需要考虑性能问题,因为info字段被打散成了多个char(3)的token,从而涉及到非常多的索引条目,如果有非常高并发的插入,最好把gin_pending_list_limit设大,来提高插入效率,降低实时合并索引带来的RT升高。

使用了fastupdate后,会在每次vacuum表时,自动将pengding的信息合并到GIN索引中。

还有一点,查询不会有合并的动作,对于没有合并的GIN信息是使用遍历的方式搜索的。


压测高并发的性能:


修改配置,让数据库的autovacuum快速迭代合并gin。


创建一个测试函数,用来产生随机的测试数据。按照这个速度,一天能支持超过40亿数据入库。


接下来对比一下字符串分离的例子,这个例子适用于字符串长度固定,并且很小的场景,如果字符串长度不固定,这种方法没用。


适用splict的方法,测试数据不尽人意,所以还是用pg_trgm比较靠谱。(省略一图)


大数据量性能测试:


模拟分区表,每小时一个分区,每小时数据量5000万,一天12亿,一个月360亿。


生成插入SQL


性能指标, 范围扫描, 落到单表5000万的数据量内, 毫秒级返回(详细看图).

单表144亿的正则和模糊查询性能测试:


测试数据后续放出,分表后做到秒级是没有问题的。信心从何而来呢?
因为瓶颈不在IO上,主要在数据的recheck, 把144亿数据拆分成29个5亿的表,并行执行,秒出是有可能的。


来看一个单表5亿的测试结果,秒出:


看大数据最大技术难关之模糊检索,PostgreSQL如何攻克!

全表扫描需要,


看大数据最大技术难关之模糊检索,PostgreSQL如何攻克!
性能对比图表:

1000万数据对比


看大数据最大技术难关之模糊检索,PostgreSQL如何攻克!

5亿数据对比

看大数据最大技术难关之模糊检索,PostgreSQL如何攻克!

1000万数据btree bit or|and与gin对比

看大数据最大技术难关之模糊检索,PostgreSQL如何攻克!

144亿分区表对比

看大数据最大技术难关之模糊检索,PostgreSQL如何攻克!


大数据量的优化方法,例如百亿级别以上的数据量,如何能做到秒级的模糊查询响应。


对于单机,可以使用分区,同时使用并行查询,充分使用CPU的功能。或者使用MPP, SHARDING架构,利用多机的资源。


原则,减少recheck,尽量扫描搜索到最终需要的结果(大量扫描,大量remove checked false row, 全表和索引都存在这种现象)。



●本文编号142,以后想阅读这篇文章直接输入142即可。

●输入m可以获取到文章目录

今日微信公号推荐↓↓↓
 


更多推荐请看


涵盖:程序人生、算法与数据结构、黑客技术与网络安全、大数据技术、前端开发、Java、Python、Web开发、安卓开发、ios开发、C/C++、.NET、Linux、数据库、运维等。传播计算机学习经验、推荐计算机优秀资源:点击前往

点击阅读原文,了解野狗

以上是关于看大数据最大技术难关之模糊检索,PostgreSQL如何攻克!的主要内容,如果未能解决你的问题,请参考以下文章

对比PigHive和SQL,浅看大数据工具之间的差异

从技术视角看大数据行业的发展趋势

工作中的Elasticsearch-模糊检索

pyqt5 tablewodget 模糊匹配

从历年 Gartner hype cycle 看大数据行业的发展历史和趋势

阿里为什么要举全集团之力做 Serverless?