假设我有一个这样的表
id data
1 0001
2 1000
3 2010
4 0120
5 0020
6 0002
id
是主键,data
是固定长度字符串,其中字符可以是0,1,2。
有没有办法建立一个索引,所以我可以快速找到与给定字符串中的n个字符不同的字符串?比如字符串0001
和n = 1
我希望获得第6行。
感谢。
答案 0 :(得分:2)
有levenshtein()
功能,由附加模块fuzzystrmatch提供。它完全符合您的要求:
SELECT *
FROM a
WHERE levenshtein(data, '1110') = 1;
但它不是很快。大表缓慢,因为它不能使用索引。
您可能会获得附加模块pg_trgm提供的相似性或距离运算符。这些可以使用链接手册页中详述的三元组索引。我没有到达任何地方,模块使用了不同的“相似性”定义。
一般来说问题似乎适合KNN ("k nearest neighbours") search pattern。
如果您的案例与问题中的示例一样简单,您可以将LIKE
与trigram GIN索引结合使用,这对于大表来说应该相当快:
SELECT *
FROM a
WHERE data <> '1110'
AND (data LIKE '_110' OR
data LIKE '1_10' OR
data LIKE '11_0' OR
data LIKE '111_');
显然,这种技术很快变得不可行,因为字符串越长且差异超过1
。
然而,由于字符串太短,任何查询都会匹配基表的相当大的百分比。因此,指数支持几乎不会给你任何东西。大多数情况下,Postgres按顺序扫描会更快。
我测试了10k和100k行,有和没有trigram GIN索引。由于约19%符合给定测试用例的标准,因此顺序扫描更快,levenshtein()
仍然获胜。对于匹配少于约5%的行(依赖)的更具选择性的查询,使用索引的查询(更快)更快。