【轉】PostgreSQL 文本數據分析實踐之 - 相似度分析


背景

在日常的生活中,我們可能會經常需要一些像相近、相仿、距離接近、性格接近等等類似這樣的需求,對數據進行篩選。

這些需求PostgreSQL居然都支持,是不是很變態。

變態的例子

這些場景都支持索引排序和檢索,否則怎么叫變態呢。

按長相相似度排序

比如最近的王寶強和馬蓉的事件,估計很多人會拿宋喆的照片進行相似度的搜索,八卦八卦。
說起圖像搜索,我前幾天才寫了一篇這樣的文章,是關於在PG數據庫中使用圖像搜索插件的文章。
《弱水三千,只取一瓢,當圖像搜索遇見PostgreSQL(Haar wavelet)》
https://yq.aliyun.com/articles/58246

按喜好重合度排序

比如收集了人群的各種喜好的數據,按喜好進行聚類,或者按喜好的重疊度進行排序,找出目標人群。

按年齡相近程度排序

這個相對簡單,比如輸入23歲,按接近23歲的輸出即可。
例子 https://www.postgresql.org/docs/9.5/static/btree-gist.html
輸出與100最接近的10條數據。

postgres=# create extension btree_gist;
CREATE EXTENSION
postgres=# create table test12(id int);
CREATE TABLE
postgres=# insert into test12 select trunc(random()*1000) from generate_series(1,100000);
INSERT 0 100000
postgres=# create index idx_test12 on test12 using gist(id);
CREATE INDEX
postgres=# select * from test12 order by id <-> 100 limit 10;
 id  
-----
 100
 100
 100
 100
 100
 100
 100
 100
 100
 100
(10 rows)

 

按距離排序

https://www.postgresql.org/docs/9.5/static/functions-geometry.html
例如取出與某個點最近的10個點。

postgres=# create table test13(c1 point);
CREATE TABLE
postgres=# insert into test13 select ('('||trunc(random()*1000)||','||trunc(random()*5000)||')')::point from generate_series(1,10000);
INSERT 0 10000
postgres=# create index idx_test13 on test13 using gist(c1);
CREATE INDEX
postgres=# select * from test13 order by c1 <-> point '(1,10000)' limit 10;
     c1     
------------
 (58,4993)
 (191,4995)
 (48,4991)
 (326,4998)
 (99,4988)
 (205,4991)
 (348,4998)
 (53,4986)
 (174,4988)
 (136,4984)
(10 rows)

 

按文本的相似度排序

https://www.postgresql.org/docs/9.5/static/pgtrgm.html
例如,根據文本的相似程度,排序輸出。

postgres=# create extension pg_trgm;
CREATE EXTENSION
postgres=# create table test14(c1 text);
CREATE TABLE
postgres=# insert into test14 values ('hello digoal'), ('china'), ('hello china'), ('nihao digoal');
INSERT 0 4
postgres=# select * from test14;
      c1      
--------------
 hello digoal
 china
 hello china
 nihao digoal
(4 rows)
postgres=# create index idx_test14 on test14 using gist(c1 gist_trgm_ops);
CREATE INDEX
postgres=# explain select *,c1 <-> 'digoal' from test14 order by c1 <-> 'digoal' limit 2;
                                   QUERY PLAN                                   
--------------------------------------------------------------------------------
 Limit  (cost=0.13..4.17 rows=2 width=36)
   ->  Index Scan using idx_test14 on test14  (cost=0.13..8.21 rows=4 width=36)
         Order By: (c1 <-> 'digoal'::text)
(3 rows)
postgres=# select *,c1 <-> 'digoal' from test14 order by c1 <-> 'digoal' limit 2;
      c1      | ?column? 
--------------+----------
 hello digoal | 0.461538
 nihao digoal | 0.461538
(2 rows)

 

按分詞的相似度排序

https://github.com/postgrespro/rum
這個與前面的文本相似度不同,因為它統計的是分詞的相似度,而不是文本的相似度。
支持計算相似度的類型分別為tsvector和tsquery。
例如 搜索帶有postgresql 或 digoal 或 oracle 或 postgres 關鍵詞的文章,通常來說返回順序是只要包含就返回,而不會管它的相似度高低來順序返回。
rum插件則滿足按相似度高低來返回的需求。
rum是類GIN的索引訪問接口。

