PostgreSQL 全文搜索 词典

1 背景知识

词典用于指定包含的 停用词stop words)。并且它能将词进行 正规化 ,正规化后的词能够匹配不同派生形式。一个 正规化 的词被称为一个 词位,有效提高搜索质量。

正规化 还能减小了文档的 tsvector 大小,因而提高了查询性能。

1.1 正规化的例子

red, green, blue, magenta -> FF0000, 00FF00, 0000FF, FF00FF 

1.2 词典输入和输出说明

1.3 预置词典和自定义词典

  1. 预定义字典
    PostgreSQL数据库为许多语言提供了预定义的字典。

  2. 自定义词典
    也有多种预定义模板可以被用于创建带自定义参数的新词典。每一种预定义词典模板在下面描述。

  3. 如果没有合适的现有模板,可以创建新的插件;例如 Kingbase 服务器编程 插件

1.4 文本搜索配置与词典的关系

一个文本搜索配置 把一个解析器 和的词典 绑定在一起。对于解析器返回的记号类型,文本搜索配置 都指定了对应的词典。

当一个 词位词典 找到时,词典将其识别为一个已知词。当它被标识为一个 停用词 时,它将被丢弃并且不会被索引和用于搜索。

当一个词位被找到后,后续同样的词位将会直接替换加快查找速度。

2 Stop word (停用词 )

在每一段英语文本都包含 athe 单词,因此把它们存储在一个索引中是没有用处的。但是,停用词确实会影响在 tsvector 中的位置,这进而会影响排名:

2.1 停用词的输出形式

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

由于停用词关系,位置 1、2、4 返回为空。

2.2 停用词对排名计算的影响

对于文档的排名计算 ,停用词影响 相似度,请看以下两个例子:

  1. 停用词较多时,相似度较低。
SELECT ts_rank_cd (to_tsvector('english', 'in the list of stop words'), to_tsquery('list & stop'));
 ts_rank_cd 
------------
       0.05
(1 row)
  1. 停用词较少时,相似度较高。
postgres=# SELECT ts_rank_cd (to_tsvector('english', 'list stop words'), to_tsquery('list & stop'));
 ts_rank_cd 
------------
        0.1
(1 row)

3 simple 词典

simple 词典:跟其他词典相似。将 记号 转换为小写形式并检查 停用词 文件。如果该 记号停用词 文件中被找到,则返回一个空数组,丢弃记号。否则,该词的小写形式被返回作为正规化的词位。

如果 标记 报告为未识别的情况,将 标记 传递给列表中的下一个词典继续判断。

3.1 创建自定义词典

使用 simple 模板的自定义词典的例子,创建public.simple_dict 词典。

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

3.2 测试自定义词典

  1. YeS 不是停用词,所以返回词位的小写形式 yes
SELECT ts_lexize('public.simple_dict', 'YeS');
//屏幕输出:
 ts_lexize
-----------
 {yes}
  1. The 则是停用词,所以返回NULL。
SELECT ts_lexize('public.simple_dict', 'The');
//屏幕输出:
 ts_lexize
-----------
 {}
  1. 找不到停用词( Accept = false)则返回
    Accept = false 时, 如果在停用词文件中找不到对应单词,则则返回NULL 。
ALTER TEXT SEARCH DICTIONARY public.simple_dict ( Accept = false );
ALTER TEXT SEARCH DICTIONARY
\dFd+ public.simple_dict
            List of text search dictionaries
 Schema |    Name     |     Template      |              Init options               | Description 
--------+-------------+-------------------+-----------------------------------------+-------------
 public | simple_dict | pg_catalog.simple | stopwords = 'english', accept = 'false' | 
(1 row)
SELECT ts_lexize('public.simple_dict', 'YeS');
 ts_lexize 
-----------
 
(1 row)
SELECT ts_lexize('public.simple_dict', 'The');
 ts_lexize 
-----------
 {}
(1 row)
Note

停用词文件必须使用 UTF-8 编码存储。
由于会话连接时会读取一次词典配置,如果想要修改后的词典生效,请使用 ALTER TEXT SEARCH DICTIONARY 命令。

4 Synonym 词典

同义词词典可以解决英语的同义词问题。例如,可以防止 Paris (巴黎) 单词正规化为 pari (相同),这样会造成匹配的时候搜索范围的扩大,搜索不准确。可以创建一个自定义的同义词词典,从而避免这个问题。

4.1 创建同义词词典

  1. Paris 解析为 pari
SELECT * FROM ts_debug('english', 'Paris');
   alias   |   description   | token |  dictionaries  |  dictionary  | lexemes
-----------+-----------------+-------+----------------+--------------+---------
 asciiword | Word, all ASCII | Paris | {english_stem} | english_stem | {pari}
  1. 创建同义词词典文件
    SYNONYMS 模版文件格式:每对同义词放置在同一行,单词后面跟上同义词,用空格分隔。
vi $PGHOME/share/tsearch_data/my_synonyms.syn
Paris paris
  1. 创建同义词词典。
参数 说明
my_synonym 自定义同义词词典的名称。
TEMPLATE 以默认的同义词词典作为模版,创建新的同义词词典。
SYNONYMS 同义词词典的模版文件,默认在 $SHAREDIR/tsearch_data/my_synonyms.syn 目录下。
CREATE TEXT SEARCH DICTIONARY my_synonym (
    TEMPLATE = synonym,
    SYNONYMS = my_synonyms
);
//屏幕输出:
CREATE TEXT SEARCH DICTIONARY

