[ruby on rails] postgresql分词搜索 pg_jieba 和 zhparser 方案

这篇具有很好参考价值的文章主要介绍了[ruby on rails] postgresql分词搜索 pg_jieba 和 zhparser 方案。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、 pg_jieba 方案

安装

brew install cmake
mkdir ~/tmp && cd ~/tmp && git clone https://github.com/jaiminpan/pg_jieba && cd pg_jieba
git submodule update --init --recursive
mkdir build && cd build
cmake -DCMAKE_PREFIX_PATH=/usr/local/opt/postgres ..
make install

测试

$ psql -d vapordb
psql (12.2)
Type "help" for help.

@vapordb=# CREATE EXTENSION pg_jieba;
CREATE EXTENSION
@vapordb=# SELECT * FROM to_tsvector('jiebacfg', '小明硕士毕业于中国科学院计算所,后在日本京都大学深造');
                                   to_tsvector
----------------------------------------------------------------------------------
 '中国科学院':5 '小明':1 '日本京都大学':10 '毕业':3 '深造':11 '硕士':2 '计算所':6
(1 row)

@vapordb=# \quit

在测试时,可以感觉到 jieba 的第一次分词有明显的延迟和卡顿,可以通过 Postgresq 预加载 jieba 的动态库和配置文件改善(/usr/local/var/postgres/postgresql.conf)。

#------------------------------------------------------------------------------
# CUSTOMIZED OPTIONS
#------------------------------------------------------------------------------

# Add settings for extensions here
# pg_jieba
shared_preload_libraries = 'pg_jieba.so'  # (change requires restart)
# default_text_search_config='pg_catalog.simple'; default value
default_text_search_config='jiebacfg'; uncomment to make 'jiebacfg' as default

二、 zhparser 方案

mac 安装 scws

brew install scws
scws -v
  • intel 安装在/usr/local 下
  • M1安装在/opt/homebrew 下,M1需要把相关文件拷贝给/usr/local

下载词典文件

mkdir -p /usr/local/etc/scws
curl "http://www.xunsearch.com/scws/down/scws-dict-chs-utf8.tar.bz2" | tar xvjf -
mv dict.utf8.xdb /usr/local/etc/scws/  #需要装在 /usr/local 下

测试效果

scws -c utf8 -d /usr/local/etc/scws/dict.utf8.xdb -r /usr/local/opt/scws/etc/rules.utf8.ini -M 9 "PostgreSQL 自带有一个简易的全文检索引擎"
PostgreSQL 自带 自 带 有 一个 一 个 简易 简 易 的 全文检索 全文 检索 全 文 检 索 引擎 引 擎
+--[scws(scws-cli/1.2.3)]----------+
| TextLen:   52                  |
| Prepare:   0.0007    (sec)     |
| Segment:   0.0002    (sec)     |
+--------------------------------+

安装 zhparser

mkdir ~/tmp && cd ~/tmp
git clone https://github.com/amutu/zhparser.git && cd zhparser
which pg_config
/usr/local/opt/libpq/bin/pg_config
PG_CONFIG=/usr/local/opt/libpq/bin/pg_config make && make install

测试 zhparser

$ psql -d vapordb
psql (12.2)
Type "help" for help.

CREATE EXTENSION zhparser;
#CREATE EXTENSION
CREATE TEXT SEARCH CONFIGURATION zhcfg (PARSER = zhparser);  
#CREATE TEXT SEARCH CONFIGURATION
#  添加名词(n)、动词(v)、形容词(a)、成语(i)、叹词(e)、习用语(l)和简称(j)七种分词策略:
ALTER TEXT SEARCH CONFIGURATION zhcfg ADD MAPPING FOR n,v,a,i,e,l,j WITH simple;
#ALTER TEXT SEARCH CONFIGURATION
SELECT to_tsvector('zhcfg', '人生苦短,我用 Python');
               to_tsvector
------------------------------------------
 'python':5 '人生':1 '用':4 '短':3 '苦':2
(1 row)

@vapordb=# \quit
  • 高亮
Post.select("content, ts_headline('zhcfg', content, '父亲', 'StartSel=<mark>, StopSel=</mark>, HighlightAll=true, MaxWords=35, MinWords=3, ShortWord=3, MaxFragments=0, FragmentDelimiter======') mark_content").where("to_tsvector('zhcfg', content) @@ plainto_tsquery('zhcfg', ?)", '父亲')
   									 ts_headline
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
 昏黄的路灯,照着他的<mark>父亲</mark>,他偎在那个墙角,身下垫着不知从哪里拣来的破纸箱。此刻,他正把身上的棉衣裹了又裹,而自己高中时围过的围巾,紧紧地缠在<mark>父亲</mark>头上。
