PostgreSQL 詞典

2021-08-27 14:56 更新
12.6.1. 停用詞
12.6.2. 簡單詞典
12.6.3. 同義詞詞典
12.6.4. 分類詞典
12.6.5. Ispell 詞典
12.6.6. Snowball 詞典

詞典被用來消除不被搜索考慮的詞(stop words)、并被用來正規(guī)化詞這樣同一個詞的不同派生形式將會匹配。一個被成功地正規(guī)化的詞被稱為一個詞位。除了提高搜索質(zhì)量,正規(guī)化和移除停用詞減小了文檔的tsvector表示的尺寸,因而提高了性能。正規(guī)化不會總是有語言上的意義并且通常依賴于應(yīng)用的語義。

一些正規(guī)化的例子:

  • 語言學(xué)的 — Ispell 詞典嘗試將輸入詞縮減為一種正規(guī)化的形式;詞干分析器詞典移除詞的結(jié)尾

  • URL位置可以被規(guī)范化來得到等效的 URL 匹配:

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

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

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

  • 顏色名可以被它們的十六進(jìn)制值替換,例如red, green, blue, magenta -> FF0000, 00FF00, 0000FF, FF00FF

  • 如果索引數(shù)字,我們可以移除某些小數(shù)位來縮減可能的數(shù)字的范圍,因此如果只保留小數(shù)點(diǎn)后兩位,例如3.14159265359、3.1415926、3.14在正規(guī)化后會變得相同。

一個詞典是一個程序,它接受一個記號作為輸入,并返回:

  • 如果輸入的記號對詞典是已知的,則返回一個詞位數(shù)組(注意一個記號可能產(chǎn)生多于一個詞位)

  • 一個TSL_FILTER標(biāo)志被設(shè)置的單一詞位,用一個新記號來替換要被傳遞給后續(xù)字典的原始記號(做這件事的一個字典被稱為一個過濾字典

  • 如果字典知道該記號但它是一個停用詞,則返回一個空數(shù)組

  • 如果字典不識別該輸入記號,則返回NULL

PostgreSQL為許多語言提供了預(yù)定義的字典。也有多種預(yù)定義模板可以被用于創(chuàng)建帶自定義參數(shù)的新詞典。每一種預(yù)定義詞典模板在下面描述。如果沒有合適的現(xiàn)有模板,可以創(chuàng)建新的;例子見PostgreSQL發(fā)布的contrib/區(qū)域。

一個文本搜索配置把一個解析器和一組處理解析器輸出記號的詞典綁定在一起。對于每一中解析器能返回的記號類型,配置都指定了一個單獨(dú)的詞典列表。當(dāng)該類型的一個記號被解析器找到時,每一個詞典都被按照順序查詢,知道某個詞典將其識別為一個已知詞。如果它被標(biāo)識為一個停用詞或者沒有一個詞典識別它,它將被丟棄并且不會被索引和用于搜索。通常,第一個返回非NULL輸出的詞典決定結(jié)果,并且任何剩下的詞典都不會被查找;但是一個過濾詞典可以將給定詞替換為一個被修改的詞,它再被傳遞給后續(xù)的詞典。

配置一個詞典列表的通用規(guī)則是將最狹窄、最特定的詞典放在第一位,然后是更加通用的詞典,以一個非常通用的詞典結(jié)尾,像一個Snowball詞干分析器或什么都識別的simple。例如,對于一個天文學(xué)相關(guān)的搜索(astro_en 配置)我們可以把記號類型asciiword(ASCII 詞)綁定到一個天文學(xué)術(shù)語的分類詞典、一個通用英語詞典和一個Snowball英語詞干分析器:

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

一個過濾詞典可以被放置在列表中的任意位置,除了在最后,因?yàn)檫^濾詞典放在最后就等于無用。過濾詞典可用于部分正規(guī)化詞來簡化后續(xù)詞典的工作。例如,一個過濾詞典可以被用來從音標(biāo)字母中移除重音符號,就像unaccent模塊所做的。

12.6.1. 停用詞

停用詞是非常常用、在幾乎每一個文檔中出現(xiàn)并且沒有任何區(qū)分度的詞。因此,在全文搜索的環(huán)境中它們可以被忽略。例如,每一段英語文本都包含athe等次,因此把它們存儲在一個索引中是沒有用處的。但是,停用詞確實(shí)會影響在tsvector中的位置,這進(jìn)而會影響排名:

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

