函数已改进,请使用新版本函数,参看PostgreSQL 黑科技-递规二分法切分汉字

1 模糊查询时,大多数情况下首先想到的是like '%关键字%'或基于gin索引的正则表达式,gin至少需要三个字符才会使用索引,对于汉语来说十分不方便;

2 在海量数据的情况下,基于like和gin索引的正则表达式均不理想时,一般采用分词后进行查询.

3 分词存在两个弊端

3.1 词库的维护是比较繁重的工作.当词库中没有的关键词会导致查询结果不正确.

3.2 历史数据的维护工作不好处理.新增关键词时,历史数据并不包含些新的关键词,使用新关键词查询时无法查询到历史数据.

4 不使用like/不使用正则/不使用分词并保证查询快捷准确的另一种方法

此方法的缺点是比较浪费空间,不过在当前相比较下来以空间换取时间的方法是值得的.

4.1 首先清除文本中的标点符号

drop function if exists clear_punctuation(text);
create or replace function clear_punctuation(text) returns text
as $$select regexp_replace($1,'[\ |\~|\`|\!|\@|\#|\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=|\||\\|\[|\]|\{|\}|\;|\:|\"|\''|\,|\<|\.|\>|\/|\?|\:|\。|\;|\,|\:|\“|\”|\(|\)|\、|\?|\《|\》]','','g');
$$ language sql strict immutable;

4.2 每两个字符做为一个词处理,将字符串转换为tsvector

drop function if exists str_to_tsvector(text);
create or replace function str_to_tsvector(text)
returns tsvector
as $$      declarev_count integer;v_txt text;v_txts text[];v_result tsvector;beginv_txt := clear_punctuation($1);--数组大小为字符数量-1v_count := length(v_txt)-1;if( v_count < 1 ) thenraise exception '输入参数("%")去除标点符号后至少需要2个字符',$1;end if;for i in 1..v_count loop      v_txts := array_append(v_txts, substring(v_txt,i,2));      end loop;--tsvector类型要求去除重复并排序with cte1 as(select f from unnest(v_txts) as f group by f),cte2 as(select f from cte1 order by f)select array_to_tsvector(array_agg(f)) into v_result from cte2;return v_result;end;
$$ language plpgsql strict immutable;

4.3 创建测试表

drop table if exists test_cond;
drop table if exists test;
create table test(objectid bigserial not null,                  --唯一编号name text not null,                               --名称newtime timestamptz default(now()) not null,    --首次添加时间lastime timestamptz,                            --最后一次修改时间  constraint pk_test_objectid primary key (objectid)
);
--rum需要大量的计算和写入,保存速度非常慢,因此创建表时设置unlogged标记
--unlogged标记不是绝对安全的,因此和主表分开
--虽然浪费了一定的磁盘空间,但可以最大程度保证写入速度
--test_cond表损坏后,通过主表可以很容易的重建,不过机率非常小
--test_cond中的数据通过触发器更新,不需要操作这个表
create unlogged table test_cond(objectid bigserial not null,                    --唯一编号keys tsvector not null,                           --关键字constraint pk_test_cond_objectid primary key (objectid),constraint fk_test_cond_objectid foreign key(objectid) references test(objectid) on delete cascade
);
create index idx_test_cond_keys on test_cond using rum(keys rum_tsvector_ops);

4.4 创建关联触发器

--test_cond表设置了级联删除,所以不需要delete触发
drop trigger if exists tri_test_change on test;
drop function if exists tri_test_trigger();
create or replace function tri_test_trigger()
returns trigger as $$ begin if (TG_OP = 'INSERT') then                   insert into test_cond(objectid,keys) values(NEW.objectid,str_to_tsvector(NEW.name));return NEW;elsif (TG_OP = 'UPDATE') thenupdate test_cond set keys=str_to_tsvector(NEW.name) where objectid=NEW.objectid;return NEW;            end if;RETURN NULL; end;
$$ language 'plpgsql' SECURITY DEFINER;
--test_cond依赖test表,因此只能在test成功后再触好,只能设置为after
create trigger tri_test_change after INSERT or UPDATE on test for each ROW EXECUTE PROCEDURE tri_test_trigger();