export PATH=/home/digoal/pgsql9.6/bin:$PATH
git clone https://github.com/postgrespro/rum
cd rum
make USE_PGXS=1
make USE_PGXS=1 install
//
//
git clone https://github.com/jaiminpan/pg_jieba
cd pg_jieba
make USE_PGXS=1 
make USE_PGXS=1 install
//
//
postgres=# create extension rum;
CREATE EXTENSION
postgres=# create extension pg_jieba;
CREATE EXTENSION
// 分詞舉例
postgres=#  select * from to_tsvector('jiebacfg', '小明碩士畢業於中國科學院計算所,后在日本京都大學深造');
                                   to_tsvector                                    
----------------------------------------------------------------------------------
 '中國科學院':5 '小明':1 '日本京都大學':10 '畢業':3 '深造':11 '碩士':2 '計算所':6
(1 row)
// 有相似度
postgres=#  select * from rum_ts_distance(to_tsvector('jiebacfg', '小明碩士畢業於中國科學院計算所,后在日本京都大學深造') , to_tsquery('計算所'));
 rum_ts_distance 
-----------------
         16.4493
(1 row)
// 沒有相似度
postgres=#  select * from rum_ts_distance(to_tsvector('jiebacfg', '小明碩士畢業於中國科學院計算所,后在日本京都大學深造') , to_tsquery('計算'));
 rum_ts_distance 
-----------------
        Infinity
(1 row)
// 或相似度
postgres=# select * from rum_ts_distance(to_tsvector('jiebacfg', '小明碩士畢業於中國科學院計算所,后在日本京都大學深造') , to_tsquery('計算所 | 碩士'));
 rum_ts_distance 
-----------------
         8.22467
(1 row)
// 與相似度
postgres=# select * from rum_ts_distance(to_tsvector('jiebacfg', '小明碩士畢業於中國科學院計算所,后在日本京都大學深造') , to_tsquery('計算所 & 碩士'));
 rum_ts_distance 
-----------------
         32.8987
(1 row)
// 排序
postgres=# create table test15(c1 tsvector);
CREATE TABLE
postgres=# insert into test15 values (to_tsvector('jiebacfg', 'hello china, i''m digoal')), (to_tsvector('jiebacfg', 'hello world, i''m postgresql')), (to_tsvector('jiebacfg', 'how are you, i''m digoal'));
INSERT 0 3
postgres=# select * from test15;
                         c1                          
-----------------------------------------------------
 ' ':2,5,9 'china':3 'digoal':10 'hello':1 'm':8
 ' ':2,5,9 'hello':1 'm':8 'postgresql':10 'world':3
 ' ':2,4,7,11 'digoal':12 'm':10
(3 rows)
postgres=# create index idx_test15 on test15 using rum(c1 rum_tsvector_ops);
CREATE INDEX
postgres=# select *,c1 <=> to_tsquery('hello') from test15;
                         c1                          | ?column? 
-----------------------------------------------------+----------
 ' ':2,5,9 'china':3 'digoal':10 'hello':1 'm':8     |  16.4493
 ' ':2,5,9 'hello':1 'm':8 'postgresql':10 'world':3 |  16.4493
 ' ':2,4,7,11 'digoal':12 'm':10                     | Infinity
(3 rows)
postgres=# explain select *,c1 <=> to_tsquery('postgresql') from test15 order by c1 <=> to_tsquery('postgresql');
                                   QUERY PLAN                                   
--------------------------------------------------------------------------------
 Index Scan using idx_test15 on test15  (cost=3600.25..3609.06 rows=3 width=36)
   Order By: (c1 <=> to_tsquery('postgresql'::text))
(2 rows)

 

不再舉例,如果你有更好的想法,PG還不支持的話,可以自己擴展哦。

參考
《找對業務G點, 體驗酸爽 - PostgreSQL內核擴展指南》
https://yq.aliyun.com/articles/55981

如果你覺得還不夠意思,要來點基於文本集合的深度挖掘,沒關系,還有MADlib插件在等你,支持豐富的文本分析和訓練接口。

http://madlib.incubator.apache.org/docs/latest/index.html

from:https://yq.aliyun.com/articles/59212


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM