配置 jieba结巴分词 for PolarDB 实现数据库高性能文本分词搜索

本文涉及的产品
云原生数据库 PolarDB 分布式版,标准版 2核8GB
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
云原生数据库 PolarDB MySQL 版,通用型 2核4GB 50GB
简介: 背景PolarDB 的云原生存算分离架构, 具备低廉的数据存储、高效扩展弹性、高速多机并行计算能力、高速数据搜索和处理; PolarDB与计算算法结合, 将实现双剑合璧, 推动业务数据的价值产出, 将数据变成生产力.本文将介绍PolarDB结合jieba分词, 实现高效率的中文分词以及中文分词搜索....

背景

PolarDB 的云原生存算分离架构, 具备低廉的数据存储、高效扩展弹性、高速多机并行计算能力、高速数据搜索和处理; PolarDB与计算算法结合, 将实现双剑合璧, 推动业务数据的价值产出, 将数据变成生产力.

本文将介绍PolarDB结合jieba分词, 实现高效率的中文分词以及中文分词搜索.

测试环境为macos+docker, polardb部署请参考如何用 PolarDB 证明巴菲特的投资理念 - 包括PolarDB简单部署

部署pg_jieba on PolarDB

编译pg_jieba

git clone --depth=1 https://github.com/jaiminpan/pg_jieba  
  
cd pg_jieba  
  
# initilized sub-project  
git submodule update --init --recursive  
  
mkdir build  
cd build  
  
cmake -DCMAKE_PREFIX_PATH=/home/postgres/tmp_basedir_polardb_pg_1100_bld ..  
  
make  
make install  

安装pg_jieba插件:

create extension pg_jieba ;  

测试中文分词:

select * from to_tsquery('jiebacfg', '是拖拉机学院手扶拖拉机专业的。不用多久,我就会升职加薪,当上CEO,走上人生巅峰。');  
select * from to_tsvector('jiebacfg', '是拖拉机学院手扶拖拉机专业的。不用多久,我就会升职加薪,当上CEO,走上人生巅峰。');  
select * from ts_token_type('jieba');  
select * from ts_debug('jiebacfg', '是拖拉机学院手扶拖拉机专业的。不用多久,我就会升职加薪,当上CEO,走上人生巅峰。');  
  
  
postgres=# create extension pg_jieba ;  
CREATE EXTENSION  
postgres=# select * from to_tsquery('jiebacfg', '是拖拉机学院手扶拖拉机专业的。不用多久,我就会升职加薪,当上CEO,走上人生巅峰。');  
                                                            to_tsquery                                                              
----------------------------------------------------------------------------------------------------------------------------------  
 '拖拉机' & '学院' & '手扶拖拉机' & '专业' & '不用' & '多久' & '会' & '升职' & '加薪' & '当上' & 'ceo' & '走上' & '人生' & '巅峰'  
(1 row)  
  
postgres=# select * from to_tsvector('jiebacfg', '是拖拉机学院手扶拖拉机专业的。不用多久,我就会升职加薪,当上CEO,走上人生巅峰。');  
                                                                to_tsvector                                                                   
--------------------------------------------------------------------------------------------------------------------------------------------  
 'ceo':18 '不用':8 '专业':5 '人生':21 '会':13 '加薪':15 '升职':14 '多久':9 '学院':3 '巅峰':22 '当上':17 '手扶拖拉机':4 '拖拉机':2 '走上':20  
(1 row)  
  
postgres=# select * from ts_token_type('jieba');  
 tokid | alias |         description           
-------+-------+-----------------------------  
     1 | eng   | letter  
     2 | nz    | other proper noun  
     3 | n     | noun  
     4 | m     | numeral  
     5 | i     | idiom  
     6 | l     | temporary idiom  
     7 | d     | adverb  
     8 | s     | space  
     9 | t     | time  
    10 | mq    | numeral-classifier compound  
    11 | nr    | person's name  
    12 | j     | abbreviate  
    13 | a     | adjective  
    14 | r     | pronoun  
    15 | b     | difference  
    16 | f     | direction noun  
    17 | nrt   | nrt  
    18 | v     | verb  
    19 | z     | z  
    20 | ns    | location  
    21 | q     | quantity  
    22 | vn    | vn  
    23 | c     | conjunction  
    24 | nt    | organization  
    25 | u     | auxiliary  
    26 | o     | onomatopoeia  
    27 | zg    | zg  
    28 | nrfg  | nrfg  
    29 | df    | df  
    30 | p     | prepositional  
    31 | g     | morpheme  
    32 | y     | modal verbs  
    33 | ad    | ad  
    34 | vg    | vg  
    35 | ng    | ng  
    36 | x     | unknown  
    37 | ul    | ul  
    38 | k     | k  
    39 | ag    | ag  
    40 | dg    | dg  
    41 | rr    | rr  
    42 | rg    | rg  
    43 | an    | an  
    44 | vq    | vq  
    45 | e     | exclamation  
    46 | uv    | uv  
    47 | tg    | tg  
    48 | mg    | mg  
    49 | ud    | ud  
    50 | vi    | vi  
    51 | vd    | vd  
    52 | uj    | uj  
    53 | uz    | uz  
    54 | h     | h  
    55 | ug    | ug  
    56 | rz    | rz  