新版本函数,请参看PostgreSQL 黑科技-递规二分法切分汉字

--test_cond表设置了级联删除,所以不需要delete触发
drop trigger if exists tri_test_change on test;
drop function if exists tri_test_trigger();
create or replace function tri_test_trigger()
returns trigger as $$ begin if (TG_OP = 'INSERT') then                   insert into test_cond(objectid,keys) values(NEW.objectid,dichotomy_split_tsv(NEW.name));return NEW;elsif (TG_OP = 'UPDATE') thenupdate test_cond set keys=dichotomy_split_tsv(NEW.name) where objectid=NEW.objectid;return NEW;            end if;RETURN NULL; end;
$$ language 'plpgsql' SECURITY DEFINER;
--test_cond依赖test表,因此只能在test成功后再触好,只能设置为after
create trigger tri_test_change after INSERT or UPDATE on test for each ROW EXECUTE PROCEDURE tri_test_trigger();

4.5 创建随机生成汉字

drop function if exists gen_random_zh(int,int);
create or replace function gen_random_zh(int,int)returns text
as $$select string_agg(chr((random()*(20901-19968)+19968 )::integer) , '')  from generate_series(1,(random()*($2-$1)+$1)::integer);
$$ language sql;

4.6 生成测试数据

每调一次ins_test插入100万数据,可以同时调用ins_test插入更多数据,以便验证模糊查询性能

drop function if exists ins_test();
create or replace function ins_test() returns void
as $$declare v_index integer;beginv_index := 0;for i in 1..1000 loop   v_index := v_index + 1;insert into test(name)select gen_random_zh(8,32) as name from generate_series(1,1000);raise notice  '%', v_index;end loop;end;
$$ language plpgsql;
--每调一次ins_test插入100万数据
select ins_test();

4.7 验证触发器的update功能

update test set name='哈哈,我来验证了' where objectid=10000;

4.7 查询数据量

select count(*) from test;
select count(*) from test_cond;

5 模糊查询测试

5.1 创建查询转换函数

drop function if exists str_to_tsquery(text,boolean);
create or replace function str_to_tsquery(text,boolean default true)
returns tsquery
as $$      declarev_count integer;v_txt text;v_txts text[];v_result tsquery;beginv_txt := clear_punctuation($1);--数组大小为字符数量-1v_count := length(v_txt)-1;if( v_count < 1 ) thenraise exception '输入参数("%")去除标点符号后至少需要2个字符',$1;end if;for i in 1..v_count loop      v_txts := array_append(v_txts, substring(v_txt,i,2));      end loop;--tsquery类型要求去除重复并排序with cte1 as(select f from unnest(v_txts) as f group by f),cte2 as(select f from cte1 order by f)select string_agg(f, (case when $2 then '&' else '|' end ) )::tsquery into v_result from cte2;return v_result;end;
$$ language plpgsql strict immutable;

5.2 模糊数据

关键字字数越多,查询越准确,并且查询速度

--因优先级问题,此语句可能会不走rum索引
explain (analyze,verbose,costs,buffers,timing)
select f.* from test as f left join test_cond as s
on f.objectid=s.objectid
where name @@ (str_to_tsquery('価仴'))

建议采用下面的方式,保证查询使用rum索引

