2025年9月25日: PostgreSQL 18 釋出!
支援的版本: 當前 (18) / 17 / 16 / 15 / 14 / 13
開發版本: 開發版
不支援的版本: 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3

12.6. 詞典 #

詞典用於消除不應在搜尋中考慮的詞(停用詞),並規範化詞,以便同一詞的不同派生形式能夠匹配。成功規範化後的詞稱為詞元。除了提高搜尋質量,規範化和刪除停用詞還可以減小文件的tsvector表示的大小,從而提高效能。規範化並不總是具有語言學意義,通常取決於應用程式語義。

一些規範化的例子

  • 語言學 — Ispell 詞典嘗試將輸入詞還原為規範形式;詞幹提取器詞典刪除詞尾

  • URL可以將位置規範化,以使等效的 URL 匹配

    • http://www.pgsql.ru/db/mw/index.html

    • http://www.pgsql.ru/db/mw/

    • http://www.pgsql.ru/db/../db/mw/index.html

  • 顏色名稱可以被其十六進位制值替換,例如,red, green, blue, magenta -> FF0000, 00FF00, 0000FF, FF00FF

  • 如果索引數字,我們可以刪除一些小數位數以減小可能數字的範圍,例如,如果小數點後只保留兩位數字,3.14159265359、3.1415926、3.14在規範化後將相同。