(56 rows)  
  
postgres=#  select * from ts_debug('jiebacfg', '是拖拉机学院手扶拖拉机专业的。不用多久,我就会升职加薪,当上CEO,走上人生巅峰。');  
 alias |  description  |   token    | dictionaries | dictionary |   lexemes      
-------+---------------+------------+--------------+------------+--------------  
 v     | verb          | 是         | {jieba_stem} | jieba_stem | {}  
 n     | noun          | 拖拉机     | {jieba_stem} | jieba_stem | {拖拉机}  
 n     | noun          | 学院       | {jieba_stem} | jieba_stem | {学院}  
 n     | noun          | 手扶拖拉机 | {jieba_stem} | jieba_stem | {手扶拖拉机}  
 n     | noun          | 专业       | {jieba_stem} | jieba_stem | {专业}  
 uj    | uj            | 的         | {jieba_stem} | jieba_stem | {}  
 x     | unknown       | 。         | {jieba_stem} | jieba_stem | {}  
 v     | verb          | 不用       | {jieba_stem} | jieba_stem | {不用}  
 m     | numeral       | 多久       | {jieba_stem} | jieba_stem | {多久}  
 x     | unknown       | ,         | {jieba_stem} | jieba_stem | {}  
 r     | pronoun       | 我         | {jieba_stem} | jieba_stem | {}  
 d     | adverb        | 就         | {jieba_stem} | jieba_stem | {}  
 v     | verb          | 会         | {jieba_stem} | jieba_stem | {会}  
 v     | verb          | 升职       | {jieba_stem} | jieba_stem | {升职}  
 nr    | person's name | 加薪       | {jieba_stem} | jieba_stem | {加薪}  
 x     | unknown       | ,         | {jieba_stem} | jieba_stem | {}  
 t     | time          | 当上       | {jieba_stem} | jieba_stem | {当上}  
 eng   | letter        | CEO        | {jieba_stem} | jieba_stem | {ceo}  
 x     | unknown       | ,         | {jieba_stem} | jieba_stem | {}  
 v     | verb          | 走上       | {jieba_stem} | jieba_stem | {走上}  
 n     | noun          | 人生       | {jieba_stem} | jieba_stem | {人生}  
 n     | noun          | 巅峰       | {jieba_stem} | jieba_stem | {巅峰}  
 x     | unknown       | 。         | {jieba_stem} | jieba_stem | {}  
(23 rows)  

分词索引测试

GIN

生成10万条随机分词数据

create or replace function gen_rand_ts(tslen int) returns tsvector as $$      
  select array_to_tsvector(array_agg(substring(md5(random()::text),1,8))) from generate_series(1,$1);      
$$ language sql strict;    
  
create unlogged table test (id int, vec tsvector);  
  
insert into test select generate_series(1,100000), gen_rand_ts(24);  

创建索引

create index on test using gin (vec);  

查询测试:

postgres=# select * from test limit 10;  
 id |                                                                                                                                   vec                                                                 
                                                                      
----+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------  
--------------------------------------------------------------------  
  1 | '0eed2ca6' '149ae774' '260d6cae' '2bde3230' '38ce089c' '3fdfb67c' '40bf233a' '41825567' '52de4ebb' '5708b49d' '63bdd9ea' '650f2dbf' '6d35d142' '7c711c0d' '7e4e028f' '913802bf' 'a8a14013' 'b6aa8ba4  
' 'd9f595e6' 'dc054607' 'dee1a2f7' 'e5b6d7e8' 'eacb6356' 'eee81aaf'  
  2 | '00bf8fbc' '117b7b5c' '1e4c8295' '2d379ff7' '2e263dcb' '48967fe5' '4f20db40' '5f7aefcd' '616cbb8e' '81d4e152' '876b2318' '8c18f4c3' '8e732b6f' '94f6b13b' '9c53cb8e' 'aedca11c' 'b56c7ed4' 'c5008853  
