Alb*_*iir 5 postgresql indexing localization tokenize string-comparison
我有一个大的postgres位置(商店,地标等)表,用户可以通过各种方式搜索.当用户想要搜索某个地点的名称时,系统当前会这样做(假设搜索在咖啡馆):
lower(location_name) LIKE '%cafe%'
Run Code Online (Sandbox Code Playgroud)
作为查询的一部分.这非常低效.这是非常的.我必须加快速度.我试过索引表
gin(to_tsvector('simple', location_name))
Run Code Online (Sandbox Code Playgroud)
和搜索
(to_tsvector('simple',location_name) @@ to_tsquery('simple','cafe'))
Run Code Online (Sandbox Code Playgroud)
它工作得很漂亮,并且将搜索时间减少了几个数量级.
但是,位置名称可以是任何语言,包括中文等不是以空格分隔的语言.这个新系统无法找到任何中文位置,除非我搜索确切的名称,而旧系统可以找到与部分名称匹配就好了.
所以,我的问题是:我可以让它同时适用于所有语言,还是我走错了路?
如果您想优化任意子字符串匹配,一种选择是使用模块pg_tgrm. 添加索引:
CREATE INDEX table_location_name_trigrams_key ON table
USING gin (location_name gin_trgm_ops);
Run Code Online (Sandbox Code Playgroud)
这会将“Simple Cafe”分解为“sim”、“imp”、“mpl”等,并为每行中的每个 trigam 的索引添加一个条目。然后,查询规划器可以自动使用该索引进行子字符串模式匹配,包括:
SELECT * FROM table WHERE location_name ILIKE '%cafe%';
Run Code Online (Sandbox Code Playgroud)
此查询将在索引中查找“caf”和“afe”,找到交集,获取这些行,然后根据您的模式检查每一行。(最后一项检查是必要的,因为“caf”和“afe”的交集既匹配“simple cafe”又匹配“unsafescaffolding”,而“%cafe%”应该只匹配一个)。随着输入模式变长,索引会变得更加有效,因为它可以排除更多行,但它仍然不如索引整个单词那么有效,因此不要指望性能会比to_tsvector.
问题是,三元组对于三个字符以下的模式根本不起作用。这可能会或可能不会影响您的申请。
编辑:我最初将其添加为评论。
昨晚,当我快要睡着的时候,我又有了一个想法。创建一个cjk_chars函数,它接受输入字符串、regexp_matches整个 CJK Unicode 范围,并返回任何此类字符的数组,或者NULL如果没有则返回。在 上添加 GIN 索引cjk_chars(location_name)。然后查询:
WHERE CASE
WHEN cjk_chars('query') IS NOT NULL THEN
cjk_chars(location_name) @> cjk_chars('query')
AND location_name LIKE '%query%'
ELSE
<tsvector/trigrams>
END
Run Code Online (Sandbox Code Playgroud)
哒哒,一元字母!
| 归档时间: |
|
| 查看次数: |
912 次 |
| 最近记录: |