jjzjj

PG-NoSQL特性:全文检索对 json 和 jsonb 数据类型的支持

XiaoYang Mum 2024-04-29 原文

文章目录
前言

一、​PostgreSQL 全文检索简介

1. tsvector

2.tsquery

3.英文全文检索例子

二、 json 、 jsonb 全文检索实践

1.查看to tsvector 函数

2.创建数据生成函数

3.创建 json 测试表

4.json 数据全文检索测试

总结

前言
第一部分简单介绍 PostgreSQL 全文检索
第二部分演示全文检索对 json 、 jsonb 数据类型的支持 。

一、​PostgreSQL 全文检索简介
对于大多数应用来说全文检索很少在数据库中实现,一般使用单独的全文检索引擎,例如基于 SQL 的全文检索引擎 Sphinx 。PostgreSQL 支持全文检索 ,对于规模不大的应用如果不想搭建专门的搜索引擎, PostgreSQL 的全文检索也可以满足需求 。

如果没有使用专门的搜索引 擎 ,大部检索需要通过数据库 like 操作匹配,这种检索方式的主要缺点在于:

不能很好地支持索引,通常需全表扫描检索数据,数据量大时检索性能很低 。
不提供检索结果排序,当输出结果数据量非常大时表现更加明显 。
PostgreSQL 全文检索能有效地解决这个问题 , PostgreSQL 全文检索通过以下两种数据类型来实现 。
在 PostgreSQL 10 版本之前全文检索不支持 json 和 jsonb 数据类型, 10 版本的一个重要特性是全文检索支持 json 和 jsonb 数据类型,这一小节将演示 10 版本的这个新特性 。

  1. tsvector
    tsvector 全文检索数据类型代表一个被优化的可以基于搜索的文挡,要将一串字符串转换成 tsvector 全文检索数据类型,代码如下所示:

postgres=# select ‘Hello,cat,how are u?cat is miling!’::tsvector;
tsvector

‘Hello,cat,how’ ‘are’ ‘is’ ‘miling!’ ‘u?cat’
(1 row)
字符串的内容被分隔成好几段

::tsvector只是做类型转换,没有进行数据标准化处理
to_tsvector函数可对于英文全文检索进行数据标准化处理

postgres=# select to_tsvector(‘english’,‘Hello cat,’);
to_tsvector

‘cat’:2 ‘hello’:1
(1 row)
2.tsquery
tsquery 表示一个文本查询 ,存储用于搜索的词, 并且支持布尔操作“&” 、“ | ”、“!”
将字符串转换成tsquery,没有做标准化

postgres=# select ‘hello&cat’::tsquery;
tsquery

‘hello’ & ‘cat’
(1 row)
to_tsquery 函数可以执行标准化

postgres=# select to_tsquery(‘hello&cat’);
to_tsquery

‘hello’ & ‘cat’
(1 row)
全文检索示例:用于检索字符串是否包括“ hello”和“ cat ” 字符,本例中返回真。

postgres=# select to_tsvector(‘english’,‘Hello cat,how are u’)@@to_tsquery(‘hello@dog’);
?column?

f
(1 row)
注:这里使用了带双参数的 to_tsvector 函数,函数 to_tsvector 双参数的格式如下所示:to_tsvector([ config regconfig, ] document text),本节 to_tsvector 函数指定了 config 参数为english ,如果不指定 config 参数,则默认使用 default_text_search_config 参数的配置 。

3.英文全文检索例子
下面演示一个英文全文检索示例,创建一张测试表并插入 200 万测试数据,如下所示:

create table test_search(id int4,name text);
insert into test_search(id,name) select n,n||‘_francs’ from generate_series(1,2000000) n;
select * from test_search where name like ‘1_francs’;
explain analyze select * from test_search where name like ‘1_francs’;
在这里插入图片描述
执行计划进行了全表扫描,执行时间为 145毫秒左右,性能很低
创建索引,再次执行计划

create index idx_gin_search on test_search using gin(to_tsvector(‘english’,name));
explain analyze select * from test_search where to_tsvector(‘english’,name)@@to_tsquery(‘english’,‘1_francs’);
在这里插入图片描述
创建索引后,以上查询走了索引并且执行时间下降到0.2毫秒,性能提升了。如果将 SQL 修改为不走索引

