支援的版本:目前 (17) / 16 / 15 / 14 / 13
開發版本:devel
不支援的版本:12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3

12.4. 其他功能 #

本節描述與文字搜尋相關的其他有用函數和運算符。

12.4.1. 操作文件 #

第 12.3.1 節說明了如何將原始文字文件轉換為 tsvector 值。PostgreSQL 還提供了函數和運算符,可用於操作已採用 tsvector 格式的文件。

tsvector || tsvector

tsvector 串聯運算符會傳回一個向量,該向量會合併作為引數提供的兩個向量的語彙基元和位置資訊。串聯期間會保留位置和權重標籤。右手向量中出現的位置會以左手向量中提及的最大位置作為偏移量,因此結果幾乎等同於對兩個原始文件字串的串聯執行 to_tsvector 的結果。(等效性不完全相同,因為從左手引數末尾移除的任何停用詞都不會影響結果,而如果使用文字串聯,它們會影響右手引數中語彙基元的位置。)

使用向量形式的串聯而不是在應用 to_tsvector 之前串聯文字的一個優點是,您可以使用不同的配置來剖析文件的不同部分。此外,由於 setweight 函數會以相同的方式標記給定向量的所有語彙基元,因此如果您想使用不同的權重標記文件的不同部分,則必須先剖析文字並執行 setweight,然後再串聯。

setweight(vector tsvector, weight "char") returns tsvector

setweight 會傳回輸入向量的副本,其中每個位置都已標記給定的 weight,即 ABCD。(D 是新向量的預設值,因此不會顯示在輸出中。)串聯向量時會保留這些標籤,允許依排名函數不同地加權文件中不同部分的單字。

請注意,權重標籤適用於位置,而不是語彙基元。如果輸入向量已移除位置,則 setweight 不會執行任何動作。

length(vector tsvector) returns integer

傳回儲存在向量中的語彙基元數量。

strip(vector tsvector) returns tsvector

傳回一個向量,該向量會列出與給定向量相同的語彙基元,但缺少任何位置或權重資訊。結果通常比未剝離的向量小得多,但也較不有用。相關性排名在剝離的向量上不如未剝離的向量效果好。此外,<->(FOLLOWED BY)tsquery 運算符永遠不會比對剝離的輸入,因為它無法判斷語彙基元出現之間的距離。

完整的 tsvector 相關函數清單可在表 9.43中找到。

12.4.2. 操作查詢 #

第 12.3.2 節說明了如何將原始文字查詢轉換為 tsquery 值。PostgreSQL 還提供了函數和運算符,可用於操作已採用 tsquery 格式的查詢。

tsquery && tsquery

傳回兩個給定查詢的 AND 組合。

tsquery || tsquery

傳回兩個給定查詢的 OR 組合。

!! tsquery

傳回給定查詢的否定 (NOT)。

tsquery <-> tsquery

傳回一個查詢,該查詢會搜尋與第一個給定查詢立即比對,後接與第二個給定查詢比對的結果,使用 <-> (FOLLOWED BY) tsquery 運算符。例如

SELECT to_tsquery('fat') <-> to_tsquery('cat | rat');
          ?column?
----------------------------
 'fat' <-> ( 'cat' | 'rat' )
tsquery_phrase(query1 tsquery, query2 tsquery [, distance integer ]) returns tsquery

傳回一個查詢,它會搜尋完全符合第一個給定查詢的結果,然後在精確 distance 個詞位距離的位置搜尋符合第二個給定查詢的結果,使用 <N> tsquery 運算子。例如

SELECT tsquery_phrase(to_tsquery('fat'), to_tsquery('cat'), 10);
  tsquery_phrase
------------------
 'fat' <10> 'cat'
numnode(query tsquery) 傳回 integer

傳回 tsquery 中節點(詞位加上運算子)的數量。此函數可用於判斷 query 是否有意義(傳回 > 0),或者僅包含停用詞(傳回 0)。範例

SELECT numnode(plainto_tsquery('the any'));
NOTICE:  query contains only stopword(s) or doesn't contain lexeme(s), ignored
 numnode
---------
       0

SELECT numnode('foo & bar'::tsquery);
 numnode
---------
       3
querytree(query tsquery) 傳回 text

