PostgreSQL 被稱爲是「最高級的開源數據庫」,它的數據類型很是豐富,用它來解決一些比較偏門的需求很是適合。html
前些天將 POI 點關鍵詞查詢的功能遷到了 PgSQL,總算對前文 空間索引 - 各數據庫空間索引使用報告 有了一個交代。git
因爲 PgSQL 國內的資料較少,遷移過程踩了很多坑,這裏總結記錄一下,幫助後來的同窗能順利使用 PgSQL。並且目前在灰度測試剛布了一臺機器,後續可能還要添加機器,整理一下流程老是好的。github
文章常常被人爬,並且還不註明原地址,我在這裏的更新和糾錯無法同步,這裏註明一下原文地址:http://www.cnblogs.com/zhenbianshu/p/7795247.html算法
首先是安裝 PgSQL,這裏我使用的是 PgSQL 9.6,PgSQL 10 也剛發佈了,有興趣的能夠嘗下鮮。sql
PgSQL 的安裝能夠說很是複雜了,除了要安裝 Server 和 Client 外,還須要安裝 devel 包。爲了實現空間索引功能,咱們還要安裝最重要的 PostGIS 插件,此插件須要不少依賴,本身手動安裝很是複雜並且極可能出錯。docker
推薦自動化方式安裝,Yum 必定要配合 epel 這樣的 Yum 源,保障能將依賴一網打盡。固然最好的仍是使用 docker 來運行,找個鏡像就好了。數據庫
因爲 PgSQL 的不少功能都由插件實現,因此還要安裝一些經常使用的插件,如:服務器
postgis_topology(管理面、邊、點等拓撲對象) pgrouting(路徑規劃) postgis_sfcgal(實現3D相關算法) fuzzystrmatch(字符串類似度計算) address_standardizer/address_standardizer_data_us(地址標準化) pg_trgm(分詞索引)
這些插件在安裝目錄 /path/extensions
下編譯完畢後,在數據庫中使用前要先使用 create extension xxx
啓用。session
postgres
的超級用戶,咱們可使用這個超級用戶來操做 PgSQL,後期建議從新建立一個普通用戶用來管理數據);/installPath/bin/
目錄下,PgSQL 在此目錄下提供了不少命令,如 createdb、createuser、dropdb、pg_dump
等;createdb
命令初始化一個文件夾 dir_db
(此目錄不能已存在)存放數據庫物理數據,使用 -E UTF8
參數指定數據庫字符集爲 utf-8;pg_ctl -D dir_db
指定數據庫啓動後臺服務;psql -d db
在命令行登錄 PgSQL;安裝完畢後還要配置一些比較基本的參數才能正常使用。工具
PgSQL須要在 pg_hba.conf
文件中配置數據庫 Host 權限,才能被其餘機器訪問。
# TYPE DATABASE USER ADDRESS METHOD local all all trust host all all 127.0.0.1/32 md5 host all all 172.16.0.1/16 md5
文件中註釋部分對這幾個字段介紹得比較詳細, 咱們極可能須要添加 host(IP)
訪問項, ADDRESS 是普通的網段表示法,METHOD 推薦使用 md5
,表示使用 md5 加密傳輸密碼。
服務器配置在 postgresql.conf
中,修改配置後須要 使用 pg_ctl restart -D dir_db
命令重啓數據庫;
此外,咱們也能夠在登錄數據庫後修改配置項:使用 SELECT * FROM pg_settings WHERE name = 'config';
查詢當前配置項,再使用 UPDATE 語句更新配置。但有些配置如內存分配策略是隻在當前 session 生效的,全局生效須要在配置文件中修改,再重啓服務器。
咱們能夠修改配置並用客戶端驗證 SQL 語句的優化,使用 \timing on
開啓查詢計時,使用 EXPLAIN ANALYSE
語句 分析查詢語句效率。 下面介紹兩個已實踐過的配置參數:
buffer 部分 read
數值過大,則表示工做內存不足,須要調整加此參數。但此值也不能太大,須要保證 work_mem * max_connections + shared_buffers + 系統內存 < RAM
,否則一樣可能會致使系統 內存swap。這樣,PgSQL 就能做爲一個正常的關係型數據使用了。
全文索引的實現要靠 PgSQL 的 gin 索引。分詞功能 PgSQL 內置了英文、西班牙文等,但中文分詞須要藉助開源插件 zhparser
;
要使用 zhparser,咱們首先要安裝 SCWS 分詞庫,SCWS 是 Simple Chinese Word Segmentation 的首字母縮寫(即:簡易中文分詞系統),其 GitHub 項目地址爲 hightman-scws,咱們下載以後能夠直接安裝。
安裝完後,就能夠在命令行中使用 scws
命令進行測試分詞了, 其參數主要有:
1|2|4|8
依次表示 短詞|二元|主要字|所有字
,默認不復合分詞,這個參數能夠幫助調整到最想要的分詞效果。git clone https:github.com/amutu/zhparser.git
;export PATH=$PATH:/path/to/pgsql
;make && make install
編譯 zhparser;CREATE EXTENSION zhparser;
啓用插件;添加分詞配置
CREATE TEXT SEARCH CONFIGURATION parser_name (PARSER = zhparser); // 添加配置 ALTER TEXT SEARCH CONFIGURATION parser_name ADD MAPPING FOR n,v,a,i,e,l,j WITH simple; // 設置分詞規則 (n 名詞 v 動詞等,詳情閱讀下面的文檔)
給某一列的分詞結果添加 gin 索引 create index idx_name on table using gin(to_tsvector('parser_name', field));
在命令行中使用上一節中介紹的 scws 命令測試分詞配置,如我認爲複合等級爲 7
時分詞結果最好,則我在 postgresql.conf
添加配置
zhparser.multi_short = true #短詞複合: 1 zhparser.multi_duality = true #散字二元複合: 2 zhparser.multi_zmain = true #重要單字複合: 4 zhparser.multi_zall = false #所有單字複合: 8
查詢中咱們可使用最簡單的 SELECT * FROM table WHERE to_tsvector('parser_name', field) @@ 'word'
來查詢 field 字段分詞中帶有 word 一詞的數據;
使用 to_tsquery()
方法將句子解析成各個詞的組合向量,如 國家大劇院
的返回結果爲 '國家' & '大劇院' & '大劇' & '劇院'
,固然咱們也可使用 & |
符號拼接本身須要的向量;在查詢 長句 時,可使用 SELECT * FROM table WHERE to_tsvector('parser_name', field) @@ to_tsquery('parser_name','words')
;
有時候咱們想像 MySQL 的 SQL_CALC_FOUND_ROWS
語句同樣同步返回結果條數,則可使用 SELECT COUNT(*) OVER() AS score FROM table WHERE ...
,PgSQL 會在每一行數據添加 score 字段存儲查詢到的總結果條數;
到這裏,普通的全文檢索需求已經實現了。
咱們接着對分詞效果和效率進行優化:
咱們可使用一個字段來存儲分詞向量,並在此字段上建立索引來更優地使用分詞索引:
ALTER TABLE table ADD COLUMN tsv_column tsvector; // 添加一個分詞字段 UPDATE table SET tsv_column = to_tsvector('parser_name', coalesce(field,'')); // 將字段的分詞向量更新到新字段中 CREATE INDEX idx_gin_zhcn ON table USING GIN(tsv_column); // 在新字段上建立索引 CREATE TRIGGER trigger_name BEFORE INSERT OR UPDATE ON table FOR EACH ROW EXECUTE PROCEDURE tsvector_update_trigger(tsv_column, 'parser_name', field); // 建立一個更新分詞觸發器
這樣,再進行查詢時就能夠直接使用 SELECT * FROM table WHERE tsv_column @@ 'keyword'
了。
這裏須要注意,這時候在往表內插入數據的時候,可能會報錯,提示指定 parser_name 的 schema, 這時候可使用 \dF
命令查看全部 text search configuration 的參數:
List of text search configurations Schema | Name | Description ------------+------------+--------------------------------------- pg_catalog | english | configuration for english language public | myparser |
注意 schema 參數,在建立 trigger 時須要指定 schema, 如上面,就須要使用 public.myparser
。
咱們能夠在網上下載 xdb 格式的詞庫來替代默認詞典,詞庫放在 share/tsearch_data/
文件夾下才能被 PgSQL 讀取到,默認使用的詞庫是 dict.utf8.xdb
。要使用自定義詞庫,能夠將詞庫放在詞庫文件夾後,在 postgresql.conf
配置 zhparser.extra_dict="mydict.xdb"
參數;
當咱們只有 txt 的詞庫,想把這個詞庫做爲默認詞庫該怎麼辦呢?使用 scws 帶的scwe-gen-dict
工具或網上找的腳本生成 xdb 後放入詞庫文件夾後,在 PgSQL 中分詞一直報錯,讀取詞庫文件失敗。我通過屢次實驗,總結出了一套製做一個詞典文件的方法:
詞 TF IDF 詞性
,詞是必須的,而 TF 詞頻(Term Frequency)、IDF 反文檔頻率(Inverse Document Frequency) 和 詞性
都是可選的,除非肯定本身的詞典資料是對的且符合 scws 的配置,否則最好仍是留空,讓 scws 自已肯定;postgresql.conf
中設置 zhparser.extra_dicts = "mydict.txt"
同時設置 zhparser.dict_in_memory = true
;select to_tsquery('parser', '隨便一個詞')
,分詞會極慢,請耐心(請保證此時只有一個分詞語句在執行);scws-xxxx.xdb
替換掉 share/tsearch_data/dict.utf8.xdb
;extra_dicts dict_in_memory
配置,重啓服務器。因爲查詢的是 POI 的名稱,通常較短,且不少詞並沒有語義,又考慮到用戶的輸入習慣,通常會輸入 POI 名稱的前幾個字符,並且 scws 的分詞準確率也不能達到100%,因而我添加了名稱的前綴查詢來提升查詢的準確率,即便用 B樹索引 實現 LIKE '關鍵詞%'
的查詢。這裏需
這裏要注意的是,建立索引時要根據字段類型配置 操做符類
,否則索引可能會不生效,如在 字段類型爲 varchar 的字段上建立索引須要使用語句CREATE INDEX idx_name ON table(COLUMN varchar_pattern_ops)
,這裏的 varcharpatternops 就是操做符類,操做符類的介紹和選擇能夠查看文檔:11.9. 操做符類和操做符族。
自此,一個良好的全文檢索系統就完成了。
set zhparser.punctuation_ignore = t; --忽略標點符號
簡單的數據遷移並非終點,後續要作的還有不少,如整個系統的數據同步、查詢效率優化、查詢功能優化(添加拼音搜索、模糊搜索)等。特別是查詢效率,不知道是否是我配置有問題,徹底達不到那種 E級毫秒 的速度,1kw 的數據效率在進行大結果返回時就大幅降低(200ms),只好老老實實地提早進行了分表,目前百萬級查詢速度在 20ms 之內,優化還有一段路要走。
不過此次卻是對 技術的「生態」有了個更深的體會,這方面 PgSQL 確實和 MySQL 差遠了,使用 MySQL 時再奇葩的問題都能在網上快速找到答案,而 PgSQL 就尷尬了,入門級的問題搜索 stackoverflow 來來回回就那麼幾個對不上的回答。雖然也有阿里的「德哥」同樣的大神在辛苦佈道,但用戶的數量纔是根本。不過,隨着 PgSQL 愈來愈完善,使用它的人必定會愈來愈多的,我這篇文章也算是爲 PgSQL 加溫了吧,哈哈~但願能幫到後來的使用者。
關於本文有什麼問題能夠在下面留言交流,若是您以爲本文對您有幫助,能夠點擊下面的 推薦
支持一下我,博客一直在更新,歡迎 關注
。