explain (analyze,verbose,costs,buffers,timing)
select f.* from test as f left join test_cond as s
on f.objectid=s.objectid
where s.keys @@ (select str_to_tsquery('哈哈'));explain (analyze,verbose,costs,buffers,timing)
select f.* from test as f left join test_cond as s
on f.objectid=s.objectid
where s.keys @@ (select str_to_tsquery('哈我'));explain (analyze,verbose,costs,buffers,timing)
select f.* from test as f left join test_cond as s
on f.objectid=s.objectid
where s.keys @@ (select str_to_tsquery('我来'));explain (analyze,verbose,costs,buffers,timing)
select f.* from test as f left join test_cond as s
on f.objectid=s.objectid
where s.keys @@ (select str_to_tsquery('来验'));explain (analyze,verbose,costs,buffers,timing)
select f.* from test as f left join test_cond as s
on f.objectid=s.objectid
where s.keys @@ (select str_to_tsquery('验证'));explain (analyze,verbose,costs,buffers,timing)
select f.* from test as f left join test_cond as s
on f.objectid=s.objectid
where s.keys @@ (select str_to_tsquery('证了'));explain (analyze,verbose,costs,buffers,timing)
select f.* from test as f left join test_cond as s
on f.objectid=s.objectid
where s.keys @@ (select str_to_tsquery('哈哈,我来验证了'));explain (analyze,verbose,costs,buffers,timing)
select f.* from test as f left join test_cond as s
on f.objectid=s.objectid
where s.keys @@ (select str_to_tsquery('侒亩'));

新版本函数,请参看PostgreSQL 黑科技-递规二分法切分汉字

explain (analyze,verbose,costs,buffers,timing)
select f.* from test as f left join test_cond as s
on f.objectid=s.objectid
where s.keys @@ (select dichotomy_split_tsq('哈哈'));explain (analyze,verbose,costs,buffers,timing)
select f.* from test as f left join test_cond as s
on f.objectid=s.objectid
where s.keys @@ (select dichotomy_split_tsq('哈我'));explain (analyze,verbose,costs,buffers,timing)
select f.* from test as f left join test_cond as s
on f.objectid=s.objectid
where s.keys @@ (select dichotomy_split_tsq('我来'));explain (analyze,verbose,costs,buffers,timing)
select f.* from test as f left join test_cond as s
on f.objectid=s.objectid
where s.keys @@ (select dichotomy_split_tsq('来验'));explain (analyze,verbose,costs,buffers,timing)
select f.* from test as f left join test_cond as s
on f.objectid=s.objectid
where s.keys @@ (select dichotomy_split_tsq('验证'));explain (analyze,verbose,costs,buffers,timing)
select f.* from test as f left join test_cond as s
on f.objectid=s.objectid
where s.keys @@ (select dichotomy_split_tsq('证了'));explain (analyze,verbose,costs,buffers,timing)
select f.* from test as f left join test_cond as s
on f.objectid=s.objectid
where s.keys @@ (select dichotomy_split_tsq('哈哈,我来验证了'));explain (analyze,verbose,costs,buffers,timing)
select f.* from test as f left join test_cond as s
on f.objectid=s.objectid
where s.keys @@ (select dichotomy_split_tsq('侒亩'));

5.3 验证级联删除功能

删除后再执行上面的sql查询均查不到数据

delete from test where objectid=10000;
``

