文章目录
前言
前言
第一部分简单介绍 PostgreSQL 全文检索
第二部分演示全文检索对 json 、 jsonb 数据类型的支持 。
一、PostgreSQL 全文检索简介
对于大多数应用来说全文检索很少在数据库中实现,一般使用单独的全文检索引擎,例如基于 SQL 的全文检索引擎 Sphinx 。PostgreSQL 支持全文检索 ,对于规模不大的应用如果不想搭建专门的搜索引擎, PostgreSQL 的全文检索也可以满足需求 。
如果没有使用专门的搜索引 擎 ,大部检索需要通过数据库 like 操作匹配,这种检索方式的主要缺点在于:
不能很好地支持索引,通常需全表扫描检索数据,数据量大时检索性能很低 。
不提供检索结果排序,当输出结果数据量非常大时表现更加明显 。
PostgreSQL 全文检索能有效地解决这个问题 , PostgreSQL 全文检索通过以下两种数据类型来实现 。
在 PostgreSQL 10 版本之前全文检索不支持 json 和 jsonb 数据类型, 10 版本的一个重要特性是全文检索支持 json 和 jsonb 数据类型,这一小节将演示 10 版本的这个新特性 。
‘Hello,cat,how’ ‘are’ ‘is’ ‘miling!’ ‘u?cat’
(1 row)
字符串的内容被分隔成好几段
::tsvector只是做类型转换,没有进行数据标准化处理
to_tsvector函数可对于英文全文检索进行数据标准化处理
‘cat’:2 ‘hello’:1
(1 row)
2.tsquery
tsquery 表示一个文本查询 ,存储用于搜索的词, 并且支持布尔操作“&” 、“ | ”、“!”
将字符串转换成tsquery,没有做标准化
‘hello’ & ‘cat’
(1 row)
to_tsquery 函数可以执行标准化
‘hello’ & ‘cat’
(1 row)
全文检索示例:用于检索字符串是否包括“ hello”和“ cat ” 字符,本例中返回真。
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:=output∣∣substr(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
我想为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
在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这
我克隆了一个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
有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳
我有一个非常简单的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":
我正在使用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
我正在使用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("
我试图在我的网站上实现使用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
我想用sunspot重现以下原始solr查询q=exact_term_text:fooORterm_textv:foo*ORalternate_text:bar*但我无法通过标准的太阳黑子界面理解这是否可能以及如何实现,因为看起来:fulltext方法似乎不接受多个文本/搜索字段参数我不知道将什么参数作为第一个参数传递给fulltext,就好像我通过了"foo"或"bar"结果不匹配如果我传递一个空参数,我得到一个q=*:*范围过滤器(例如with(:term).starting_with('foo*')(顾名思义)作为过滤器查询应用,因此不参与评分。似乎可以手动编写字符串(或者可能使
我在一个简单的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'