缺失的位置 1、2、4 是因?yàn)橥S迷~。文檔的排名計(jì)算在使用和不使用停用詞的情況下是很不同的:

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詞典首先正規(guī)化詞并且查看停用詞列表,而Snowball詞干分析器首先檢查停用詞的列表。這種不同行為的原因是一沖降低噪聲的嘗試。

12.6.2. 簡單詞典

simple詞典模板的操作是將輸入記號轉(zhuǎn)換為小寫形式并且根據(jù)一個停用詞文件檢查它。如果該記號在該文件中被找到,則返回一個空數(shù)組,導(dǎo)致該記號被丟棄。否則,該詞的小寫形式被返回作為正規(guī)化的詞位。作為一種選擇,該詞典可以被配置為將非停用詞報(bào)告為未識別,允許它們被傳遞給列表中的下一個詞典。

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

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

這里,english是一個停用詞文件的基本名稱。該文件的全名將是$SHAREDIR/tsearch_data/english.stop,其中$SHAREDIR表示PostgreSQL安裝的共享數(shù)據(jù)目錄,通常是/usr/local/share/postgresql(如果不確定,使用 pg_config --sharedir)。該文件格式是一個詞的列表,每行一個。空行和尾部的空格都被忽略,并且大寫也被折疊成小寫,但是沒有其他對該文件內(nèi)容的處理。

現(xiàn)在我們能夠測試我們的詞典:

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

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

如果沒有在停用詞文件中找到,我們也可以選擇返回NULL而不是小寫形式的詞。這種行為可以通過設(shè)置詞典的Accept參數(shù)為false來選擇。繼續(xù)該例子:

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
-----------
 {}

在使用默認(rèn)值Accept = true,只有把一個simple詞典放在詞典列表的尾部才有用,因?yàn)樗鼘⒉粫鬟f任何記號給后續(xù)的詞典。相反,Accept = false只有當(dāng)至少有一個后續(xù)詞典的情況下才有用。

小心

大部分類型的詞典依賴于配置文件,例如停用詞文件。這些文件必須被存儲為 UTF-8 編碼。當(dāng)它們被讀入服務(wù)器時,如果存在不同,它們將被翻譯成真實(shí)的數(shù)據(jù)庫編碼。

小心

通常,當(dāng)一個詞典配置文件第一次在數(shù)據(jù)庫會話中使用時,數(shù)據(jù)庫會話將只讀取它一次。如果你修改了一個配置文件并且想強(qiáng)迫現(xiàn)有的會話取得新內(nèi)容,可以在該詞典上發(fā)出一個ALTER TEXT SEARCH DICTIONARY命令。這可以是一次更新,它并不實(shí)際修改任何參數(shù)值。

12.6.3. 同義詞詞典

這個詞典模板被用來創(chuàng)建用于同義詞替換的詞典。不支持短語(使用分類詞典模板(本文中第 12.6.4 節(jié))可以支持)。一個同義詞詞典可以被用來解決語言學(xué)問題,例如,阻止一個英語詞干分析器詞典把詞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模板要求的唯一參數(shù)是SYNONYMS,它是其配置文件的基本名 — 上例中的my_synonyms。該文件的完整名稱將是$SHAREDIR/tsearch_data/my_synonyms.syn(其中$SHAREDIR表示 PostgreSQL安裝的共享數(shù)據(jù)目錄)。該文件格式是每行一個要被替換的詞,后面跟著它的同義詞,用空白分隔??招泻徒Y(jié)尾的空格會被忽略。

synonym模板還有一個可選的參數(shù)CaseSensitive,其默認(rèn)值為false。當(dāng)CaseSensitivefalse時,同義詞文件中的詞被折疊成小寫,這和輸入記號一樣。當(dāng)它為true時,詞和記號將不會被折疊成小寫,但是比較時就好像被折疊過一樣。