PostgreSQL-模糊查询相关推荐

  1. postgresql模糊查询不区分大小写

    pg默认的模糊查询是区分大小写的,如果你想忽略大小写的话,酱紫做 修改sql 很简单,直接把like换成ilike select * from table_name where name ilike ...

  2. Greenplum 模糊查询 实践

    标签 PostgreSQL , Greenplum , orafunc , 阿里云HybridDB for PostgreSQL , reverse , like , 模糊查询 背景 文本搜索的需求分 ...

  3. 中文模糊查询性能优化 by PostgreSQL trgm

    前模糊,后模糊,前后模糊,正则匹配都属于文本搜索领域常见的需求. PostgreSQL在文本搜索领域除了全文检索,还有trgm是一般数据库没有的,甚至可能很多人没有听说过. 对于前模糊和后模糊,PG则 ...

  4. 用PostgreSQL 做实时高效 搜索引擎 - 全文检索、模糊查询、正则查询、相似查询、ADHOC查询...

    用PostgreSQL 做实时高效 搜索引擎 - 全文检索.模糊查询.正则查询.相似查询.ADHOC查询 作者 digoal 日期 2017-12-05 标签 PostgreSQL , 搜索引擎 , ...

  5. PostgreSQL 实时高效搜索 - 全文检索、模糊查询、正则查询、相似查询、ADHOC查询...

    标签 PostgreSQL , 搜索引擎 , GIN , ranking , high light , 全文检索 , 模糊查询 , 正则查询 , 相似查询 , ADHOC查询 背景 字符串搜索是非常常 ...

  6. PostgreSQL 百亿数据 秒级响应 正则及模糊查询

    原文: https://yq.aliyun.com/articles/7444?spm=5176.blog7549.yqblogcon1.6.2wcXO2 摘要: 正则匹配和模糊匹配通常是搜索引擎的特 ...

  7. 【postgreSQL】时间类型模糊查询

    关键代码 全部模糊查询,%直接用是在文本类型数据上,时间类型不行.转换一下进行查询 WHERE (TO_CHAR("c_statistic_time", 'hh24:mi:ss') ...

  8. mysql41 sphinx_抛弃mysql模糊查询,使用sphinx做专业索引

    Sphinx是一个基于SQL的全文检索引擎,可以结合MySQL,PostgreSQL做全文搜索,提供比数据库本身更专业的搜索功能特别为MySQL也设计了一个存储引擎插件,从此抛弃模糊查询吧. Sphi ...

  9. PostgreSQL 各种查询

    PostgreSQL的各种查询 (···*···)这个查询比较厉害 在表中,可能会包含重复值.这并不成问题,不过,有时您也许希望仅仅列出不同(distinct)的值.关键词 distinct用于返回唯 ...

  10. PGSQL 模糊查询不区分大小写

    PostgreSQL 和 MySql在字母的模糊查询上是不一样的,mysql的like是不区分大小写的,但是PostgreSQL 是区分的,要想做到不区分大小写需要使用ILIKE进行查询.

最新文章

  1. szu 寒训个人复习第一天 线段树入门单点修改,区间修改,以及线段树的扩展运用[线段树+dp][区间最大公约数]
  2. Lambda表达式很鸡肋?它到底有何用呢?
  3. c++中利用sizeof运算符计算结构体大小问题探讨
  4. 【GoLang】GoLang 遍历 map、slice、array方法
  5. ansible编译httpd playbook示例
  6. VS20“.NET研究”10自定义新建文件模版
  7. 谷歌为安卓系统加入Fast Pair技术 蓝牙耳机将实现设备自动切换
  8. ELK下钉钉邮件告警通知
  9. 半导体基础知识 二极管
  10. 面试题,互联网产品的盈利模式有哪些?
  11. LINUX 下SQL server 安装、配置及对接ceph功能性能测试
  12. 关于2D-DCT字典和克罗内克积以及二维字典的separable特性的个人理解
  13. 推荐系统和搜索引擎的比较
  14. 18年春季第一题 PAT甲级 1144 The Missing Number (20分) 上限感很重要
  15. 强化练习题(二)易错题
  16. 我们该怎么样看待人工智能?
  17. 国产数据库《人大金仓v8》适配过程问题解决记录
  18. 老婆小厂程序媛竟想在北京买房!
  19. Linux-软件安装管理
  20. 事务、提交、回滚、脏读、幻读等名词解释以及事务隔离级别详解

热门文章

  1. vscode html自定义标签自动补全,vscode代码编辑器的html标签自动补全如何设置
  2. 人人网开心网等SNS的新出路——用户选择型广告
  3. 解决Maven报错:Plugin execution not covered by lifecycle configuration
  4. 淘宝商品口红数据爬取与分析
  5. 超详细、超完整的C++教程(算是吧)
  6. 东莞精密塑胶模具生产制造的工艺流程
  7. 2021年最火的报表工具
  8. 女生适合学python吗_女生适合学习Python吗?
  9. Excel显示文件已损坏解决措施
  10. ChatGPT提示词,汇聚全网提示词,chatgpt提示词大全