傳回可用於搜尋索引的 tsquery 部分。此函數可用於偵測無法建立索引的查詢,例如僅包含停用詞或僅包含否定詞的查詢。例如

SELECT querytree(to_tsquery('defined'));
 querytree
-----------
 'defin'

SELECT querytree(to_tsquery('!defined'));
 querytree
-----------
 T

12.4.2.1. 查詢重寫 #

ts_rewrite 函數系列會在給定的 tsquery 中搜尋目標子查詢的出現次數,並將每次出現的結果替換為替代子查詢。本質上,此操作是 tsquery 的特定版本,用於子字串替換。目標和替代組合可以被認為是查詢重寫規則。此類重寫規則的集合可能是一種強大的搜尋輔助工具。例如,您可以使用同義詞(例如,new yorkbig applenycgotham)擴展搜尋範圍,或縮小搜尋範圍以引導使用者到一些熱門主題。此功能與同義詞詞典之間存在一些功能重疊(第 12.6.4 節)。但是,您可以動態修改一組重寫規則,而無需重新建立索引,而更新同義詞詞典則需要重新建立索引才能生效。

ts_rewrite (query tsquery, target tsquery, substitute tsquery) 傳回 tsquery

此形式的 ts_rewrite 僅套用單一重寫規則:target 會被 substitute 取代,只要它出現在 query 中。例如

SELECT ts_rewrite('a & b'::tsquery, 'a'::tsquery, 'c'::tsquery);
 ts_rewrite
------------
 'b' & 'c'
ts_rewrite (query tsquery, select text) 傳回 tsquery

此形式的 ts_rewrite 接受一個起始 query 和一個 SQL select 命令,該命令以文字字串的形式給出。select 必須產生兩個 tsquery 類型的欄位。對於 select 結果的每一列,第一個欄位值(目標)的出現次數將被目前 query 值中的第二個欄位值(替代)取代。例如

CREATE TABLE aliases (t tsquery PRIMARY KEY, s tsquery);
INSERT INTO aliases VALUES('a', 'c');

SELECT ts_rewrite('a & b'::tsquery, 'SELECT t,s FROM aliases');
 ts_rewrite
------------
 'b' & 'c'

請注意,當以這種方式套用多個重寫規則時,套用順序可能很重要;因此在實務中,您會希望來源查詢以某個排序鍵 ORDER BY

讓我們考慮一個真實的天文範例。我們將使用表驅動的重寫規則擴展查詢 supernovae

CREATE TABLE aliases (t tsquery primary key, s tsquery);
INSERT INTO aliases VALUES(to_tsquery('supernovae'), to_tsquery('supernovae|sn'));

SELECT ts_rewrite(to_tsquery('supernovae & crab'), 'SELECT * FROM aliases');
           ts_rewrite
---------------------------------
 'crab' & ( 'supernova' | 'sn' )

我們可以透過更新表格來變更重寫規則

UPDATE aliases
SET s = to_tsquery('supernovae|sn & !nebulae')
WHERE t = to_tsquery('supernovae');

SELECT ts_rewrite(to_tsquery('supernovae & crab'), 'SELECT * FROM aliases');
                 ts_rewrite
---------------------------------------------
 'crab' & ( 'supernova' | 'sn' & !'nebula' )

當重寫規則很多時,重寫可能會很慢,因為它會檢查每個規則以尋找可能的匹配項。為了篩選掉明顯的非候選規則,我們可以對 tsquery 類型使用包含運算子。在下面的範例中,我們僅選擇可能與原始查詢匹配的規則

SELECT ts_rewrite('a & b'::tsquery,
                  'SELECT t,s FROM aliases WHERE ''a & b''::tsquery @> t');
 ts_rewrite
------------
 'b' & 'c'

12.4.3. 自動更新的觸發程序 #

請注意

本節中描述的方法已被儲存的產生欄位的使用所取代,如第 12.2.2 節中所述。

當使用單獨的欄位儲存文件的 tsvector 表示時,需要建立一個觸發程序,以便在文件內容欄位變更時更新 tsvector 欄位。有兩個內建的觸發程序函數可用於此目的,或者您可以編寫自己的函數。