4.2 修改文本搜索配置

修改预定义配置,将 my_synonyms 词典放在 english_stem 词典之前。

ALTER TEXT SEARCH CONFIGURATION english
    ALTER MAPPING FOR asciiword
    WITH my_synonym, english_stem;
ALTER TEXT SEARCH CONFIGURATION
  1. 验证同义词问题已解决。
SELECT * FROM ts_debug('english', 'Paris');
//屏幕输出:
   alias   |   description   | token |       dictionaries        | dictionary | lexemes 
-----------+-----------------+-------+---------------------------+------------+---------
 asciiword | Word, all ASCII | Paris | {my_synonym,english_stem} | my_synonym | {paris}
(1 row)

4.3 同义词模版详解

* 星号可以放在配置文件同义词的末尾。表示该同义词是一个前缀。

  1. 当使用 to_tsvector() 函数时,* 星号将被忽略。
  2. 当使用 to_tsquery() 函数时,将产生带有匹配前缀的查询项。
    下面是 $SHAREDIR/tsearch_data/synonym_sample.syn 默认模版的内容。
postgres        pgsql
postgresql      pgsql
postgre pgsql
gogle   googl
indices index*
  1. 可以得出以下结果。
CREATE TEXT SEARCH DICTIONARY syn (template=synonym, synonyms='synonym_sample');
SELECT ts_lexize('syn', 'indices');
//屏幕输出:
 ts_lexize
-----------
 {index}
(1 row)
CREATE TEXT SEARCH CONFIGURATION tst (copy=simple);
ALTER TEXT SEARCH CONFIGURATION tst ALTER MAPPING FOR asciiword WITH syn;
SELECT to_tsvector('tst', 'indices');
 to_tsvector
-------------
 'index':1
(1 row)
SELECT to_tsquery('tst', 'indices');
//屏幕输出:
 to_tsquery
------------
 'index':*
(1 row)
SELECT 'indexes are very useful'::tsvector;
//屏幕输出:
            tsvector
---------------------------------
 'are' 'indexes' 'useful' 'very'
(1 row)
SELECT 'indexes are very useful'::tsvector @@ to_tsquery('tst', 'indices');
//屏幕输出:
 ?column?
----------
 t
(1 row)

5 Thesaurus 词典

Thesaurus 词典,也称分类词典。但是和 Synonym 词典 不同,Thesaurus 词典 能够匹配短语句。

短语

5.1 短语匹配原则

分类词典会用一个 首选词 替换所有 非首选词,并且也可选择地保留原始术语用于索引。

分类词典的当前实现是 Synonym 词典 的一个扩展,并增加了 短语 支持。分类词典的配置文件格式如下:

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

:(冒号)前面是 非首选词 ,后面是 首选词

5.2 子词典

一个分类词典使用一个 子词典 、用于 正规化 输入文本。

由于 子词典 不能指定自定义停用词;但可以使用逻辑判断符号 ? 代替 停用词。例如,子词典 athe 是停用词:

? one ? two : swsw

a one the two 或者 the one a two 都会被 swsw 替换。

Note

注意:在索引中使用分类词典时,当分类词典的参数发生变化时,都需要强制重建索引。

5.3 创建分类词典

  1. 创建分类词典文件。
vi $PGHOME/share/tsearch_data/mythesaurus.ths
one two three : *123
one two : *12
one : *1
two : *2

supernovae stars : *sn
supernovae : *sn
booking tickets : order invitation cards
booking ? tickets : order invitation Cards
  1. 创建分类词典。
CREATE TEXT SEARCH DICTIONARY thesaurus_simple (
    TEMPLATE = thesaurus,
    DictFile = mythesaurus,
    Dictionary = pg_catalog.english_stem
);
参数 说明
thesaurus_simple 自定义分类词典的名称。
TEMPLATE=thesaurus 分类词典的模版,请使用 \dFt命令查看。
Dictionary 分类词典的所使用的 子词典、请使用 \dFd命令查看。
DictFile = mythesaurus 分类词典的词典文件,请在 $PGHOME/share/tsearch_data/ 文件创建。

5.4 修改文本搜索配置

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

6 Thesaurus 词典配置

6.1 词典设计

  1. 准备一个天文学词库 thesaurus_astro ,其中包含一些天文词汇。
vi $PGHOME/share/tsearch_data/thesaurus_astro.ths
supernovae stars : sn
crab nebulae : crab

6.2 创建天文学词典

CREATE TEXT SEARCH DICTIONARY thesaurus_astro (
    TEMPLATE = thesaurus,
    DictFile = thesaurus_astro,
    Dictionary = english_stem
);

6.3 修改预定义配置

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

6.4 检查词典是否配置正确

6.4.1 验证 tsquery

SELECT plainto_tsquery('russian','supernova star');
 plainto_tsquery 
-----------------
 'sn'
(1 row)

6.4.2 验证 tsvector

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

7 Ispell 词典

8 参考链接

Thesaurus Dictionary 词典、Ispell Dictionary 词典、Snowball Dictionary 词典。请参考 PostgreSQL 官方文档