一個星號(*)可以被放置在配置文件中一個同義詞的末尾。這表示該同義詞是一個前綴。當(dāng)項(xiàng)被用在to_tsvector()中時,星號會被忽略;當(dāng)它被用在to_tsquery()中時,結(jié)果將是一個帶有前綴匹配標(biāo)記器(見第 12.3.2 節(jié))的查詢項(xiàng)。例如,假設(shè)我們在$SHAREDIR/tsearch_data/synonym_sample.syn中有這些項(xiàng):

postgres        pgsql
postgresql      pgsql
postgre pgsql
gogle   googl
indices index*

那么我們將得到這些結(jié)果:

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)是一個詞的集合,其中包括了詞與短語之間的聯(lián)系,即廣義詞(BT)、狹義詞(NT)、首選詞、非首選詞、相關(guān)詞等。

基本上一個分類詞典會用一個首選詞替換所有非首選詞,并且也可選擇地保留原始術(shù)語用于索引。PostgreSQL的分類詞典的當(dāng)前實(shí)現(xiàn)是同義詞詞典的一個擴(kuò)展,并增加了短語支持。一個分類詞典要求一個下列格式的配置文件:

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

其中冒號(:)符號扮演了一個短語及其替換之間的定界符。

一個分類詞典使用一個子詞典(在詞典的配置中指定)在檢查短語匹配之前正規(guī)化輸入文本。只能選擇一個子詞典。如果子詞典無法識別一個詞,將報(bào)告一個錯誤。在這種情況下,你應(yīng)該移除該詞的使用或者讓子詞典學(xué)會這個詞。你可以在一個被索引詞的開頭放上一個星號(*)來跳過在其上應(yīng)用子詞典,但是所有采樣詞必須被子詞典知道。

如果有多個短語匹配輸入,則分類詞典選擇最長的那一個,并且使用最后的定義打破連結(jié)。

由子詞典識別的特定停用詞不能夠被指定;改用?標(biāo)記任何可以出現(xiàn)停用詞的地方。例如,假定根據(jù)子詞典athe是停用詞:

? one ? two : swsw

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

由于一個分類詞典具有識別短語的能力,它必須記住它的狀態(tài)并與解析器交互。一個分類詞典使用這些任務(wù)來檢查它是否應(yīng)當(dāng)處理下一個詞或者停止累積。分類詞典必須被小心地配置。例如,如果分類詞典被分配只處理asciiword記號,則一個形如one 7的分類詞典定義將不會工作,因?yàn)橛浱栴愋?code class="literal">uint沒有被分配給該分類詞典。

小心

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

12.6.4.1. 分類詞典配置

要定義一個新的分類詞典,可使用thesaurus模板。例如:

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

這里:

  • thesaurus_simple是新詞典的名稱

  • mythesaurus是分類詞典配置文件的基礎(chǔ)名稱(它的全名將是$SHAREDIR/tsearch_data/mythesaurus.ths,其中$SHAREDIR表示安裝的共享數(shù)據(jù)目錄)。

  • pg_catalog.english_stem是要用于分類詞典正規(guī)化的子詞典(這里是一個 Snowball 英語詞干分析器)。注意子詞典將擁有它自己的配置(例如停用詞),但這里沒有展示。

現(xiàn)在可以在配置中把分類詞典thesaurus_simple綁定到想要的記號類型上,例如:

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

12.6.4.2. 分類詞典例子

考慮一個簡單的天文學(xué)分類詞典thesaurus_astro,它包含一些天文學(xué)詞組合:

supernovae stars : sn
crab nebulae : crab

下面我們創(chuàng)建一個詞典并綁定一些記號類型到一個天文學(xué)分類詞典以及英語詞干分析器:

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;

現(xiàn)在我們可以看看它如何工作。ts_lexize對于測試一個分類詞典用處不大,因?yàn)樗阉妮斎肟闯墒且粋€單一記號。我們可以用plainto_tsqueryto_tsvector,它們將把其輸入字符串打斷成多個記號:

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

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

原則上,如果你對參數(shù)加了引號,你可以使用to_tsquery

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

注意在thesaurus_astrosupernova star匹配supernovae stars,因?yàn)槲覀冊诜诸愒~典定義中指定了english_stem詞干分析器。該詞干分析器移除了es。

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

supernovae stars : sn supernovae stars

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

12.6.5. Ispell 詞典