' 'cc407ea8' 'd4f3d5a1' 'd63ca731' 'd87514ec' 'f9626af4' 'fa5b7458'  
  3 | '0e3b6147' '13674c4d' '16463e9b' '32894aca' '3a15d964' '453c9a26' '54664d82' '5cb0e40d' '62c8ca30' '6d0ebc3a' '6ee0a517' '71ccfeb5' '7e75a9d5' '7f61f401' '87b5f2cb' '8f1c6274' '976dff7f' '9b7a6758  
' 'af9c624e' 'e5422d57' 'ed7bb9d4' 'edc039a2' 'efe1e5fa' 'f9db8132'  
  4 | '118bf21c' '2087d303' '2579c220' '3733357a' '503b50ec' '56104ea2' '573b9ea9' '58a665af' '59250bad' '86abf8a9' '8a3b5a72' '8d8bb478' 'a16b8bd8' 'ac966a06' 'af4eabd8' 'b09ccbb5' 'b2d7aac4' 'b5134f1b  
' 'b5228857' 'b6836add' 'bcafbce0' 'd1ca5a3a' 'e8588e37' 'f6ffe6b0'  
  5 | '01876ad5' '07a8a579' '0a33ce9e' '0b5bbdd4' '10b00efe' '118fae91' '1c12acee' '2d74f4eb' '2d99481c' '41483d1c' '6864b85e' '7ba1937f' '8a6ccb01' '9c1ae58b' 'a251fd3d' 'a936eecd' 'b560d231' 'baa6927f  
' 'd78f04c6' 'dabff656' 'e5d975c0' 'f0598071' 'f819b029' 'fb202c1a'  
  6 | '1c6eea85' '23f37dd9' '28151030' '319fa87f' '447ddc9d' '45dcc30a' '5269c7c2' '77184ff9' '792793c2' '81f63a78' '87b67199' '8ddc346f' '9dbc6f02' 'a4130ee7' 'a4b21300' 'a8ae9afe' 'ae54596a' 'b01e580a  
' 'c17caa99' 'c7784bd5' 'd27a19ce' 'df21c10f' 'e383a9d0' 'fde1f572'  
  7 | '1c6e6d6e' '209c45cf' '23415a93' '292ba393' '3d64d313' '49cf134a' '4a1a1f0d' '4c7e54a7' '4e74180a' '5054e77e' '5882f01f' '59c25e04' '69eb2f87' '6f2ed6bb' '7c830771' '81c415f5' '975f413a' 'a3dc8375  
' 'a5a38d13' 'b1f83c28' 'bb62f740' 'c8bab4d1' 'd947163c' 'f3a81f80'  
  8 | '0800c7b2' '0ffbe32e' '19f84945' '1c001bd3' '1f3f5826' '2e13cca1' '36ca5372' '3abc8149' '516878e9' '534357fc' '67cb7af9' '69a7849d' '8c134ad3' '8d87ed42' '96069ef5' '98bfcdbe' 'b4b0ffa1' 'bc61912a  
' 'ddf1d8e6' 'e07722ea' 'e68ffbbf' 'f0751b01' 'f12cb4b9' 'fe0a7c4c'  
  9 | '14588466' '1b16dfff' '25339aa7' '4874dc00' '4c6bb5bf' '510c8f7b' '59cbfb21' '70372c94' '7db5e3c2' '85f68385' '8b0e7746' '9596e2d0' '997ca4d3' '9f4df7dc' 'b1726109' 'c42ae6e4' 'dc759b2d' 'e378d2d5  
' 'e956bc2b' 'ea5c6ed2' 'f0e58f77' 'f24f74b1' 'fa6df884' 'fa8edffb'  
 10 | '0188c7ac' '09a75236' '15fb2eee' '1dc80e6e' '2f543594' '3559f46a' '4369adcd' '477410ed' '5df678d0' '799bc453' '80ad7901' '81871ec1' '92faa899' '94c9cf0f' '971d699f' 'a002241a' 'a1636465' 'aee34bbb  
' 'b08f2f0c' 'b697c161' 'b8f290b9' 'd0acf8b4' 'd3beb05b' 'f8ca2a66'  
(10 rows)  
  
postgres=# explain select * from test where vec @@ '52de4ebb & 41825567'::tsquery ;  
                                 QUERY PLAN                                   
----------------------------------------------------------------------------  
 Bitmap Heap Scan on test  (cost=36.02..43.91 rows=2 width=300)  
   Recheck Cond: (vec @@ '''52de4ebb'' & ''41825567'''::tsquery)  
   ->  Bitmap Index Scan on test_vec_idx  (cost=0.00..36.02 rows=2 width=0)  
         Index Cond: (vec @@ '''52de4ebb'' & ''41825567'''::tsquery)  
