支援的版本:目前 (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.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 在正規化後將相同。

字典是一個程式,它接受一個 token 作為輸入並傳回

  • 如果字典知道輸入 token,則傳回詞位陣列(請注意,一個 token 可以產生多個詞位)

  • 傳回帶有設定 TSL_FILTER 標誌的單個詞位,以將原始 token 替換為新 token,以便傳遞到後續字典(執行此操作的字典稱為篩選字典

  • 如果字典知道 token,但它是停用詞,則傳回空陣列

  • 如果字典無法辨識輸入 token,則傳回 NULL

PostgreSQL 提供了許多語言的預定義字典。還有幾個預定義的範本可用於建立具有自訂參數的新字典。下面描述了每個預定義的字典範本。如果沒有合適的現有範本,則可以建立新的範本;請參閱 PostgreSQL 發行版本的 contrib/ 區域以取得範例。

文字搜尋組態將剖析器與一組字典繫結在一起,以處理剖析器的輸出 token。對於剖析器可以傳回的每個 token 類型,組態會指定一個單獨的字典清單。當剖析器找到該類型的 token 時,會依次查詢清單中的每個字典,直到某些字典將其辨識為已知單字。如果它被識別為停用詞,或者如果沒有字典辨識該 token,它將被丟棄,並且不會被索引或搜尋。通常,傳回非 NULL 輸出的第一個字典決定結果,並且不會查詢任何剩餘的字典;但是篩選字典可以用修改後的詞語替換給定的詞語,然後將其傳遞到後續字典。

配置字典清單的一般規則是首先放置最窄、最特定的字典,然後放置更一般的字典,最後放置非常一般的字典,例如 Snowball 詞幹提取器或 simple,它可以識別所有內容。例如,對於天文學專用搜尋(astro_en 組態),可以將 token 類型 asciiword (ASCII word) 繫結到天文學術語的同義詞字典、一般英語字典和 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 字典會識別所有內容,無論它是否能夠簡化單字,因此應將其放置在字典列表的末尾。 在任何其他字典之前使用它是沒有用的,因為 Token 永遠不會通過它傳遞到下一個字典。

提交更正

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