explain analyze select * from test_search where to_tsvector(name)@@to_tsquery(‘1_francs’);

在这里插入图片描述
由于创建索引时使用的是 to_tsvector(’english’,name)函数索引,带了两个参数,因此 where条件中的 to_tsvector 函数带两个参数才能走索引,而 to_tsvector(name)不走索引。

二、 json 、 jsonb 全文检索实践
1.查看to tsvector 函数
postgres-# \df to_tsvector
在这里插入图片描述
10 版本的 to_tsvector 函数支持的数据类型增加了 json 和 jsonb 。

2.创建数据生成函数
为了便于生成测试数据,创建以下两个函数用来随机生成指定长度的字符串, random_range(int4, int4)函数的代码如下所示:

create or replace function random_range(int4,int4)
returns int4
language sql
as KaTeX parse error: Can't use function '$' in math mode at position 14: select ($̲1+floor(($2-$1+…;
接着创建 random_text_simple(length int4)函数,此函数会调用 random_range(int4, int4)函数,其代码如下所示 :

create or replace function random_text_simple(length int4)
returns text
language plpgsql
as d e c l a r e p o s s i b l e c h a r s t e x t : = ′ 0123456789 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z ′ ; o u t p u t t e x t : = ′ ′ ; i i n t 4 ; p o s i n t ; b e g i n f o r i i n 1.. l e n g t h l o o p p o s : = r a n d o m r a n g e ( 1 , l e n g t h ( p o s s i b l e c h a r s ) ) ; o u t p u t : = o u t p u t ∣ ∣ s u b s t r ( p o s s i b l e c h a r s , p o s , 1 ) ; e n d l o o p ; r e t u r n o u t p u t ; e n d ; declare possible_chars text:='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'; output text:=''; i int4; pos int; begin for i in 1..length loop pos:=random_range(1,length(possible_chars)); output:=output||substr(possible_chars,pos,1); end loop; return output; end; declarepossiblecharstext:=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ;outputtext:=;iint4;posint;beginforiin1..lengthlooppos:=randomrange(1,length(possiblechars));output:=outputsubstr(possiblechars,pos,1);endloop;returnoutput;end;;
random_text_simple(length int4)函数可以随机生成指定长度字符串,下列代码随机生成含3位和6位字符的字符串 :

select random_text_simple(3);
select random_text_simple(6);
在这里插入图片描述
后面会使用这个函数生成测试数据

3.创建 json 测试表
创建 user_ini 测试表,并通过 random_text_simple(length int4) 函数插入 100 万随机生成的六位字符的字符串 ,作为测试数据 , 如下所示 :

create table user_ini_text(id int4,user_id int8,user_name character varying(64),create_time timestamp(6) with time zone default clock_timestamp());
insert into user_ini_text(id,user_id,user_name) select r,round(random()*1000000),random_text_simple(6) from generate_series(1,1000000) as r;
select * from user_ini_text limit 1;
4.json 数据全文检索测试
使用全文检索查询表 user_ini_text且on 的 user_name 字段中包含 U6XUW4 字符的记录,如下所示 :

select * from user_ini_text where to_tsvector(‘english’,user_name)@@to_tsquery(‘ENGLISH’,‘U6XUW4’);
explain analyze select * from user_ini_text where to_tsvector(‘english’,user_name)@@to_tsquery(‘ENGLISH’,‘U6XUW4’);
正常执行说明全文检索支持 json 数据类型 ,只是上述 SQL 进行了全表扫描,性能较低,执行时间为738毫秒
在这里插入图片描述
创建索引,再次执行SQL查看执行计划

create index idx_gin_search_json on user_ini_text using gin(to_tsvector(‘english’,user_name));
create index idx_gin_search_json on user_ini_text using gin(to_tsvector(‘english’,user_name));
在这里插入图片描述
从上述执行计划看出走了索引, 并且执行时间降为 0.034 毫秒,性能非常不错 。

总结
前一部分对 PostgreSQL 全文检索的实现做了简单介绍,并且给出了一个英文检索的例子,后一部分通过示例介绍了 PostgreSQL的一个新特性,即全文检索对 json、jsonb类型的支持 。PostgreSQL 对中文检索也是支持的, 可自行测试 。

csdn:https://blog.csdn.net/qq961573863/article/details/127470028
墨天轮:https://www.modb.pro/db/530796
公众号:Xiao Yang Mum
image.png