(4 rows)  
  
postgres=# select * from test where vec @@ '52de4ebb & 41825567'::tsquery ;  
 id |                                                                                                                                   vec                                                                 
                                                                      
----+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------  
--------------------------------------------------------------------  
  1 | '0eed2ca6' '149ae774' '260d6cae' '2bde3230' '38ce089c' '3fdfb67c' '40bf233a' '41825567' '52de4ebb' '5708b49d' '63bdd9ea' '650f2dbf' '6d35d142' '7c711c0d' '7e4e028f' '913802bf' 'a8a14013' 'b6aa8ba4  
' 'd9f595e6' 'dc054607' 'dee1a2f7' 'e5b6d7e8' 'eacb6356' 'eee81aaf'  
(1 row)  
  
Time: 0.768 ms  
  
  
postgres=# set enable_bitmapscan =off;  
SET  
Time: 0.887 ms  
postgres=# explain select * from test where vec @@ '52de4ebb & 41825567'::tsquery ;  
                        QUERY PLAN                           
-----------------------------------------------------------  
 Seq Scan on test  (cost=0.00..5417.00 rows=2 width=300)  
   Filter: (vec @@ '''52de4ebb'' & ''41825567'''::tsquery)  
(2 rows)  
  
Time: 1.136 ms  
  
  
postgres=# select * from test where vec @@ '52de4ebb & 41825567'::tsquery ;  
 id |                                                                                                                                   vec                                                                 
                                                                      
----+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------  
--------------------------------------------------------------------  
  1 | '0eed2ca6' '149ae774' '260d6cae' '2bde3230' '38ce089c' '3fdfb67c' '40bf233a' '41825567' '52de4ebb' '5708b49d' '63bdd9ea' '650f2dbf' '6d35d142' '7c711c0d' '7e4e028f' '913802bf' 'a8a14013' 'b6aa8ba4  
' 'd9f595e6' 'dc054607' 'dee1a2f7' 'e5b6d7e8' 'eacb6356' 'eee81aaf'  
(1 row)  
  
Time: 51.815 ms  
postgres=# select * from test where vec @@ '52de4ebb & 41825567'::tsquery ;  
 id |                                                                                                                                   vec                                                                 
                                                                      
----+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------  
--------------------------------------------------------------------  
  1 | '0eed2ca6' '149ae774' '260d6cae' '2bde3230' '38ce089c' '3fdfb67c' '40bf233a' '41825567' '52de4ebb' '5708b49d' '63bdd9ea' '650f2dbf' '6d35d142' '7c711c0d' '7e4e028f' '913802bf' 'a8a14013' 'b6aa8ba4  
' 'd9f595e6' 'dc054607' 'dee1a2f7' 'e5b6d7e8' 'eacb6356' 'eee81aaf'  
(1 row)  
  
Time: 49.055 ms  

10万条文本向量, 搜索命中1条. 性能参考:

GIN索引 0.768 ms VS 全表扫描 49.055 ms

参数配置

配置PolarDB 所有计算节点, 重启polardb即可:

shared_preload_libraries = 'pg_jieba.so, ... 其他已预加载lib'   # (change requires restart)  
  
# default_text_search_config='pg_catalog.simple'   # default value  
  
default_text_search_config='jiebacfg'       # uncomment to make 'jiebacfg' as default  
cd ~  
vi tmp_master_dir_polardb_pg_1100_bld/postgresql.conf  
vi tmp_replica_dir_polardb_pg_1100_bld1/postgresql.conf  
vi tmp_replica_dir_polardb_pg_1100_bld2/postgresql.conf  
重启polardb, 检查是否加载  
  
postgres=# show shared_preload_libraries ;  
                                                                                  shared_preload_libraries                                                                                     
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------  
 pg_jieba.so,$libdir/polar_px,$libdir/polar_vfs,$libdir/polar_worker,$libdir/pg_stat_statements,$libdir/auth_delay,$libdir/auto_explain,$libdir/polar_monitor_preload,$libdir/polar_stat_sql  
(1 row)  
  
select * from to_tsvector('是拖拉机学院手扶拖拉机专业的。不用多久,我就会升职加薪,当上CEO,走上人生巅峰。');  
  
postgres=# select * from to_tsvector('是拖拉机学院手扶拖拉机专业的。不用多久,我就会升职加薪,当上CEO,走上人生巅峰。');  
                                                                to_tsvector                                                                   