Ispell詞典模板支持詞法詞典,它可以把一個詞的很多不同語言學(xué)的形式正規(guī)化成相同的詞位。例如,一個英語Ispell詞典可以匹配搜索詞bank的詞尾變化和詞形變化,例如bankingbanked、 banks、banks'bank's。

標(biāo)準(zhǔn)的PostgreSQL發(fā)布不包括任何Ispell配置文件。用于很多種語言的詞典可以從Ispell得到。此外,也支持一些更現(xiàn)代的詞典文件格式 — MySpell(OO < 2.0.1)和Hunspell(OO >= 2.0.2)。一個很大的詞典列表在OpenOffice Wiki上可以得到。

要創(chuàng)建一個Ispell詞典,執(zhí)行這三步:

  • 下載詞典配置文件。OpenOffice擴(kuò)展文件的擴(kuò)展名是.oxt。有必要抽取.aff.dic文件,把擴(kuò)展改為.affix.dict。對于某些詞典文件,還需要使用下面的命令把字符轉(zhuǎn)換成 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);
    

這里,DictFile、AffFileStopWords指定詞典、詞綴和停用詞文件的基礎(chǔ)名稱。停用詞文件的格式和前面解釋的simple詞典類型相同。其他文件的格式在這里沒有指定,但是也可以從上面提到的網(wǎng)站獲得。

Ispell 詞典通常識別一個有限集合的詞,這樣它們后面應(yīng)該跟著另一個更廣義的詞典;例如,一個 Snowball 詞典,它可以識別所有東西。

Ispell.affix文件具有下面的結(jié)構(gòu):

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文件具有下面的結(jié)構(gòu):

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

.dict文件的格式是:

basic_form/affix_class_name

.affix文件中,每一個詞綴標(biāo)志以下面的格式描述:

condition > [-stripping_letters,] adding_affix

這里的條件具有和正則表達(dá)式相似的格式。它可以使用分組[...][^...]。例如,[AEIOU]Y表示詞的最后一個字母是"y"并且倒數(shù)第二個字母是"a"、"e"、 "i"、"o"或者"u"。[^EY]表示最后一個字母既不是"e"也不是"y"。

Ispell 詞典支持劃分復(fù)合詞,這是一個有用的特性。注意詞綴文件應(yīng)該用compoundwords controlled語句指定一個特殊標(biāo)志,它標(biāo)記可以參與到復(fù)合格式中的詞典詞:

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文件具有下面的結(jié)構(gòu):

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]

一個詞綴類的第一行是頭部。頭部后面列出了詞綴規(guī)則的域:

  • 參數(shù)名(PFX 或者 SFX)

  • 標(biāo)志(詞綴類的名稱)

  • 從該詞的開始(前綴)或者結(jié)尾(后綴)剝離字符

  • 增加詞綴

  • 和正則表達(dá)式格式類似的條件。

.dict文件看起來和Ispell.dict文件相似:

larder/M
lardy/RT
large/RSPMYT
largehearted

注意

MySpell 不支持復(fù)合詞。Hunspell則對復(fù)合詞有更好的支持。當(dāng)前,PostgreSQL只實(shí)現(xiàn)了 Hunspell 中基本的復(fù)合詞操作。

12.6.6. Snowball 詞典

Snowball詞典模板基于 Martin Porter 的一個項(xiàng)目,他是流行的英語 Porter 詞干分析算法的發(fā)明者。Snowball 現(xiàn)在對許多語言提供詞干分析算法(詳見Snowball 站點(diǎn))。每一個算法懂得按照其語言中的拼寫,如何縮減詞的常見變體形式為一個基礎(chǔ)或詞干。一個 Snowball 詞典要求一個language參數(shù)來標(biāo)識要用哪種詞干分析器,并且可以選擇地指定一個stopword文件名來給出一個要被消除的詞列表(PostgreSQL的標(biāo)準(zhǔn)停用詞列表也是由 Snowball 項(xiàng)目提供的)。例如,有一個內(nèi)建的定義等效于

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

停用詞文件格式和已經(jīng)解釋的一樣。

一個Snowball詞典識別所有的東西,不管它能不能簡化該詞,因此它應(yīng)當(dāng)被放置在詞典列表的最后。把它放在任何其他詞典前面是沒有用處的,因?yàn)橐粋€記號永遠(yuǎn)不會穿過它而進(jìn)入到下一個詞典。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號