支持的版本: 当前 (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

  • 颜色名称可以替换为其十六进制值,例如,红色、绿色、蓝色、洋红色 -> 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 词典会识别所有内容,无论它是否能够简化单词,因此应将其放置在词典列表的末尾。将其放在任何其他词典之前都是无用的,因为标记永远不会通过它传递到下一个词典。

提交更正

如果您发现文档中有任何不正确的地方,与您使用特定功能的体验不符,或需要进一步澄清,请使用 此表单 报告文档问题。