W3Cschool
恭喜您成為首批注冊(cè)用戶(hù)
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
全文搜索(或者文本搜索)提供了確定滿(mǎn)足一個(gè)查詢(xún)的自然語(yǔ)言文檔的能力,并可以選擇將它們按照與查詢(xún)的相關(guān)度排序。最常用的搜索類(lèi)型是找到所有包含給定查詢(xún)?cè)~的文檔并按照它們與查詢(xún)的相似性順序返回它們。查詢(xún)
和
相似性
的概念非常靈活并且依賴(lài)于特定的應(yīng)用。最簡(jiǎn)單的搜索認(rèn)為查詢(xún)
是一組詞而相似性
是查詢(xún)?cè)~在文檔中的頻度。
文本搜索操作符已經(jīng)在數(shù)據(jù)庫(kù)中存在很多年了。PostgreSQL對(duì)文本數(shù)據(jù)類(lèi)型提供了~
、~*
、LIKE
和ILIKE
操作符,但是它們?nèi)鄙佻F(xiàn)代信息系統(tǒng)所要求的很多基本屬性:
即使對(duì)英語(yǔ)也缺乏語(yǔ)言的支持。正則表達(dá)式是不夠的,因?yàn)樗鼈儾荒芎苋菀椎靥幚砼缮~,例如satisfies
和satisfy
。你可能會(huì)錯(cuò)過(guò)包含satisfies
的文檔,盡管你可能想要在對(duì)于satisfy
的搜索中找到它們??梢允褂?code class="literal">OR來(lái)搜索多個(gè)派生形式,但是這樣做太羅嗦也容易出錯(cuò)(有些詞可能有數(shù)千種派生)。
它們不提供對(duì)搜索結(jié)果的排序(排名),這使它們面對(duì)數(shù)以千計(jì)被找到的文檔時(shí)變得無(wú)效。
它們很慢因?yàn)闆](méi)有索引支持,因此它們必須為每次搜索處理所有的文檔。
全文索引允許文檔被預(yù)處理并且保存一個(gè)索引用于以后快速的搜索。預(yù)處理包括:
將文檔解析成記號(hào)。標(biāo)識(shí)出多種類(lèi)型的記號(hào)是有所幫助的,例如數(shù)字、詞、復(fù)雜的詞、電子郵件地址,這樣它們可以被以不同的方式處理。原則上記號(hào)分類(lèi)取決于相關(guān)的應(yīng)用,但是對(duì)于大部分目的都可以使用一套預(yù)定義的分類(lèi)。PostgreSQL使用一個(gè)解析器來(lái)執(zhí)行這個(gè)步驟。其中提供了一個(gè)標(biāo)準(zhǔn)的解析器,并且為特定的需要也可以創(chuàng)建定制的解析器。
將記號(hào)轉(zhuǎn)換成詞位。和一個(gè)記號(hào)一樣,一個(gè)詞位是一個(gè)字符串,但是它已經(jīng)被正規(guī)化,這樣同一個(gè)詞的不同形式被變成一樣。例如,正規(guī)化幾乎總是包括將大寫(xiě)字母轉(zhuǎn)換成小寫(xiě)形式,并且經(jīng)常涉及移除后綴(例如英語(yǔ)中的s
或es
)。這允許搜索找到同一個(gè)詞的變體形式,而不需要冗長(zhǎng)地輸入所有可能的變體。此外,這個(gè)步驟通常會(huì)消除
停用詞,它們是那些太普通的詞,它們對(duì)于搜索是無(wú)用的(簡(jiǎn)而言之,記號(hào)是文檔文本的原始片段,而詞位是那些被認(rèn)為對(duì)索引和搜索有用的詞)。PostgreSQL使用詞典來(lái)執(zhí)行這個(gè)步驟。已經(jīng)提供了多種標(biāo)準(zhǔn)詞典,并且為特定的需要也可以創(chuàng)建定制的詞典。
為搜索優(yōu)化存儲(chǔ)預(yù)處理好的文檔。例如,每一個(gè)文檔可以被表示為正規(guī)化的詞位的一個(gè)有序數(shù)組。與詞位一起,通常還想要存儲(chǔ)用于近似排名的位置信息,這樣一個(gè)包含查詢(xún)?cè)~更“密集”區(qū)域的文檔要比那些包含分散的查詢(xún)?cè)~的文檔有更高的排名。
詞典允許對(duì)記號(hào)如何被正規(guī)化進(jìn)行細(xì)粒度的控制。使用合適的詞典,你可以:
定義不應(yīng)該被索引的停用詞。
使用Ispell把同義詞映射到一個(gè)單一詞。
使用一個(gè)分類(lèi)詞典把短語(yǔ)映射到一個(gè)單一詞。
使用一個(gè)Ispell詞典把一個(gè)詞的不同變體映射到一種規(guī)范的形式。
使用Snowball詞干分析器規(guī)則將一個(gè)詞的不同變體映射到一種規(guī)范的形式。
我們提供了一種數(shù)據(jù)類(lèi)型tsvector
來(lái)存儲(chǔ)預(yù)處理后的文檔,還提供了一種類(lèi)型tsquery
來(lái)表示處理過(guò)的查詢(xún)(第 8.11 節(jié))。有很多函數(shù)和操作符可以用于這些數(shù)據(jù)類(lèi)型(第 9.13 節(jié)),其中最重要的是匹配操作符@@
,它在本文章中第 12.1.2 節(jié)中介紹。全文搜索可以使用索引來(lái)加速(第 12.9 節(jié))。
一個(gè)document是在一個(gè)全文搜索系統(tǒng)中進(jìn)行搜索的單元,例如,一篇雜志文章或電子郵件消息。文本搜索引擎必須能夠解析文檔并存儲(chǔ)詞位(關(guān)鍵詞)與它們的父文檔之間的關(guān)聯(lián)。隨后,這些關(guān)聯(lián)會(huì)被用來(lái)搜索包含查詢(xún)?cè)~的文檔。
對(duì)于PostgreSQL中的搜索,一個(gè)文檔通常是一個(gè)數(shù)據(jù)庫(kù)表中一行內(nèi)的一個(gè)文本形式的域,或者可能是這類(lèi)域的一個(gè)組合(連接),這些域可能存儲(chǔ)在多個(gè)表或者是動(dòng)態(tài)獲取。換句話(huà)說(shuō),一個(gè)文檔可能從用于索引的不同部分構(gòu)建,并且它可能被作為一個(gè)整體存儲(chǔ)在某個(gè)地方。例如:
SELECT title || ' ' || author || ' ' || abstract || ' ' || body AS document
FROM messages
WHERE mid = 12;
SELECT m.title || ' ' || m.author || ' ' || m.abstract || ' ' || d.body AS document
FROM messages m, docs d
WHERE m.mid = d.did AND m.mid = 12;
實(shí)際上在這些例子查詢(xún)中,coalesce
應(yīng)該被用來(lái)防止一個(gè)單一NULL
屬性導(dǎo)致整個(gè)文檔的一個(gè)NULL
結(jié)果。
另一種存儲(chǔ)文檔的可能性是作為文件系統(tǒng)中的簡(jiǎn)單文本文件。在這種情況下,數(shù)據(jù)庫(kù)可以被用來(lái)存儲(chǔ)全文索引并執(zhí)行搜索,并且某些唯一標(biāo)識(shí)符可以被用來(lái)從文件系統(tǒng)檢索文檔。但是,從數(shù)據(jù)庫(kù)的外面檢索文件要求超級(jí)用戶(hù)權(quán)限或者特殊函數(shù)支持,因此這種方法通常不如把所有數(shù)據(jù)放在PostgreSQL內(nèi)部方便。另外,把所有東西放在數(shù)據(jù)庫(kù)內(nèi)部允許方便地訪(fǎng)問(wèn)文檔元數(shù)據(jù)來(lái)協(xié)助索引和現(xiàn)實(shí)。
對(duì)于文本搜索目的,每一個(gè)文檔必須被縮減成預(yù)處理后的tsvector
格式。搜索和排名被整個(gè)在一個(gè)文檔的tsvector
表示上執(zhí)行 — 只有當(dāng)文檔被選擇來(lái)顯示給用戶(hù)時(shí)才需要檢索原始文本。我們因此經(jīng)常把tsvector
說(shuō)成是文檔,但是當(dāng)然它只是完整文檔的一種緊湊表示。
PostgreSQL中的全文搜索基于匹配操作符@@
,它在一個(gè)tsvector
(文檔)匹配一個(gè)tsquery
(查詢(xún))時(shí)返回true
。哪種數(shù)據(jù)類(lèi)型寫(xiě)在前面沒(méi)有影響:
SELECT 'a fat cat sat on a mat and ate a fat rat'::tsvector @@ 'cat & rat'::tsquery;
?column?
----------
t
SELECT 'fat & cow'::tsquery @@ 'a fat cat sat on a mat and ate a fat rat'::tsvector;
?column?
----------
f
正如以上例子所建議的,一個(gè)tsquery
并不只是一個(gè)未經(jīng)處理的文本,頂多一個(gè)tsvector
是這樣。一個(gè)tsquery
包含搜索術(shù)語(yǔ),它們必須是已經(jīng)正規(guī)化的詞位,并且可以使用 AND 、OR、NOT 以及 FOLLOWED BY 操作符結(jié)合多個(gè)術(shù)語(yǔ)(語(yǔ)法詳見(jiàn)第 8.11.2 節(jié))。有幾個(gè)函數(shù)to_tsquery
、plainto_tsquery
以及phraseto_tsquery
可用于將用戶(hù)書(shū)寫(xiě)的文本轉(zhuǎn)換為正確的tsquery
,它們會(huì)主要采用正則化出現(xiàn)在文本中的詞的方法。相似地,
to_tsvector
被用來(lái)解析和正規(guī)化一個(gè)文檔字符串。因此在實(shí)際上一個(gè)文本搜索匹配可能看起來(lái)更像:
SELECT to_tsvector('fat cats ate fat rats') @@ to_tsquery('fat & rat');
?column?
----------
t
注意如果這個(gè)匹配被寫(xiě)成下面這樣它將不會(huì)成功:
SELECT 'fat cats ate fat rats'::tsvector @@ to_tsquery('fat & rat');
?column?
----------
f
因?yàn)檫@里不會(huì)發(fā)生詞rats
的正規(guī)化。一個(gè)tsvector
的元素是詞位,它被假定為已經(jīng)正規(guī)化好,因此rats
不匹配rat
。
@@
操作符也支持text
輸出,它允許在簡(jiǎn)單情況下跳過(guò)從文本字符串到tsvector
或tsquery
的顯式轉(zhuǎn)換??捎玫淖凅w是:
tsvector @@ tsquery
tsquery @@ tsvector
text @@ tsquery
text @@ text
前兩種我們已經(jīng)見(jiàn)過(guò)。形式text
@@
tsquery
等價(jià)于to_tsvector(x) @@ y
。形式text
@@
text
等價(jià)于
to_tsvector(x) @@ plainto_tsquery(y)
。
在tsquery
中,&
(AND)操作符指定它的兩個(gè)參數(shù)都必須出現(xiàn)在文檔中才表示匹配。類(lèi)似地,|
(OR)操作符指定至少一個(gè)參數(shù)必須出現(xiàn),而!
(NOT)操作符指定它的參數(shù)不出現(xiàn)才能匹配。例如,查詢(xún)
fat & ! rat
匹配包含fat
但不包含rat
的文檔。
在<->
(FOLLOWED BY) tsquery
操作符的幫助下搜索可能的短語(yǔ),只有該操作符的參數(shù)的匹配是相鄰的并且符合給定順序時(shí),該操作符才算是匹配。例如:
SELECT to_tsvector('fatal error') @@ to_tsquery('fatal <-> error');
?column?
----------
t
SELECT to_tsvector('error is not fatal') @@ to_tsquery('fatal <-> error');
?column?
----------
f
FOLLOWED BY 操作符還有一種更一般的版本,形式是<
,其中N
>N
是一個(gè)表示匹配詞位位置之間的差。<1>
和<->
相同,而<2>
允許剛好一個(gè)其他詞位出現(xiàn)在匹配之間,以此類(lèi)推。當(dāng)有些詞是停用詞時(shí),phraseto_tsquery
函數(shù)利用這個(gè)操作符來(lái)構(gòu)造一個(gè)能夠匹配多詞短語(yǔ)的
tsquery
。例如:
SELECT phraseto_tsquery('cats ate rats');
phraseto_tsquery
-------------------------------
'cat' <-> 'ate' <-> 'rat'
SELECT phraseto_tsquery('the cats ate the rats');
phraseto_tsquery
-------------------------------
'cat' <-> 'ate' <2> 'rat'
一種有時(shí)候有用的特殊情況是,<0>
可以被用來(lái)要求兩個(gè)匹配同一個(gè)詞的模式。
圓括號(hào)可以被用來(lái)控制tsquery
操作符的嵌套。如果沒(méi)有圓括號(hào),|
的計(jì)算優(yōu)先級(jí)最低,然后從低到高依次是&
、<->
、!
。
值得注意的是,當(dāng)AND/OR/NOT操作符在一個(gè)FOLLOWED BY操作符的參數(shù)中時(shí),它們表示與不在那些參數(shù)中時(shí)不同的含義,因?yàn)樵贔OLLOWED BY中匹配的準(zhǔn)確位置是有意義的。例如,通常!x
僅匹配在任何地方都不包含x
的文檔。但如果y
不是緊接在一個(gè)x
后面,
!x <-> y
就會(huì)匹配那個(gè)y
,在文檔中其他位置出現(xiàn)的x
不會(huì)阻止匹配。另一個(gè)例子是,x & y
通常僅要求x
和y
均出現(xiàn)在文檔中的某處,但是(x & y) <-> z
要求
x
和y
在緊挨著z
之前的同一個(gè)位置匹配。因此這個(gè)查詢(xún)的行為會(huì)不同于x <-> z & y <-> z
,它將匹配一個(gè)含有兩個(gè)單獨(dú)序列x z
以及y z
的文檔(這個(gè)特定的查詢(xún)一點(diǎn)用都沒(méi)有,因?yàn)? x
和y
不可能在同一個(gè)位置匹配,但是對(duì)于前綴匹配模式之類(lèi)的更復(fù)雜的情況,這種形式的查詢(xún)就會(huì)有用武之地)。
前述的都是簡(jiǎn)單的文本搜索例子。正如前面所提到的,全文搜索功能包括做更多事情的能力:跳過(guò)索引特定詞(停用詞)、處理同義詞并使用更高級(jí)的解析,例如基于空白之外的解析。這個(gè)功能由文本搜索配置控制。PostgreSQL中有多種語(yǔ)言的預(yù)定義配置,并且你可以很容易地創(chuàng)建你自己的配置(psql的\dF
命令顯示所有可用的配置)。
在安裝期間一個(gè)合適的配置將被選擇并且default_text_search_config也被相應(yīng)地設(shè)置在postgresql.conf
中。如果你正在對(duì)整個(gè)集簇使用相同的文本搜索配置,你可以使用在postgresql.conf
中使用該值。要在集簇中使用不同的配置但是在任何一個(gè)數(shù)據(jù)庫(kù)內(nèi)部使用同一種配置,使用
ALTER DATABASE ... SET
。否則,你可以在每個(gè)會(huì)話(huà)中設(shè)置default_text_search_config
。
依賴(lài)一個(gè)配置的每一個(gè)文本搜索函數(shù)都有一個(gè)可選的regconfig
參數(shù),因此要使用的配置可以被顯式指定。只有當(dāng)這個(gè)參數(shù)被忽略時(shí),default_text_search_config
才被使用。
為了讓建立自定義文本搜索配置更容易,一個(gè)配置可以從更簡(jiǎn)單的數(shù)據(jù)庫(kù)對(duì)象來(lái)建立。PostgreSQL的文本搜索功能提供了四類(lèi)配置相關(guān)的數(shù)據(jù)庫(kù)對(duì)象:
文本搜索解析器將文檔拆分成記號(hào)并分類(lèi)每個(gè)記號(hào)(例如,作為詞或者數(shù)字)。
文本搜索詞典將記號(hào)轉(zhuǎn)變成正規(guī)化的形式并拒絕停用詞。
文本搜索模板提供位于詞典底層的函數(shù)(一個(gè)詞典簡(jiǎn)單地指定一個(gè)模板和一組用于模板的參數(shù))。
文本搜索配置選擇一個(gè)解析器和一組用于將解析器產(chǎn)生的記號(hào)正規(guī)化的詞典。
文本搜索解析器和模板是從低層 C 函數(shù)構(gòu)建而來(lái),因此它要求 C 編程能力來(lái)開(kāi)發(fā)新的解析器和模板,并且還需要超級(jí)用戶(hù)權(quán)限來(lái)把它們安裝到一個(gè)數(shù)據(jù)庫(kù)中(在PostgreSQL發(fā)布的contrib/
區(qū)域中有一些附加的解析器和模板的例子)。由于詞典和配置只是對(duì)底層解析器和模板的參數(shù)化和連接,不需要特殊的權(quán)限來(lái)創(chuàng)建一個(gè)新詞典或配置。創(chuàng)建定制詞典和配置的例子將在本章稍后的部分給出。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話(huà):173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: