全部產品
Search
文件中心

PolarDB:詞典

更新時間:Jul 06, 2024

詞典被用來消除不被搜尋考慮的詞(stop words)、並被用來正規化詞這樣同一個詞的不同派生形式將會匹配。一個被成功地正規化的詞被稱為一個詞位。除了提高搜尋品質,正規化和移除停用詞減小了文檔的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

本資料庫中為許多語言提供了預定義的字典。也有多種預定義模板可以被用於建立帶自訂參數的新詞典。每一種預定義詞典模板在下面描述。如果沒有合適的現有模板,可以建立新的;例子見本資料庫中發布的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 模組所做的。

停用詞

停用詞是非常常用的詞,在幾乎每一個文檔中出現並且沒有任何區分度。因此,在全文檢索搜尋的環境中它們可以被忽略。例如,每一段英語文本都包含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詞幹分析器首先檢查停用詞的列表。這種不同行為的原因是一衝降低雜訊的嘗試。

簡單詞典

simple詞典模板的操作是將輸入記號轉換為小寫形式並且根據一個停用詞檔案檢查它。如果該記號在該檔案中被找到,則返回一個空數組,導致該記號被丟棄。否則,該詞的小寫形式被返回作為正規化的詞位。作為一種選擇,該詞典可以被配置為將非停用詞報告為未識別,允許它們被傳遞給列表中的下一個詞典。

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

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

這裡,english是一個停用詞檔案的基本名稱。該檔案的全名將是$SHAREDIR/tsearch_data/english.stop,其中$SHAREDIR表示本資料庫的共用資料目錄,通常是/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命令。這可以是一次“假”更新,它並不實際修改任何參數值。

同義字詞典

這個詞典模板被用來建立用於同義字替換的詞典。不支援短語。一個同義字詞典可以被用來解決語言學問題,例如,阻止一個英語詞幹分析器詞典把詞“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表示本資料庫中安裝的共用資料目錄)。該檔案格式是每行一個要被替換的詞,後面跟著它的同義字,用空白分隔。空行和結尾的空格會被忽略。

synonym模板還有一個可選的參數CaseSensitive,其預設值為false。當CaseSensitivefalse時,同義字檔案中的詞被摺疊成小寫,這和輸入記號一樣。當它為true時,詞和記號將不會被摺疊成小寫,但是比較時就好像被摺疊過一樣。

一個星號(*)可以被放置在設定檔中一個同義字的末尾。這表示該同義字是一個首碼。當項被用在to_tsvector()中時,星號會被忽略;當它被用在to_tsquery()中時,結果將是一個帶有首碼匹配標記器的查詢項。例如,假設我們在$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)

分類詞典

一個分類詞典(有時被簡寫成 TZ)是一個詞的集合,其中包括了詞與短語之間的聯絡,即廣義詞(BT)、狹義詞(NT)、首選詞、非首選詞、相關詞等。基本上一個分類詞典會用一個首選詞替換所有非首選詞,並且也可選擇地保留原始術語用於索引。本資料庫中的分類詞典的當前實現是同義字詞典的一個擴充,並增加了短語支援。一個分類詞典要求一個下列格式的設定檔:

    # 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沒有被分配給該分類詞典。

警告

在索引期間要用到分類詞典,因此分類詞典參數中的任何變化都要求重索引。對於大多數其他索引類型,例如增加或移除停用詞等小改動都不會強制重索引。

分類詞典配置

要定義一個新的分類詞典,可使用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;

分類詞典例子

考慮一個簡單的天文學分類詞典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'

注意在thesaurus_astrosupernova star匹配supernovae stars,因為我們在分類詞典定義中指定了english_stem詞幹分析器。該詞幹分析器移除了es

要和替補一樣也索引原始短語,只要將它包含在定義的右手部分中:

    supernovae stars : sn supernovae stars

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

Ispell 詞典

Ispell詞典模板支援詞法詞典,它可以把一個詞的很多不同語言學的形式正規化成相同的詞位。例如,一個英語Ispell詞典可以匹配搜尋字詞bank的詞尾變化和屈折,例如bankingbankedbanksbanks'bank's。標準的本資料庫中發布不包括任何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目錄。

  • 用下面的命令把檔案載入:

        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

這裡的條件具有和Regex相似的格式。它可以使用分組[...][^...]。例如,[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)

  • 標誌(詞綴類的名稱)

  • 從該詞的開始(首碼)或者結尾(尾碼)剝離字元

  • 增加詞綴

  • 和Regex格式類似的條件。

.dict檔案看起來和Ispell的.dict檔案相似:

    larder/M
    lardy/RT
    large/RSPMYT
    largehearted
說明

MySpell 不支援複合詞。Hunspell則對複合詞有更好的支援。當前,本資料庫中只實現了 Hunspell 中基本的複合詞操作。

Snowball 詞典

Snowball詞典模板基於 Martin Porter 的一個專案,他是流行的英語 Porter 詞幹分析演算法的發明者。Snowball 現在對許多語言提供詞幹分析演算法(詳見 Snowball 網站)。每一個演算法懂得按照其語言中的拼字,如何縮減詞的常見變體形式為一個基礎或詞幹。一個 Snowball 詞典要求一個language參數來標識要用哪種詞幹分析器,並且可以選擇地指定一個stopword檔案名稱來給出一個要被消除的詞列表(本資料庫中的標準停用詞列表也是由 Snowball 專案提供的)。例如,有一個內建的定義等效於

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

停用詞檔案格式和已經解釋的一樣。一個Snowball詞典識別所有的東西,不管它能不能簡化該詞,因此它應當被放置在詞典列表的最後。把它放在任何其他詞典前面是沒有用處的,因為一個記號永遠不會穿過它而進入到下一個詞典。