Postgres 全文搜索和拼写错误(又名模糊全文搜索)

090*_*9EM 6 postgresql full-text-search fuzzy-search

我有一个场景,我有需要能够搜索的非正式通信数据。因此,我想要全文搜索,但我也要弄清楚拼写错误。问题是如何考虑拼写错误以便能够进行模糊全文搜索?

这在Postgres Full Text Search is Good Enough非常简要地讨论过,该文章讨论了拼写错误。

所以我建立了一个“文档”表,创建了索引等。

CREATE TABLE data (
  id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, 
  text TEXT NOT NULL);
Run Code Online (Sandbox Code Playgroud)

我可以创建一个额外的 tsvector 类型的列并相应地索引......

alter table data 
  add column search_index tsvector 
  generated always as (to_tsvector('english', coalesce(text, ''))) 
  STORED;

create index search_index_idx on data using gin (search_index);
Run Code Online (Sandbox Code Playgroud)

例如,我有一些文本,其中数据显示“气球”,但有人可能会搜索“气球”,所以我插入了两行(一排故意拼错)...

insert into data (text) values ('baloon');
insert into data (text) values ('balloon');

select * from data;

id |  text   | search_index
----+---------+--------------
 1 | baloon  | 'baloon':1
 2 | balloon | 'balloon':1
Run Code Online (Sandbox Code Playgroud)

...并对数据执行全文搜索...

select * from data where search_index @@ plainto_tsquery('balloon');

 id |  text   | search_index
----+---------+--------------
  2 | balloon | 'balloon':1
(1 row)
Run Code Online (Sandbox Code Playgroud)

但是我没有得到拼写错误版本“baloon”的结果......所以使用链接文章中的建议我已经建立了我词典中所有单词的查找表如下......

“通过将类似的词素附加到您的 tsquery 中,您可能会获得良好的结果”

CREATE TABLE data_words AS SELECT word FROM ts_stat('SELECT to_tsvector(''simple'', text) FROM data');

CREATE INDEX data_words_idx ON data_words USING GIN (word gin_trgm_ops);
Run Code Online (Sandbox Code Playgroud)

...我可以搜索可能拼写错误的相似词

从 data_words 中选择 word, Similarity(word, 'balloon') 作为相似度,其中 Similarity(word, 'balloon') > 0.4 order by Similarity(word, 'balloon');

  word   | similarity
---------+------------
 baloon  |  0.6666667
 balloon |          1
Run Code Online (Sandbox Code Playgroud)

...但是我如何在查询中包含拼写错误的单词?

这不是上面那篇文章的意思吗?

select plainto_tsquery('balloon' || ' ' || (select string_agg(word, ' ') from data_words where similarity(word, 'balloon') > 0.4));

         plainto_tsquery
----------------------------------
 'balloon' & 'baloon' & 'balloon'
(1 row)
Run Code Online (Sandbox Code Playgroud)

...插入实际搜索,我没有得到任何行!

select * from data where text @@ plainto_tsquery('balloon' || ' ' || (select string_agg(word, ' ') from data_words where similarity(word, 'balloon') > 0.4));

select * from data where search_index @@ phraseto_tsquery('baloon balloon'); -- no rows returned
Run Code Online (Sandbox Code Playgroud)

我不确定我哪里出错了 - 有什么可以说明的吗?我觉得我非常接近这个目标......?

Lau*_*lbe 8

SELECT to_tsquery('balloon |' ||
                  string_agg(word, ' | ')
       )
FROM data_words
WHERE similarity(word, 'balloon') > 0.4;
Run Code Online (Sandbox Code Playgroud)