需求分析

要通过PostgreSQL实现类似Google搜索自动提示的功能,例如要实现一个查询海量数据中的商品名字,每次输入就提示用户各种相关搜索选项,例如淘宝、京东等电商查询

思路

这个功能可以用 PostgreSQL的实时全文检索和分词、相似搜索、前模糊匹配等特性实现。具体策略是,定义一个搜索提示的最大数量。首先通过前模糊匹配查询获取数据,如果未满最大数量,则进行全文检索分词查询补偿,如果全文检索补偿查询的数据未满最大提示数量,最后就加入相识查询的结果。当然这里是一个简单的思路,复杂的还得根据实际需求实现。

构造数据

新建一张商品表,插入一千万条数据,name就是商品名字。

create table goods(id int, name varchar);

insert into goods select generate_series(1,10000000),md5(random()::varchar);

一、前模糊匹配及优化

实现SQL,每次输入就作为前缀模糊查询:

select * from goods where name like '123%' ;

这个简单的前模糊匹配SQL,可以使用B-Tree来加速优化模糊查询。

未建立索引时查询"123%"的商品名字,执行计划显示耗时大约为575ms:

explain (analyze,verbose,timing,costs,buffers) select * from goods where name like '123%' ;
========================================
Gather (cost=1000.00..136516.59 rows=1000 width=37) (actual time=1.390..572.857 rows=2364 loops=1)
Output: id, name
Workers Planned: 2
Workers Launched: 2
Buffers: shared hit=83334
-> Parallel Seq Scan on public.goods (cost=0.00..135416.59 rows=417 width=37) (actual time=0.750..528.116 rows=788 loops=3)
Output: id, name
Filter: ((goods.name)::text ~~ '123%'::text)
Rows Removed by Filter: 3332545
Buffers: shared hit=83334
Worker 0: actual time=1.032..511.776 rows=676 loops=1
Buffers: shared hit=24201
Worker 1: actual time=0.145..511.737 rows=755 loops=1
Buffers: shared hit=26101
Planning time: 0.065 ms
Execution time: 573.157 ms

优化1,建立索引(lc_collate方式)

通过lc_collate方式建立索引、也就是B-Tree索引。

  • lc_collate (string) 是指报告文本数据排序使用的区域
  • lc_collate (string) 是指报告文本数据排序使用的区域

建立索引脚本如下

create index idx_c on goods(name collate "C");

执行计划显示耗时为10ms以内:

explain (analyze,verbose,timing,costs,buffers) select * from goods where name like '123%' collate "C";

优化2,建立索引(操作符类varchar_pattern_ops方式)

建立索引脚本如下

create index idx_varchar on goods(name varchar_pattern_ops);

执行计划显示耗时为5ms以内:

explain (analyze,verbose,timing,costs,buffers) select * from goods where name like '123%' collate "C";

======================================
Bitmap Heap Scan on public.goods (cost=86.60..7681.10 rows=1000 width=37) (actual time=0.740..4.628 rows=2364 loops=1)
Output: id, name
Filter: ((goods.name)::text ~~ '123%'::text)
Heap Blocks: exact=2330
Buffers: shared hit=2351
-> Bitmap Index Scan on idx_varchar (cost=0.00..86.35 rows=2179 width=0) (actual time=0.487..0.487 rows=2364 loops=1)
Index Cond: (((goods.name)::text ~>=~ '123'::text) AND ((goods.name)::text ~<~ '124'::text))
Buffers: shared hit=21
Planning time: 0.139 ms
Execution time: 4.891 ms

二、全文检索和分词(通过gin索引优化加速)

注意:全文检索和下面的相识搜索都需要pg_trgm插件。所以先要执行:

create extension pg_trgm;

具体SQL如下,每次输入空格用&符号代替,最后接:*表示模糊检索。to_tsvector ,to_tsquery参阅postgresql全文检索文档。

SELECT name FROM goods WHERE to_tsvector('English',name) @@  to_tsquery('English','aaa&bbb&cc:*')

通过执行计划查看速度:接近8秒

。。。。。。。
Planning time: 0.129 ms
Execution time: 7986.176 ms

通过gin索引来优化加速,这里to_tsvector('English',name)就是一个表达式索引。

CREATE INDEX name_idx ON goods USING GIN(to_tsvector('English',name));

优化后后的执行计划,速度为13毫秒左右:

explain (analyze,verbose,timing,costs,buffers) SELECT name FROM goods WHERE to_tsvector('English',name) @@  to_tsquery('English','aaa&bbb&cc:*')
=================================================
Bitmap Heap Scan on public.goods (cost=88.04..109.24 rows=5 width=33) (actual time=17.343..17.353 rows=4 loops=1)
Output: name
Recheck Cond: (to_tsvector('english'::regconfig, (goods.name)::text) @@ '''aaa'' & ''bbb'' & ''cc'':*'::tsquery)
Heap Blocks: exact=1
Buffers: shared hit=473
-> Bitmap Index Scan on name_idx (cost=0.00..88.04 rows=5 width=0) (actual time=17.334..17.334 rows=4 loops=1)
Index Cond: (to_tsvector('english'::regconfig, (goods.name)::text) @@ '''aaa'' & ''bbb'' & ''cc'':*'::tsquery)
Buffers: shared hit=472
Planning time: 0.222 ms
Execution time: 13.381 ms

三、相似搜索

具体实现SQL,通过查询结果可以看到越相似,相似度越小,可以看到,在搜索aaa bbb的时候搜索出了aaa b6b,这就是相似搜索。

SELECT name ,name <-> 'aaa bbb' FROM goods WHERE name <-> 'aaa bbb' < 0.7 LIMIT 10
aaa bbb     	    0
aaa bbb ccc 0.333333
aaa ccc bbb 0.333333
aaa bbb ccc ddd 0.5
aaa b6b ccc 0.666667
aaa bbb ccsdsd 0.466667
aaa 0.5

PostgreSQL扩展知识

在第一种模糊查询中,可以使用关键字ILIKE替换LIKE, ILIKE表示字符串匹配时与大小写无关。这是一个PostgreSQL扩展、并不是标准SQL语法。

参考

postgresql索引官方文档

【搜索引擎】 PostgreSQL 10 实时全文检索和分词、相似搜索、模糊匹配实现类似Google搜索自动提示的更多相关文章

  1. 【搜索引擎】Solr Suggester 实现全文检索功能-分词和和自动提示

    功能需求 全文检索搜索引擎都会有这样一个功能:输入一个字符便自动提示出可选的短语: 要实现这种功能,可以利用solr的SuggestComponent,SuggestComponent这种方法利用Lu ...

  2. PHP+mysql数据库开发搜索功能:中英文分词+全文检索(MySQL全文检索+中文分词(SCWS))

    PHP+mysql数据库开发类似百度的搜索功能:中英文分词+全文检索 中文分词: a)   robbe PHP中文分词扩展: http://www.boyunjian.com/v/softd/robb ...

  3. Lucene全文检索_分词_复杂搜索_中文分词器

    1 Lucene简介 Lucene是apache下的一个开源的全文检索引擎工具包. 1.1 全文检索(Full-text Search)  1.1.1 定义 全文检索就是先分词创建索引,再执行搜索的过 ...

  4. [转帖] “王者对战”之 MySQL 8 vs PostgreSQL 10

    原贴地址:https://www.oschina.net/translate/showdown-mysql-8-vs-postgresql-10?lang=chs&page=2# 英文原版地址 ...

  5. 【ELK】【docker】【elasticsearch】1. 使用Docker和Elasticsearch+ kibana 5.6.9 搭建全文本搜索引擎应用 集群,安装ik分词器

    系列文章:[建议从第二章开始] [ELK][docker][elasticsearch]1. 使用Docker和Elasticsearch+ kibana 5.6.9 搭建全文本搜索引擎应用 集群,安 ...

  6. “王者对战”之 MySQL 8 vs PostgreSQL 10

    既然 MySQL 8 和 PostgreSQL 10 已经发布了,现在是时候回顾一下这两大开源关系型数据库是如何彼此竞争的. 在这些版本之前,人们普遍认为,Postgres 在功能集表现更出色,也因其 ...

  7. 重磅发布!阿里云推PostgreSQL 10 高可用版

    摘要: 近日,阿里云重磅发布PostgreSQL 10 高可用本地SSD盘版,相比原 9.4 版本又新增了JSONB.BRIN索引.GROUPING SETS/CUBE/ROLLUP.UPSERT等多 ...

  8. PostgreSQL 10.7 linux 主从配置

    PostgreSQL 10.7 主从安装 硬件环境 云服务商:华为云 Linux: CentOS7.1 工具:Xshell Xftp IP:114.115.251.168 Port: 5432 543 ...

  9. PostgreSQL 10 如何使用 PgAdmin3

    自从 PgAdmin4 出来以后,PgAdmin3 就停止开发了,PgAdmin 官网下载的 PgAdmin3 无法支持 PostgreSQL 10 或者更高版本的数据库服务器端. 但是 PgAdmi ...

随机推荐

  1. “Rsync” could not be found on your PATH

    Vagrant with VirtualBox on Windows10: “Rsync” could not be found on your PATH 使用agrant安装系统时,遇到的错误提示: ...

  2. DataTemplate

    DataTemplate作用是布局+数据绑定 使用DataTemplate 同时完成样式布局和数据绑定 <Window.Resources> <DataTemplate x:Key= ...

  3. WPF GridSplitter最好设置HorizontalAlignment和VerticalAlignment,否则不可以左右移动

    <Window x:Class="XamlTest.Window5"        xmlns="http://schemas.microsoft.com/winf ...

  4. jquery动态创建小广告

    <!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...

  5. MVC 异步调用

    @{    Layout = null;}<!DOCTYPE html><html><head>    <meta name="viewport&q ...

  6. 数据绑定(五)使用集合对象作为列表控件的ItemsSource

    原文:数据绑定(五)使用集合对象作为列表控件的ItemsSource ItemsSource属性可以接收一个IEnumerable接口派生类的实例作为自己的值,ItemsSource里存放的是一条一条 ...

  7. ASP如何实现注册后发送激活邮件?

    <% Sub Sendemail(title,content,email) Set jmail = Server.CreateObject("JMAIL.Message") ...

  8. 网络文件系统nfs文件系统使用(很全面)

    一.NFS简介 1.NFS就是Network FileSystem的缩写,它的最大功能就是可以通过网络让不同的机器,不同的操作系统彼此共享文件(sharefiles)——可以通过NFS挂载远程主机的目 ...

  9. PRML Chapter3

    曲线拟合的几种方法 最大似然估计MLE,最大后验概率MAP:MLE和MAP MLE 给定一堆数据,假如我们知道它是从某一种分布中随机取出来的,可是我们并不知道这个分布具体的参,即"模型已定, ...

  10. 15 款 jQuery 社交分享插件

    过去几年中社交媒体越来越流行了,能够分享音乐.视频.图像甚至是其他的 docs 文档到互联网上去,这样子还能够提高页面的点击量.通常,一些社交媒体插件都能允许你的用户分享你网站上的内容到其他的社交平台 ...