詞典是一個程式,它接受一個令牌作為輸入並返回

  • 如果詞典知道輸入令牌,則返回一個詞元陣列(請注意,一個令牌可以產生多個詞元)

  • 一個帶有TSL_FILTER標誌的單個詞元,用於將原始令牌替換為要傳遞給後續詞典的新令牌(執行此操作的詞典稱為過濾詞典

  • 如果詞典知道該令牌但它是停用詞,則返回一個空陣列

  • NULL如果詞典不識別輸入令牌

PostgreSQL 為許多語言提供了預定義詞典。還有一些預定義的模板可用於建立具有自定義引數的新詞典。下面將介紹每個預定義詞典模板。如果現有的模板都不合適,可以建立新的;有關示例,請參閱PostgreSQL發行版的contrib/目錄。

文字搜尋配置將一個解析器與一組詞典繫結,以處理解析器的輸出令牌。對於解析器可以返回的每種令牌型別,配置會指定一個單獨的詞典列表。當解析器找到該型別的令牌時,將依次諮詢列表中的每個詞典,直到某個詞典將其識別為已知詞。如果將其識別為停用詞,或者沒有詞典識別該令牌,則將其丟棄,既不索引也不搜尋。通常,第一個返回非NULL輸出的詞典決定結果,並且不會諮詢剩餘的詞典;但過濾詞典可以將給定的詞替換為修改後的詞,然後將其傳遞給後續詞典。

配置詞典列表的一般規則是,首先放置最狹窄、最具體的詞典,然後是更通用的詞典,最後是一個非常通用的詞典,如Snowball詞幹提取器或simple,它識別所有內容。例如,對於天文學特定的搜尋(astro_en配置),可以將asciiword(ASCII單詞)令牌型別繫結到天文學術語的同義詞典、一個通用的英語詞典和一個Snowball英語詞幹提取器。

ALTER TEXT SEARCH CONFIGURATION astro_en
    ADD MAPPING FOR asciiword WITH astrosyn, english_ispell, english_stem;

過濾詞典可以放在列表中的任何位置,除了末尾,否則將無用。過濾詞典對於部分規範化詞以簡化後續詞典的任務很有用。例如,可以使用過濾詞典刪除帶重音的字母的重音符號,就像unaccent模組所做的那樣。

12.6.1. 停用詞 #

停用詞是非常常見、幾乎出現在每個文件中且沒有區分價值的詞。因此,它們可以在全文搜尋的上下文中被忽略。例如,所有英文文字都包含athe這樣的詞,因此將它們儲存在索引中是無用的。然而,停用詞確實會影響tsvector中的位置,進而影響排名。

SELECT to_tsvector('english', 'in the list of stop words');
        to_tsvector
----------------------------
 'list':3 'stop':5 'word':6

缺失的位置 1,2,4 是因為停用詞。帶停用詞和不帶停用詞的文件的排名差異很大。

SELECT ts_rank_cd (to_tsvector('english', 'in the list of stop words'), to_tsquery('list & stop'));
 ts_rank_cd
------------
       0.05

SELECT ts_rank_cd (to_tsvector('english', 'list stop words'), to_tsquery('list & stop'));
 ts_rank_cd
------------
        0.1

停用詞的處理方式取決於特定詞典。例如,ispell詞典先規範化詞,然後檢視停用詞列表,而Snowball詞幹提取器先檢查停用詞列表。行為不同的原因是為了嘗試降低噪聲。

12.6.2. 簡單詞典 #

simple詞典模板透過將輸入令牌轉換為小寫並與停用詞檔案進行檢查來工作。如果找到該詞,則返回一個空陣列,導致令牌被丟棄。如果沒有找到,則將小寫形式的單詞作為規範化後的詞元返回。或者,該詞典可以配置為將非停用詞報告為未識別,從而允許將它們傳遞到列表中的下一個詞典。

下面是一個使用simple模板的詞典定義的示例

CREATE TEXT SEARCH DICTIONARY public.simple_dict (
    TEMPLATE = pg_catalog.simple,
    STOPWORDS = english
);

在這裡,english是停用詞檔案的基本名稱。檔案的完整名稱將是$SHAREDIR/tsearch_data/english.stop,其中$SHAREDIR表示PostgreSQL安裝的共享資料目錄,通常是/usr/local/share/postgresql(如果不確定,請使用pg_config --sharedir確定)。檔案格式只是每行一個詞。忽略空行和尾隨空格,並將大寫轉換為小寫,但不對檔案內容進行其他處理。

現在我們可以測試我們的詞典了

SELECT ts_lexize('public.simple_dict', 'YeS');
 ts_lexize
-----------
 {yes}

SELECT ts_lexize('public.simple_dict', 'The');
 ts_lexize
-----------
 {}

我們還可以選擇在停用詞檔案中未找到單詞時返回NULL,而不是小寫單詞。透過將詞典的Accept引數設定為false來選擇此行為。繼續上面的示例

ALTER TEXT SEARCH DICTIONARY public.simple_dict ( Accept = false );

SELECT ts_lexize('public.simple_dict', 'YeS');
 ts_lexize
-----------


SELECT ts_lexize('public.simple_dict', 'The');
 ts_lexize
-----------
 {}

使用預設設定Accept = true,將simple詞典放在詞典列表的末尾才有意義,因為它永遠不會將任何令牌傳遞給後續的詞典。相反,Accept = false只有在至少有一個後續詞典時才有意義。

注意

大多數型別的詞典都依賴於配置檔案,例如停用詞檔案。這些檔案必須以UTF-8編碼儲存。當它們被讀取到伺服器時,如果資料庫編碼不同,它們將被轉換為實際的資料庫編碼。

注意

通常,資料庫會話只在會話中首次使用字典配置檔案時讀取一次。如果要修改配置檔案並希望現有會話讀取新內容,請在字典上發出ALTER TEXT SEARCH DICTIONARY命令。這可以是一個不實際更改任何引數值的虛擬更新。

12.6.3. 同義詞典 #

此詞典模板用於建立將單詞替換為其同義詞的詞典。不支援短語(請參閱主題詞典模板(第 12.6.4 節))。同義詞典可用於克服語言問題,例如,防止英語詞幹提取器將單詞Paris縮減為pari。只需在同義詞典中有一行Paris paris,並將其放在english_stem詞典之前即可。例如

SELECT * FROM ts_debug('english', 'Paris');
   alias   |   description   | token |  dictionaries  |  dictionary  | lexemes
-----------+-----------------+-------+----------------+--------------+---------
 asciiword | Word, all ASCII | Paris | {english_stem} | english_stem | {pari}

CREATE TEXT SEARCH DICTIONARY my_synonym (
    TEMPLATE = synonym,
    SYNONYMS = my_synonyms
);

ALTER TEXT SEARCH CONFIGURATION english
    ALTER MAPPING FOR asciiword
    WITH my_synonym, english_stem;

SELECT * FROM ts_debug('english', 'Paris');
   alias   |   description   | token |       dictionaries        | dictionary | lexemes
-----------+-----------------+-------+---------------------------+------------+---------
 asciiword | Word, all ASCII | Paris | {my_synonym,english_stem} | my_synonym | {paris}

synonym模板唯一必需的引數是SYNONYMS,它是其配置檔案(在本例中為my_synonyms)的基本名稱。檔案的完整名稱將是$SHAREDIR/tsearch_data/my_synonyms.syn(其中$SHAREDIR表示PostgreSQL安裝的共享資料目錄)。檔案格式是每行一個要替換的單詞,後跟其同義詞,由空格分隔。忽略空行和尾隨空格。

synonym模板還有一個可選引數CaseSensitive,預設為false。當CaseSensitivefalse時,同義詞檔案中的單詞以及輸入令牌都會轉換為小寫。當它為true時,單詞和令牌不會轉換為小寫,而是按原樣進行比較。

星號(*)可以放在配置檔案中同義詞的末尾。這表示同義詞是字首。當條目在to_tsvector()中使用時,星號將被忽略,但在to_tsquery()中使用時,結果將是一個帶有字首匹配標記的查詢項(參見第 12.3.2 節)。例如,假設我們在$SHAREDIR/tsearch_data/synonym_sample.syn中有以下條目

postgres        pgsql
postgresql      pgsql
postgre pgsql
gogle   googl
indices index*

然後我們將得到以下結果

mydb=# CREATE TEXT SEARCH DICTIONARY syn (template=synonym, synonyms='synonym_sample');
mydb=# SELECT ts_lexize('syn', 'indices');
 ts_lexize
-----------
 {index}
(1 row)

mydb=# CREATE TEXT SEARCH CONFIGURATION tst (copy=simple);
mydb=# ALTER TEXT SEARCH CONFIGURATION tst ALTER MAPPING FOR asciiword WITH syn;
mydb=# SELECT to_tsvector('tst', 'indices');
 to_tsvector
-------------
 'index':1
(1 row)

mydb=# SELECT to_tsquery('tst', 'indices');
 to_tsquery
------------
 'index':*
(1 row)

mydb=# SELECT 'indexes are very useful'::tsvector;
            tsvector
---------------------------------
 'are' 'indexes' 'useful' 'very'
(1 row)

mydb=# SELECT 'indexes are very useful'::tsvector @@ to_tsquery('tst', 'indices');
 ?column?
----------
 t
(1 row)

12.6.4. 主題詞典 #

主題詞典(有時縮寫為TZ)是一組詞,其中包含詞語和短語之間關係的語料,即上位詞(BT)、下位詞(NT)、首選詞、非首選詞、相關詞等。

基本上,主題詞典用一個首選詞替換所有非首選詞,並可選擇地保留原始詞以供索引。PostgreSQL當前的主題詞典實現是同義詞典的擴充套件,增加了短語支援。主題詞典需要以下格式的配置檔案

# this is a comment
sample word(s) : indexed word(s)
more sample word(s) : more indexed word(s)
...

其中冒號(:)符號用作短語與其替換之間的分隔符。

主題詞典使用一個子詞典(在詞典的配置中指定)來規範化輸入文字,然後再檢查短語匹配。只能選擇一個子詞典。如果子詞典未能識別某個詞,則會報告錯誤。在這種情況下,您應該刪除該詞的使用或教子詞典瞭解它。您可以在索引詞的開頭放置一個星號(*)來跳過對該詞應用子詞典,但所有示例詞必須被子詞典識別。

如果存在多個短語匹配輸入,主題詞典將選擇最長的匹配項,並使用最後一個定義來打破平局。

子詞典識別的具體停用詞無法指定;而是使用?來標記任何停用詞可能出現的位置。例如,假設根據子詞典athe是停用詞

? one ? two : swsw

匹配a one the twothe one a two;兩者都將被替換為swsw

由於主題詞典具有識別短語的能力,因此它必須記住其狀態並與解析器進行互動。主題詞典使用這些賦值來檢查它是否應處理下一個詞或停止累積。主題詞典必須仔細配置。例如,如果主題詞典僅分配給處理asciiword令牌,那麼像one 7這樣的主題詞典定義將不起作用,因為令牌型別uint未分配給主題詞典。

注意

主題詞典在索引期間使用,因此主題詞典引數的任何更改都需要重新索引。對於大多數其他詞典型別,小的更改(例如新增或刪除停用詞)不會強制重新索引。

12.6.4.1. 主題詞典配置 #

要定義一個新的主題詞典,請使用thesaurus模板。例如

CREATE TEXT SEARCH DICTIONARY thesaurus_simple (
    TEMPLATE = thesaurus,
    DictFile = mythesaurus,
    Dictionary = pg_catalog.english_stem
);

這裡

  • thesaurus_simple是新詞典的名稱

  • mythesaurus是主題詞典配置檔案的基本名稱。(它的完整名稱將是$SHAREDIR/tsearch_data/mythesaurus.ths,其中$SHAREDIR表示安裝共享資料目錄。)

  • pg_catalog.english_stem是用於主題詞典規範化的子詞典(此處為Snowball英語詞幹提取器)。請注意,子詞典將有自己的配置(例如,停用詞),此處未顯示。

現在可以將主題詞典thesaurus_simple繫結到配置中的所需令牌型別,例如

ALTER TEXT SEARCH CONFIGURATION russian
    ALTER MAPPING FOR asciiword, asciihword, hword_asciipart
    WITH thesaurus_simple;

12.6.4.2. 主題詞典示例 #

考慮一個簡單的天文主題詞典thesaurus_astro,它包含一些天文詞組合

supernovae stars : sn
crab nebulae : crab

下面我們建立一個詞典,並將一些令牌型別繫結到一個天文主題詞典和一個英語詞幹提取器

CREATE TEXT SEARCH DICTIONARY thesaurus_astro (
    TEMPLATE = thesaurus,
    DictFile = thesaurus_astro,
    Dictionary = english_stem
);

ALTER TEXT SEARCH CONFIGURATION russian
    ALTER MAPPING FOR asciiword, asciihword, hword_asciipart
    WITH thesaurus_astro, english_stem;

現在我們可以看看它是如何工作的。ts_lexize對於測試主題詞典不太有用,因為它將輸入視為單個令牌。相反,我們可以使用plainto_tsqueryto_tsvector,它們會將輸入字串分解為多個令牌

SELECT plainto_tsquery('supernova star');
 plainto_tsquery
-----------------
 'sn'

SELECT to_tsvector('supernova star');
 to_tsvector
-------------
 'sn':1

原則上,如果引用引數,可以使用to_tsquery

SELECT to_tsquery('''supernova star''');
 to_tsquery
------------
 'sn'

請注意,supernova starthesaurus_astro中匹配supernovae stars,因為我們在主題詞典定義中指定了english_stem詞幹提取器。詞幹提取器刪除了es

要索引原始短語以及替換短語,只需將其包含在定義的右側即可

supernovae stars : sn supernovae stars

SELECT plainto_tsquery('supernova star');
       plainto_tsquery
-----------------------------
 'sn' & 'supernova' & 'star'

12.6.5. Ispell 詞典 #

Ispell詞典模板支援形態學詞典,它可以將單詞的許多不同語言形式規範化為相同的詞元。例如,英語Ispell詞典可以匹配搜尋詞bank的所有屈折和變位,例如bankingbankedbanksbanks'bank's

標準的PostgreSQL發行版不包含任何Ispell配置檔案。大量語言的詞典可從Ispell獲取。此外,還支援一些更現代的詞典檔案格式 — MySpell(OO < 2.0.1)和Hunspell(OO >= 2.0.2)。可以在OpenOffice Wiki上找到大量詞典。

要建立Ispell詞典,請執行以下步驟

  • 下載詞典配置檔案。OpenOffice擴充套件檔案具有.oxt副檔名。有必要提取.aff.dic檔案,並將副檔名更改為.affix.dict。對於某些詞典檔案,還需要使用命令將字元轉換為UTF-8編碼(例如,對於挪威語詞典)

    iconv -f ISO_8859-1 -t UTF-8 -o nn_no.affix nn_NO.aff
    iconv -f ISO_8859-1 -t UTF-8 -o nn_no.dict nn_NO.dic
    
  • 將檔案複製到$SHAREDIR/tsearch_data目錄

  • 使用以下命令將檔案載入到PostgreSQL中

    CREATE TEXT SEARCH DICTIONARY english_hunspell (
        TEMPLATE = ispell,
        DictFile = en_us,
        AffFile = en_us,
        Stopwords = english);
    

在這裡,DictFileAffFileStopWords指定了詞典、詞綴和停用詞檔案的基本名稱。停用詞檔案的格式與上面為simple詞典型別解釋的格式相同。其他檔案的格式在此未指定,但可從上述網站獲得。

Ispell詞典通常識別有限數量的詞,因此應該在它們之後使用另一個更廣泛的詞典;例如,一個Snowball詞典,它識別所有內容。

Ispell.affix檔案具有以下結構

prefixes
flag *A:
    .           >   RE      # As in enter > reenter
suffixes
flag T:
    E           >   ST      # As in late > latest
    [^AEIOU]Y   >   -Y,IEST # As in dirty > dirtiest
    [AEIOU]Y    >   EST     # As in gray > grayest
    [^EY]       >   EST     # As in small > smallest

.dict檔案具有以下結構

lapse/ADGRS
lard/DGRS
large/PRTY
lark/MRS

.dict檔案的格式是

basic_form/affix_class_name

.affix檔案中,每個詞綴標誌都用以下格式描述

condition > [-stripping_letters,] adding_affix

這裡,條件具有類似於正則表示式的格式。它可以包含分組[...][^...]。例如,[AEIOU]Y表示單詞的最後一個字母是"y",倒數第二個字母是"a""e""i""o""u"[^EY]表示最後一個字母既不是"e"也不是"y"

Ispell詞典支援拆分複合詞,這是一項有用的功能。請注意,詞綴檔案應指定一個特殊標誌,使用compoundwords controlled語句來標記可以參與複合構詞的詞典詞。

compoundwords  controlled z

以下是一些挪威語的例子

SELECT ts_lexize('norwegian_ispell', 'overbuljongterningpakkmesterassistent');
   {over,buljong,terning,pakk,mester,assistent}
SELECT ts_lexize('norwegian_ispell', 'sjokoladefabrikk');
   {sjokoladefabrikk,sjokolade,fabrikk}

MySpell格式是Hunspell的一個子集。Hunspell.affix檔案具有以下結構

PFX A Y 1
PFX A   0     re         .
SFX T N 4
SFX T   0     st         e
SFX T   y     iest       [^aeiou]y
SFX T   0     est        [aeiou]y
SFX T   0     est        [^ey]

詞綴類的第一行是標題。詞綴規則的欄位列在標題之後

  • 引數名稱(PFX 或 SFX)

  • 標誌(詞綴類的名稱)

  • 從單詞的開頭(字首)或結尾(字尾)剝離字元

  • 新增詞綴

  • 條件,其格式類似於正則表示式。

.dict檔案看起來像Ispell.dict檔案

larder/M
lardy/RT
large/RSPMYT
largehearted

注意

MySpell不支援複合詞。Hunspell對複合詞有複雜支援。目前,PostgreSQL僅實現了Hunspell的基本複合詞操作。

12.6.6. Snowball 詞典 #

Snowball詞典模板基於Martin Porter的專案,他是英語流行詞幹提取演算法Porter的發明者。Snowball現在為許多語言提供詞幹提取演算法(有關更多資訊,請參見Snowball網站)。每種演算法都能夠將單詞的常見變體形式減少到其語言中的基本或詞幹拼寫。Snowball詞典需要一個language引數來標識要使用的詞幹提取器,並且可以選擇指定一個stopword檔名,其中包含要消除的單詞列表。(PostgreSQL的標準停用詞列表也由Snowball專案提供。)例如,有一個內建定義等同於

CREATE TEXT SEARCH DICTIONARY english_stem (
    TEMPLATE = snowball,
    Language = english,
    StopWords = english
);

停用詞檔案的格式與前面解釋的相同。

Snowball詞典識別所有內容,無論它是否能夠簡化單詞,因此它應該放在詞典列表的末尾。在它之前放置任何其他詞典都是沒有意義的,因為令牌永遠不會傳遞到下一個詞典。

提交更正

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