--------------------------------------------------------------------------------------------------------------------------------------------  
 'ceo':18 '不用':8 '专业':5 '人生':21 '会':13 '加薪':15 '升职':14 '多久':9 '学院':3 '巅峰':22 '当上':17 '手扶拖拉机':4 '拖拉机':2 '走上':20  
(1 row)  

感谢志铭贡献的中文分词插件pg_jieba.

参考

如果想了解GIN索引的原理请参考:

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
22天前
|
自然语言处理 关系型数据库 MySQL
如何在mysql数据库里进行文本的相似度排序?
【8月更文挑战第28天】如何在mysql数据库里进行文本的相似度排序?
191 62
|
7天前
|
关系型数据库 MySQL Serverless
探索PolarDB MySQL版:Serverless数据库的灵活性与性能
本文介绍了个人开发者对阿里云PolarDB MySQL版,特别是其Serverless特性的详细评测体验。评测涵盖了产品初体验、性能观测、Serverless特性深度评测及成本效益分析等方面。尽管试用过程中遇到一些小问题,但总体而言,PolarDB MySQL版表现出色,提供了高性能、高可用性和灵活的资源管理,是个人开发者和企业用户的优秀选择。
|
14天前
|
关系型数据库 分布式数据库 数据库
2024年全国大学生计算机系统能力大赛PolarDB数据库创新设计赛(天池杯)等你来战!
2024年全国大学生计算机系统能力大赛PolarDB数据库创新设计赛(天池杯)等你来战!
2024年全国大学生计算机系统能力大赛PolarDB数据库创新设计赛(天池杯)等你来战!
|
6天前
|
关系型数据库 MySQL 分布式数据库
PolarDB MySQL数据库场景体验与测评
本文介绍如何在PolarDB上部署数据库,包括登录控制台、配置账号与数据库管理、执行SQL查询及调整Serverless配置等内容。通过创建测试表和数据操作演示了基本数据库管理功能,并展示了如何设置资源弹性扩缩、监控及备份数据。此外,还提供了关于节点切换、压测、加速复杂SQL查询、弹性并行查询及高可用性的详细场景体验说明,全方位展示了PolarDB的强大功能。
|
8天前
|
关系型数据库 分布式数据库 数据库
报名啦|PolarDB数据库创新设计赛(天池杯)等你来战
2024年全国大学生计算机系统能力大赛PolarDB数据库创新设计赛(天池杯)已启动报名,面向全国高校全日制本专科学生。大赛由多家机构联合主办,旨在培养数据库领域人才,促进产学研合作,设有丰厚奖金与奖项。报名截至10月7日,决赛将于12月13日举行。更多详情及报名请访问大赛官网。
|
9天前
|
关系型数据库 分布式数据库 数据库
报名啦|PolarDB数据库创新设计赛(天池杯)等你来战
2024年全国大学生计算机系统能力大赛PolarDB数据库创新设计赛(天池杯)已启动报名,面向全国高校全日制本专科学生。大赛由多家机构联合主办,旨在培养数据库领域人才,促进产学研合作,设有丰厚奖金与奖项。报名截至10月7日,决赛将于12月13日举行。更多详情及报名请访问大赛官网。
|
14天前
|
SQL 关系型数据库 分布式数据库
PolarDB Proxy配置与优化:提升数据库访问效率
【9月更文挑战第6天】PolarDB是阿里云推出的高性能分布式关系型数据库,PolarDB Proxy作为其关键组件,位于客户端与PolarDB集群间,负责SQL请求的解析与转发,并支持连接池管理、SQL过滤及路由规则等功能。本文详细介绍了PolarDB Proxy的配置方法,包括连接池、负载均衡和SQL过滤设置,并探讨了监控调优、缓存及网络优化策略,以帮助提升数据库访问效率。
24 1
|
18天前
|
Java 数据库连接 数据库
数据库以及其他项目配置
该项目配置了数据库连接和MyBatis设置,并解决了配置文件加载问题。启动类使用 `@SpringBootApplication` 注解,可通过 `@ComponentScan` 指定扫描包。Lombok 自动生成 getter/setter 等方法,简化代码。Result 实体类用于统一返回格式。用户模块包括注册与登录功能,使用 MD5 加密密码、Spring Validation 参数校验及 JWT 认证。JWT 工具类处理令牌生成与解析,并通过拦截器验证。Redis 优化登录功能,利用 ThreadLocal 存储用户信息。此外,还包括文章模块的相关功能,如文章分类管理、
35 2
|
18天前
|
自然语言处理 关系型数据库 MySQL
match如何在mysql数据库里进行文本的相似度排序?
【9月更文挑战第1天】match如何在mysql数据库里进行文本的相似度排序?
30 1

热门文章

最新文章