有关PG-NoSQL特性:全文检索对 json 和 jsonb 数据类型的支持的更多相关文章

  1. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

  2. ruby-on-rails - Rails HTML 请求渲染 JSON - 2

    在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这

  3. ruby-on-rails - 错误 : Error installing pg: ERROR: Failed to build gem native extension - 2

    我克隆了一个rails仓库,我现在正尝试捆绑安装背景:OSXElCapitanruby2.2.3p173(2015-08-18修订版51636)[x86_64-darwin15]rails-v在您的Gemfile中列出的或native可用的任何gem源中找不到gem'pg(>=0)ruby​​'。运行bundleinstall以安装缺少的gem。bundleinstallFetchinggemmetadatafromhttps://rubygems.org/............Fetchingversionmetadatafromhttps://rubygems.org/...Fe

  4. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

  5. ruby-on-rails - 如何使用 Rack 接收 JSON 对象 - 2

    我有一个非常简单的RubyRack服务器,例如:app=Proc.newdo|env|req=Rack::Request.new(env).paramspreq.inspect[200,{'Content-Type'=>'text/plain'},['Somebody']]endRack::Handler::Thin.run(app,:Port=>4001,:threaded=>true)每当我使用JSON对象向服务器发送POSTHTTP请求时:{"session":{"accountId":String,"callId":String,"from":Object,"headers":

  6. ruby - 使用 postgres.app 在 rvm 下要求 pg 时出错 - 2

    我正在使用Postgres.app在OSX(10.8.3)上。我已经修改了我的PATH,以便应用程序的bin文件夹位于所有其他文件夹之前。Rammy:~phrogz$whichpg_config/Applications/Postgres.app/Contents/MacOS/bin/pg_config我已经安装了rvm并且可以毫无错误地安装pggem,但是当我需要它时我得到一个错误:Rammy:~phrogz$gem-v1.8.25Rammy:~phrogz$geminstallpgFetching:pg-0.15.1.gem(100%)Buildingnativeextension

  7. ruby - 用 YAML.load 解析 json 安全吗? - 2

    我正在使用ruby2.1.0我有一个json文件。例如:test.json{"item":[{"apple":1},{"banana":2}]}用YAML.load加载这个文件安全吗?YAML.load(File.read('test.json'))我正在尝试加载一个json或yaml格式的文件。 最佳答案 YAML可以加载JSONYAML.load('{"something":"test","other":4}')=>{"something"=>"test","other"=>4}JSON将无法加载YAML。JSON.load("

  8. ruby-on-rails - 使用 HTTP.get_response 检索 Facebook 访问 token 时出现 Rails EOF 错误 - 2

    我试图在我的网站上实现使用Facebook登录功能,但在尝试从Facebook取回访问token时遇到障碍。这是我的代码:ifparams[:error_reason]=="user_denied"thenflash[:error]="TologinwithFacebook,youmustclick'Allow'toletthesiteaccessyourinformation"redirect_to:loginelsifparams[:code]thentoken_uri=URI.parse("https://graph.facebook.com/oauth/access_token

  9. ruby-on-rails - Sunspot:如何对具有不同值的多个字段进行全文查询? - 2

    我想用sunspot重现以下原始solr查询q=exact_term_text:fooORterm_textv:foo*ORalternate_text:bar*但我无法通过标准的太阳黑子界面理解这是否可能以及如何实现,因为看起来:fulltext方法似乎不接受多个文本/搜索字段参数我不知道将什么参数作为第一个参数传递给fulltext,就好像我通过了"foo"或"bar"结果不匹配如果我传递一个空参数,我得到一个q=*:*范围过滤器(例如with(:term).starting_with('foo*')(顾名思义)作为过滤器查询应用,因此不参与评分。似乎可以手动编写字符串(或者可能使

  10. ruby-on-rails - Rails 渲染带有驼峰命名法的 json 对象 - 2

    我在一个简单的RailsAPI中有以下Controller代码:classApi::V1::AccountsControllerehead:not_foundendendend问题在于,生成的json具有以下格式:{id:2,name:'Simpleaccount',cash_flows:[{id:1,amount:34.3,description:'simpledescription'},{id:2,amount:1.12,description:'otherdescription'}]}我需要我生成的json是camelCase('cashFlows'而不是'cash_flows'

随机推荐