tsvector_update_trigger(tsvector_column_name,​ config_name, text_column_name [, ... ])
tsvector_update_trigger_column(tsvector_column_name,​ config_column_name, text_column_name [, ... ])

這些觸發程序函數會自動從一個或多個文字欄位計算 tsvector 欄位,並在 CREATE TRIGGER 命令中指定的參數控制下。以下是其用法的範例

CREATE TABLE messages (
    title       text,
    body        text,
    tsv         tsvector
);

CREATE TRIGGER tsvectorupdate BEFORE INSERT OR UPDATE
ON messages FOR EACH ROW EXECUTE FUNCTION
tsvector_update_trigger(tsv, 'pg_catalog.english', title, body);

INSERT INTO messages VALUES('title here', 'the body text is here');

SELECT * FROM messages;
   title    |         body          |            tsv
------------+-----------------------+----------------------------
 title here | the body text is here | 'bodi':4 'text':5 'titl':1

SELECT title, body FROM messages WHERE tsv @@ to_tsquery('title & body');
   title    |         body
------------+-----------------------
 title here | the body text is here

建立此觸發程序後,titlebody 中的任何變更都會自動反映到 tsv 中,而無需應用程式擔心。

第一個觸發程序引數必須是要更新的 tsvector 欄位的名稱。第二個引數指定要用於執行轉換的文字搜尋配置。對於 tsvector_update_trigger,配置名稱僅作為第二個觸發程序引數給出。它必須是 schema 限定的,如上所示,以便觸發程序的行為不會隨著 search_path 中的變更而變更。對於 tsvector_update_trigger_column,第二個觸發程序引數是另一個表格欄位的名稱,該欄位必須是 regconfig 類型。這允許對配置進行逐列選擇。剩餘的引數是文字欄位的名稱(類型為 textvarcharchar)。這些欄位將按給定的順序包含在文件中。將跳過 NULL 值(但其他欄位仍將被索引)。

這些內建觸發程序的限制是它們以相同的方式處理所有輸入欄位。若要以不同的方式處理欄位(例如,以不同於正文的方式對標題進行加權),則需要編寫自訂觸發程序。以下是以 PL/pgSQL 作為觸發程序語言的範例

CREATE FUNCTION messages_trigger() RETURNS trigger AS $$
begin
  new.tsv :=
     setweight(to_tsvector('pg_catalog.english', coalesce(new.title,'')), 'A') ||
     setweight(to_tsvector('pg_catalog.english', coalesce(new.body,'')), 'D');
  return new;
end
$$ LANGUAGE plpgsql;

CREATE TRIGGER tsvectorupdate BEFORE INSERT OR UPDATE
    ON messages FOR EACH ROW EXECUTE FUNCTION messages_trigger();

請記住,在觸發程序內建立 tsvector 值時,明確指定配置名稱非常重要,以便欄位的內容不會受到 default_text_search_config 變更的影響。如果未能做到這一點,很可能會導致問題,例如在傾印和還原後搜尋結果發生變更。

12.4.4. 收集文件統計資料 #

函數 ts_stat 對於檢查您的配置和尋找停用詞候選詞很有用。

ts_stat(sqlquery text, [ weights text, ]
        OUT word text, OUT ndoc integer,
        OUT nentry integer) returns setof record

sqlquery 是一個文字值,其中包含一個 SQL 查詢,該查詢必須傳回單個 tsvector 欄位。ts_stat 執行查詢,並傳回有關 tsvector 資料中包含的每個不同詞位(單字)的統計資料。傳回的欄位為

  • word text — 詞位的值

  • ndoc integer — 該單字出現的文件(tsvector)數量

  • nentry integer — 該單字的總出現次數

如果提供 weights,則僅計算具有這些權重的出現次數。

例如,若要尋找文件集合中最常出現的十個單字

SELECT * FROM ts_stat('SELECT vector FROM apod')
ORDER BY nentry DESC, ndoc DESC, word
LIMIT 10;

同樣,但僅計算權重為 AB 的單字出現次數

SELECT * FROM ts_stat('SELECT vector FROM apod', 'ab')
ORDER BY nentry DESC, ndoc DESC, word
LIMIT 10;

提交更正

如果您在文件中看到任何不正確、與您使用特定功能的體驗不符或需要進一步澄清的內容,請使用此表單回報文件問題。