类似于@willglynn 已经发布的内容,我会考虑pg_trgm 模块。但最好使用 GiST 索引:
CREATE INDEX tbl_location_name_trgm_idx
USING gist(location_name gist_trgm_ops);
gist_trgm_ops 运算符类通常忽略大小写,ILIKE 与LIKE 一样快。 Quoting the source code:
注意:IGNORECASE 宏表示三元组不区分大小写。
我在这里使用COLLATE "C" - 这实际上不是特殊的排序规则(而是字节顺序),因为您的列中显然混合了各种排序规则。排序规则与排序或范围相关,对于基本的相似性搜索,您可以不用它。我会考虑为您的专栏设置COLLATE "C"。
此索引将为您的第一个简单形式的查询提供支持:
SELECT * FROM tbl WHERE location_name ILIKE '%cafe%';
- 非常快。
- 保留查找部分匹配项的功能。
- 添加了模糊搜索功能。
查看% operator 和set_limit()。
- GiST 索引对于使用
LIMIT n 的查询来选择n 个“最佳”匹配项也非常快。您可以在上面的查询中添加:
ORDER BY location_name <-> 'cafe'
LIMIT 20
详细了解“距离”运算符<->in the manual here。
甚至:
SELECT *
FROM tbl
WHERE location_name ILIKE '%cafe%' -- exact partial match
OR location_name % 'cafe' -- fuzzy match
ORDER BY
(location_name ILIKE 'cafe%') DESC -- exact beginning first
,(location_name ILIKE '%cafe%') DESC -- exact partial match next
,(location_name <-> 'cafe') -- then "best" matches
,location_name -- break remaining ties (collation!)
LIMIT 20;
我在几个应用程序中使用类似的东西以获得(对我而言)令人满意的结果。当然,结合应用多个功能,它会变得有点慢。找到你的甜蜜点...
您可以更进一步,为每种语言创建一个单独的partial index,并为每种语言使用匹配的排序规则:
CREATE INDEX location_name_trgm_idx
USING gist(location_name COLLATE "de_DE" gist_trgm_ops)
WHERE location_name_language = 'German';
-- repeat for each language
这只是有用的,如果您只希望每个查询的特定语言的结果,并且在这种情况下会非常快。