(1 row)
  • StartSel, StopSel:该字符串分隔文档中出现的查询词,以区别于其他摘录词。 如果它们含有空格或逗号,你必须用双引号字符串。
  • MaxWords, MinWords:这些数字决定最长和最短的标题输出。
  • ShortWord:这个长度或更短的词在标题的开始和结束被丢弃。三个默认值消除了常见英语文章。
  • HighlightAll:布尔标志;如果为真,整个文档将作为标题,忽略了前面的三个参数。
  • MaxFragments:要显示的文本摘录或片段的最大数量。默认值零选择非片段标题的生成方法。 一个大于零的值选择基于片段的标题生成。此方法查找文本片段与尽可能多的查询词并在查询词周围延伸这些片段。 作为查询词的结果接近每一片段中间,每边都有词。每个片段至多是MaxWords ,并且长度为ShortWord或更短的词在每一个片段开始和结束被丢弃。 如果不是所有的查询词在文档中找到,则文档中开头的MinWords单片段将被显示。
  • FragmentDelimiter:当一个以上的片段显示时,通过字符串分隔这些片段。
  • 默认:StartSel=<b>, StopSel=</b>, MaxWords=35, MinWords=15, ShortWord=3, HighlightAll=FALSE, MaxFragments=0, FragmentDelimiter=" … "
  • zhcfg的一些配置
# 查看安装的解析器
select * from pg_ts_parser;
# 查看安装的全文搜索插件
select * from pg_ts_config;
# 查看zhparser支持的字典类型
select * from pg_catalog.ts_token_type('zhparser');  
# 查看已配置的字典映射
\dF+ zhcfg  
select * from pg_ts_config_map where mapcfg=(select oid from pg_ts_config where cfgname='zhcfg');
# 查看用到的字典类型
select ts_debug('zhcfg','三一') ;
可以查看到分词的token类型 如果不在之前的mapping内的话是不会被分词的

# 添加字典映射
ALTER TEXT SEARCH CONFIGURATION zhcfg ADD MAPPING FOR n,v,a,i,e,l,j WITH simple; #常用
ALTER TEXT SEARCH CONFIGURATION zhcfg ADD MAPPING FOR 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 WITH simple; #全部添加
# 字典对应意思
(97,  a, "adjective,        形容词")
(98,  b, "differentiation,  区别词")
(99,  c, "conjunction,      连词")
(100, d, "adverb,           副词")
(101, e, "exclamation,      感叹词")
(102, f, "position,         方位词")
(103, g, "root,             词根")
(104, h, "head,             前连接成分")
(105, i, "idiom,            成语")
(106, j, "abbreviation,     简称")
(107, k, "tail,             后连接成分")
(108, l, "tmp,              习用语")
(109, m, "numeral,          数词")
(110, n, "noun,             名词")
(111, o, "onomatopoeia,     拟声词")
(112, p, "prepositional,    介词")
(113, q, "quantity,         量词")
(114, r, "pronoun,          代词")
(115, s, "space,            处所词")
(116, t, "time,             时语素")
(117, u, "auxiliary,        助词")
(118, v, "verb,             动词")
(119, w, "punctuation,      标点符号")
(120, x, "unknown,          未知词")
(121, y, "modal,            语气词")
(122, z, "status,           状态词")

# 删除字典映射
ALTER TEXT SEARCH CONFIGURATION zhcfg DROP MAPPING FOR m;
# 忽略所有的标点等特殊符号
set zhparser.punctuation_ignore = on;
# 全部单字复合
set zhparser.multi_zall = on;
# 散字二元复合
set zhparser.multi_duality = on;
# 闲散文字自动以二字分词法聚合
set zhparser.seg_with_duality = on;
# 短词复合
set zhparser.multi_short = on;
# 重要单字复合
set zhparser.multi_zmain = on;
  • 自定义词库
    所有的自定义词都放在了 zhprs_custom_word 表里面,默认添加的自定义词的词性是 (120, x, “unknown, 未知词”),可能用到的 sql 包含但不局限于如下:
