首页 > 解决方案 > 如何将 PostgreSQL 文本搜索与模糊字符串匹配相结合

问题描述

我希望能够从 type 的列中查询单词,ts_vector但是所有具有低于 X 的 levenshtein 距离的东西都应该被认为是匹配的。

像这样的东西在哪里my_table

id | my_ts_vector_colum             | sentence_as_text
------------------------------------------------------
1  | 'bananna':3 'tasty':2 'very':1 | Very tasty bananna
2  | 'banaana':2 'yellow':1         | Yellow banaana
3  | 'banana':2 'usual':1           | Usual banana
4  | 'baaaanaaaanaaa':2 'black':1   | Black baaaanaaaanaaa

我想查询类似“给我所有行的 ID,其中包含单词香蕉或类似于香蕉的单词,其中相似意味着它的 Levenshtein 距离小于 4”。所以结果应该是 1、2 和 3。

我知道我可以做类似的事情select id from my_table where my_ts_vector_column @@ to_tsquery('banana');,但这只会让我完全匹配。

我也知道我可以做类似的事情select id from my_table where levenshtein(sentence_as_text, 'banana') < 4;,但这仅适用于文本列,并且仅当匹配项仅包含单词香蕉时才有效。

但我不知道是否或如何将两者结合起来。

我要执行此操作的 PS 表包含大约 200 万条记录,并且查询应该非常快(肯定少于 100 毫秒)。

PPS - 我可以完全控制表的架构,因此更改数据类型、创建新列等是完全可行的。

标签: postgresqlfull-text-searchlevenshtein-distance

解决方案


大概 200 万个短句包含的不同单词要少得多。但如果你所有的句子都有“创造性”的拼写,也许不是。

因此,您也许可以创建一个不同单词的表,以便使用未索引的距离函数相对快速地搜索:

create materialized view words as 
    select distinct unnest(string_to_array(lower(sentence_as_text),' ')) word from my_table;

并在更大的表中创建一个精确的索引:

create index on my_table using gin (string_to_array(lower(sentence_as_text),' '));

然后一起加入:

select * from my_table join words 
   ON (ARRAY[word] <@ string_to_array(lower(sentence_as_text),' ')) 
   WHERE levenshtein(word,'banana')<4;

推荐阅读