PostgreSQL · 特性介绍 · 全文搜索介绍
背景
在日常的數據處理中,我們經常會有這樣的需求:從一個文本中尋找某個字符串(比如某個單詞)。
對這個需求,我們可以用類似這樣的SQL完成:SELECT * FROM tbl WHERE text LIKE '%rds PostgreSQL%';(找到含有“rds PostgreSQL”的文本)
現在我們考慮一些特殊的情形:
那么此時再用以上的“SELECT ... LIKE ...”就不明智了,因為對數據庫來說,這樣的SQL必然走的是全表掃描,那么當文本特別多,特別大的時候,查找效率就會很低。
另外,這樣的SQL也不會智能到可以處理自然語言的特性。
怎么辦呢?PostgreSQL(以下簡稱PG)提供了強大的全文搜索功能可以滿足這樣的需求。
對文本的預處理
全文搜索首先需要對文本預處理,包括3步:
在PG中,以上對文本的預處理可以通過一個函數to_tsvector來完成,函數的返回值是tsvector這個數據類型。
另外,對于待查找的單詞,我們也要用to_tsquery這個函數包裝起來,函數的返回值是tsquery這個數據類型。
一個簡單的例子見下面,to_tsquery里的參數可以使用運算符(&:與,|:或,!:非):
SELECT to_tsvector('fat cats ate fat rats') @@ to_tsquery('fat & rat');?column? ----------tQuick Start
在了解了這些概念之后,我們用實際的例子來玩一玩PG的全文搜索。
我們在client端輸入以下命令,dFp顯示的是所有的parser,這里只有一個默認parser(default)。
dFp+ default 顯示默認parser(default)的詳細信息:parse的過程(5個函數),parse的Token類型(asciihword, asciiword...)。
sbtest=# \dFpList of text search parsersSchema | Name | Description ------------+---------+---------------------pg_catalog | default | default word parser (1 row)sbtest=# \dFp+ defaultText search parser "pg_catalog.default"Method | Function | Description -----------------+----------------+-------------Start parse | prsd_start | (internal)Get next token | prsd_nexttoken | (internal)End parse | prsd_end | (internal)Get headline | prsd_headline | (internal)Get token types | prsd_lextype | (internal)Token types for parser "pg_catalog.default"Token name | Description -----------------+------------------------------------------asciihword | Hyphenated word, all ASCIIasciiword | Word, all ASCIIblank | Space symbolsemail | Email addressentity | XML entityfile | File or path namefloat | Decimal notationhost | Hosthword | Hyphenated word, all lettershword_asciipart | Hyphenated word part, all ASCIIhword_numpart | Hyphenated word part, letters and digitshword_part | Hyphenated word part, all lettersint | Signed integernumhword | Hyphenated word, letters and digitsnumword | Word, letters and digitsprotocol | Protocol headsfloat | Scientific notationtag | XML taguint | Unsigned integerurl | URLurl_path | URL pathversion | Version numberword | Word, all letters (23 rows)輸入dF+ english,給出標準化各類英語token時所用到的dictionary:
sbtest=# \dF+ english Text search configuration "pg_catalog.english" Parser: "pg_catalog.default"Token | Dictionaries -----------------+--------------asciihword | english_stemasciiword | english_stememail | simplefile | simplefloat | simplehost | simplehword | english_stemhword_asciipart | english_stemhword_numpart | simplehword_part | english_stemint | simplenumhword | simplenumword | simplesfloat | simpleuint | simpleurl | simpleurl_path | simpleversion | simpleword | english_stem創建以default為parser的配置defcfg,并增加token映射,這里我們只關心email, url, host:
sbtest=# CREATE TEXT SEARCH CONFIGURATION defcfg (PARSER = default); CREATE TEXT SEARCH CONFIGURATION sbtest=# ALTER TEXT SEARCH CONFIGURATION defcfg ADD MAPPING FOR email,url,host WITH simple; ALTER TEXT SEARCH CONFIGURATION建好配置defcfg后,我們看看利用defcfg對文本進行處理的結果。這里使用to_tsvector函數,可以看到email,url,host都被識別出來了:
sbtest=# select to_tsvector('defcfg','xxx yyy xxx@taobao.com yyy@sina.com http://google.com/123 12345 ');to_tsvector -----------------------------------------------------------------------'google.com':4 'google.com/123':3 'xxx@taobao.com':1 'yyy@sina.com':2 (1 row)在實際對表內的文本做全文搜索時,一般對目標列建立gin索引(也就是倒排索引,詳情見官方文檔),這樣可以加快查詢效率,具體操作如下:
sbtest=# CREATE TABLE t1(c1 text); CREATE TABLE sbtest=# CREATE INDEX c1_idx ON t1 USING gin(to_tsvector('defcfg', c1)); CREATE INDEX sbtest=# \d t1Table "public.t1"Column | Type | Modifiers --------+------+-----------c1 | text | Indexes:"c1_idx" gin (to_tsvector('defcfg'::regconfig, c1))這里我們插入2條文本,并做一些匹配:
sbtest=# INSERT INTO t1 VALUES('xxx yyy xxx@taobao.com yyy@sina.com http://google.com 12345'); INSERT 0 1 sbtest=# INSERT INTO t1 VALUES('xxx yyy xxx@gmail.com yyy@sina.com http://google.com 12345'); INSERT 0 1 sbtest=# select * from t1;c1 -------------------------------------------------------------xxx yyy xxx@taobao.com yyy@sina.com http://google.com 12345xxx yyy xxx@gmail.com yyy@sina.com http://google.com 12345 (2 rows)sbtest=# select * from t1 where to_tsvector('defcfg',c1) @@ 'google.com';c1 -------------------------------------------------------------xxx yyy xxx@taobao.com yyy@sina.com http://google.com 12345xxx yyy xxx@gmail.com yyy@sina.com http://google.com 12345 (2 rows)sbtest=# select * from t1 where to_tsvector('defcfg',c1) @@ to_tsquery('google.com & yyy@sina.com');c1 -------------------------------------------------------------xxx yyy xxx@taobao.com yyy@sina.com http://google.com 12345xxx yyy xxx@gmail.com yyy@sina.com http://google.com 12345 (2 rows)sbtest=# select * from t1 where to_tsvector('defcfg',c1) @@ to_tsquery('google.com & xxx@gmail.com');c1 ------------------------------------------------------------xxx yyy xxx@gmail.com yyy@sina.com http://google.com 12345 (1 row)以上的操作都是針對英文,實際上對中文也是支持的,不過會稍微麻煩點,因為中文的token必須通過分詞才能產生,所以需要先裝分詞的組件scws和zhparser,具體可以參考這篇博文。
結語
本文對PG的全文搜索做了一個入門級的介紹,方便用戶快速上手,如果需要對全文搜索作更深入的研究,建議閱讀官方文檔第12章。
總結
以上是生活随笔為你收集整理的PostgreSQL · 特性介绍 · 全文搜索介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++ new/delete、mallo
- 下一篇: SQL Server数据库备份的镜像