# 添加自定义词
insert into zhparser.zhprs_custom_word values('资金压力');
# 自定义词库也支持停止词功能,例如我们不希望词语'这是'单独作为一个分词,同样可以在自定义词库中插入对应的词语和控制符停止特定分词:
insert into zhparser.zhprs_custom_word(word, attr) values('这是','!');
# 删除自定义词
delete from zhparser.zhprs_custom_word where word = '安全高效';

# 添加/删除自定义分词之后需要执行以下命令才能使词库生效
select sync_zhprs_custom_word();

# 查询已存在的自定义词库
select * from zhparser.zhprs_custom_word;
  • 阿里云自定义词库
-- 初始的分词结果
SELECT to_tsquery('testzhcfg', '保障房资金压力');
-- 往自定义分词词典里面插入新的分词
insert into pg_ts_custom_word values ('保障房资');
-- 删除分词
delete from pg_ts_custom_word where word = '非金镶';
-- 使新的分词生效
select zhprs_sync_dict_xdb();
-- 退出此连接
\c
-- 重新查询,可以得到新的分词结果
SELECT to_tsquery('testzhcfg', '保障房资金压力');

阿里云rds自带pg_jieba和zhparser扩展,使用前需要先按要求设置参数shared_preload_libraries,然后创建扩展就行 阿里云rds中文分词链接

三、对比

两种方案效果上差不多.

$ psql -d vapordb
psql (12.2)
Type "help" for help.

@vapordb=# SELECT * FROM to_tsvector('jiebacfg', '小明硕士毕业于中国科学院计算所,后在日本京都大学深造');
                                   to_tsvector
----------------------------------------------------------------------------------
 '中国科学院':5 '小明':1 '日本京都大学':10 '毕业':3 '深造':11 '硕士':2 '计算所':6
(1 row)

@vapordb=# SELECT * FROM to_tsvector('zhcfg', '小明硕士毕业于中国科学院计算所,后在日本京都大学深造');
                                to_tsvector
---------------------------------------------------------------------------
 '中国科学院计算所':4 '小明':1 '日本京都大学':5 '毕业':3 '深造':6 '硕士':2
(1 row)

@vapordb=# \quit

四、如何使用

对于全文检索,有两种使用方式,大家可以权衡自己的内容进行选择。

  1. 在搜索的时候进行分词,然后搜索对应的字段。
  2. 提前把表中需要检索的字段进行分词,保存到一个新的字段中,再在这个字段上建立索引进行搜。

两种方案就是时间和空间的取舍:第一种方式创建索引简单,存储空间少,但是比较慢。第二种方案由于预先进行了分词并存储,浪费了空间,但是时间上肯定用得少。创建索引也有两种方案:gin 索引和 rum 索引。

第一种

创建索引:

CREATE INDEX idx_xxxx ON xxxx_table USING gin(to_tsvector('jiebacfg',
COALESCE(xx_field, '') || COALESCE(xxx_field, '')));

查询:

EXPLAIN ANALYSE SELECT * FROM xxxx_table
        WHERE to_tsvector('jiebacfg', COALESCE(xx_field, '') || COALESCE(xxx_field, '')) @@
        to_tsquery('jiebacfg', '关键字或者句子');

第二种

创建 tsv 字段和索引

ALTER TABLE xxxx_table ADD COLUMN tsv tsvector;
UPDATE xxxx_table SET tsv_field = to_tsvector('jiebacfg', COALESCE(xx_field, '') || COALESCE(xxx_field, ''));
CREATE INDEX idx_xxxx ON xxxx_table USING gin(tsv_field);

查询:

EXPLAIN ANALYSE SELECT * FROM xxxx_table WHERE tsv_field @@ to_tsquery('jiebacfg', '关键词或者句子');

当然因为是预先分词保存,所以需要在 update 的时候藉由 触发器 来更新 tsv 字段,。

CREATE TRIGGER tsvector_update BEFORE INSERT OR UPDATE
       ON xxxx_table FOR EACH ROW  EXECUTE PROCEDURE tsvector_update_trigger('tsv_field', 'jiebacfg', 'xx_field', 'xxx_field');

rum 索引

使用 rum 索引类似, 但是 rum 引擎默认是没有安装的,需要自己编译,暂时先不用了。

CREATE INDEX idx_xxxx ON xxxx_table USING rum(tsv_field rum_tsvector_ops);

另外 rum 还支持相似度的查询:文章来源地址https://www.toymoban.com/news/detail-579479.html

SELECT * FROM to_tsvector('jiebacfg', '小明硕士毕业于中国科学院计算所,后在日本京都大学深造');
SELECT * FROM rum_ts_distance(to_tsvector('jiebacfg', '小明硕士毕业于中国科学院计算所,后在日本京都大学深造') , to_tsquery('计算所'));

到了这里,关于[ruby on rails] postgresql分词搜索 pg_jieba 和 zhparser 方案的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【ruby on rails】rswag使用

    生成文档

    2024年02月16日
    浏览(31)
  • 框架分析(6)-Ruby on Rails

    link 主要对目前市面上常见的框架进行分析和总结,希望有兴趣的小伙伴们可以看一下,会持续更新的。希望各位可以监督我,我们一起学习进步。 Ruby on Rails(简称Rails)是一种使用Ruby编程语言开发的开源Web应用程序框架。它遵循MVC(Model-View-Controller)架构模式,旨在提供简

    2024年02月10日
    浏览(31)
  • 【ruby on rails】M1遇到的一些安装问题

    1. homebrew位置变了 原来的 Cellar Homebrew Caskroom 都是在 /usr/local/ 下面 M1在 /opt/homebrew 下面 2. 装ruby M1电脑安装ruby,装不上的问题 3. 装puma报错 3. 装nokogiri报错 4. 安装gem报错就用arch -arch x86_64 gem install试试 5. rails c 报错 ruby版本2.7.1的 enum 的bug 解决方案: 把ruby版本升级到2.7.5

    2024年02月15日
    浏览(30)
  • ubuntu 18.04 LTS安装ruby on rails

    由于令人‘烦恼’的网络问题,不用代理来正确安装rails已不可能。我自己配置了一个VirtualBox的ubuntu 18.04 LTS的虚拟机,在其中设置了rails的开发环境,你可以直接在virtualbox中导入它,然后即可拥有rails环境。在百度网盘中下载它,提取码:4zp4。用户名:myubuntu, 密码:123456

    2024年01月20日
    浏览(30)
  • 【漏洞复现】Ruby on Rails 路径穿越与任意文件读取漏洞(CVE-2019-5418)

    1. 漏洞简介 Ruby on Rails使用了指定参数的render file来渲染应用之外的视图,且会根据用户传入的Accept头来确定文件具体位置。我们可以通过修改访问某控制器的请求包,通过…/…/…/…/来达到路径穿越的目的,然后再通过{{来闭合模板查询路径,那我们访问的文件会被当做外部

    2024年02月04日
    浏览(44)
  • RubyMine for Mac/win:提升Ruby和Rails开发的强大IDE

    随着Ruby和Rails在Web开发领域的广泛应用,一款高效的开发工具对于提高生产力至关重要。JetBrains RubyMine正是这样一款值得信赖的集成开发环境(IDE)。作为Mac和Windows平台上的强大工具,RubyMine为开发者提供了卓越的代码编辑、实时分析和调试功能。 RubyMine的智能代码编辑器可

    2024年01月18日
    浏览(34)
  • Jieba分词统计词频及自定义分词词典

    统计词频的测试文本如下: 编写代码 运行代码查看统计结果 2.1 创建词典 首先我们创建一个 user_dict.txt 文本文件,在文件中添加我们需要的词典,如下所示: 2.2 编写代码 接着我们编写代码进行词典的测试,测试的文本如下: 首先我们 不导入 自定义的分词词典,看看分词

    2024年02月13日
    浏览(29)
  • NLP基础—jieba分词

    支持四种分词模式 精确模式 试图将句子最精确地切开,适合文本分析; 全模式 把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义; 搜索引擎模式 在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词。 paddle模式 利用Paddl

    2024年04月17日
    浏览(32)
  • python之jieba分词库使用

    一. 介绍 A. 什么是jieba库 jieba库是一款开源的中文分词工具,能够将中文文本切分成词语。 B. jieba库的特点和优势 支持四种分词模式:精确模式、全模式、搜索引擎模式和paddle模式。 提供自定义词典功能,可以添加、删除词语。 支持提取和词性标注。 提供Tokenize接口

    2024年02月16日
    浏览(25)
  • 数据分析之jieba分词使用详解

    在所有人类语言中,一句话、一段文本、一篇文章都是有一个个的词组成的。词是包含独立意义的最小文本单元,将长文本拆分成单个独立的词汇的过程叫做分词。分词之后,文本原本的语义将被拆分到在更加精细化的各个独立词汇中,词汇的结构比长文本简单,对于计算机

    2024年02月11日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包