字典用于消除在搜索中不应考虑的词语(停用词),并规范化词语,以便相同词语的不同派生形式能够匹配。一个成功规范化的词语被称为词素。除了提高搜索质量外,规范化和去除停用词还会减小文档的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 模块所做的那样。
停用词是那些非常常见、几乎出现在每份文档中且没有区分价值的词语。因此,在全文搜索的上下文中可以忽略它们。例如,每个英语文本都包含像a
和the
这样的词语,因此将它们存储在索引中毫无用处。但是,停用词确实会影响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
表示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.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
。当CaseSensitive
为false
时,同义词文件中的词语将被折叠为小写,输入标记也是如此。当它为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)
同义词词典(有时缩写为TZ)是一个词语集合,包含有关词语和短语关系的信息,即更广泛的术语(BT),更狭窄的术语(NT),首选术语,非首选术语,相关术语等。
基本上,同义词词典将所有非首选术语替换为一个首选术语,并可选地保留原始术语以进行索引。 PostgreSQL 当前同义词词典的实现是同义词词典的扩展,增加了 短语 支持。同义词词典需要以下格式的配置文件
# this is a comment sample word(s) : indexed word(s) more sample word(s) : more indexed word(s) ...
其中冒号(:
)符号充当短语及其替换项之间的分隔符。
同义词词典使用一个 子词典(在词典配置中指定)来规范化输入文本,然后再检查短语匹配。只能选择一个子词典。如果子词典无法识别一个词,就会报错。在这种情况下,您应该删除该词的使用或教子词典识别该词。您可以在索引词的开头放置一个星号(*
)来跳过对其应用子词典,但所有示例词都 必须 为子词典所知。
如果有多个短语与输入匹配,同义词词典将选择最长的匹配,并通过使用最后一个定义来打破平局。
子词典识别的特定停用词无法指定;而是使用 ?
来标记任何停用词可以出现的位置。例如,假设 a
和 the
都是子词典中的停用词
? one ? two : swsw
匹配 a one the two
和 the 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_tsquery
和 to_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 star
在 thesaurus_astro
中与 supernovae stars
匹配,因为我们在同义词词典定义中指定了 english_stem
词干提取器。词干提取器删除了 e
和 s
。
要同时索引原始短语和替代短语,只需将其包含在定义的右侧部分
supernovae stars : sn supernovae stars SELECT plainto_tsquery('supernova star'); plainto_tsquery ----------------------------- 'sn' & 'supernova' & 'star'
Ispell 词典模板支持 形态词典,它可以将同一个词的许多不同的语言形式规范化为同一个词素。例如,一个英文 Ispell 词典可以匹配搜索词 bank
的所有变格和变位,例如 banking
、banked
、banks
、banks'
和 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);
这里,DictFile
、AffFile
和 StopWords
指定词典、词缀和停用词文件的基名。停用词文件与上面解释的 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 的基本复合词操作。
Snowball 词典模板基于 Martin Porter 的一个项目,Martin Porter 是流行的 Porter 词干提取算法的发明者,用于英语。Snowball 现在为许多语言提供词干提取算法(有关更多信息,请参见 Snowball 网站)。每个算法都了解如何将词语的常见变体形式还原为其语言中的基本形式或词干形式。Snowball 词典需要一个 language
参数来标识要使用的词干提取器,并且可以选择指定一个 stopword
文件名,该文件名给出要消除的词语列表。(PostgreSQL 的标准停用词列表也由 Snowball 项目提供。)例如,有一个内置的定义等效于
CREATE TEXT SEARCH DICTIONARY english_stem ( TEMPLATE = snowball, Language = english, StopWords = english );
停用词文件的格式与前面解释的相同。
Snowball 词典识别所有词语,无论它是否能够简化该词语,因此它应该放在词典列表的最后。在任何其他词典之前使用它是无用的,因为令牌永远不会通过它传递到下一个词典。
如果您在文档中发现任何不正确的内容、与您对特定功能的体验不符或需要进一步说明的内容,请使用 此表格 报告文档问题。