背景
用户可以输入名称,系统应该匹配文本,即使用户输入或数据库字段包含重音 (UTF-8) 字符。这是使用 pg_trgm
模块。
问题
代码类似于以下内容:
SELECT
t.label
FROM
the_table t
WHERE
label % 'fil'
ORDER BY
similarity( t.label, 'fil' ) DESC
当用户键入 fil
时,查询匹配 filbert
但不匹配 filé powder
。 (因为重音字符?)
失败的解决方案 #1
我尝试实现一个 unaccent 函数并将查询重写为:
SELECT
t.label
FROM
the_table t
WHERE
unaccent( label ) % unaccent( 'fil' )
ORDER BY
similarity( unaccent( t.label ), unaccent( 'fil' ) ) DESC
这只返回 filbert
。
失败的解决方案 #2
按照建议:
CREATE EXTENSION pg_trgm;
CREATE EXTENSION unaccent;
CREATE OR REPLACE FUNCTION unaccent_text(text)
RETURNS text AS
$BODY$
SELECT unaccent($1);
$BODY$
LANGUAGE sql IMMUTABLE
COST 1;
表上的所有其他索引都已删除。然后:
CREATE INDEX label_unaccent_idx
ON the_table( lower( unaccent_text( label ) ) );
这只返回一个结果:
SELECT
t.label
FROM
the_table t
WHERE
label % 'fil'
ORDER BY
similarity( t.label, 'fil' ) DESC
问题
重写查询以确保返回两个结果的最佳方法是什么?
谢谢!
相关
http://wiki.postgresql.org/wiki/What%27s_new_in_PostgreSQL_9.0#Unaccent_filtering_dictionary
http://postgresql.1045698.n5.nabble.com/index-refuses-to-build-td5108810.html
最佳答案
您没有使用 pg_trgm
模块提供的运算符类。创建这样的索引:
CREATE INDEX label_Lower_unaccent_trgm_idx
ON test_trgm USING gist (lower(unaccent_text(label)) gist_trgm_ops);
最初,我在这里有一个 GIN 索引,但 GiST 通常更适合这种查询,因为它可以返回按相似性排序的值。见:
您的查询必须匹配索引表达式才能使用它。
SELECT label
FROM the_table
WHERE lower(unaccent_text(label)) % 'fil'
ORDER BY similarity(label, 'fil') DESC; -- ok to use original string here
但是,根据 %
运算符,“filbert”和“filé powder”实际上与“fil”并不十分相似。我怀疑你真的想要:
SELECT label
FROM the_table
WHERE lower(unaccent_text(label)) LIKE 'fil%' -- !
ORDER BY similarity(label, 'fil') DESC; -- ok to use original string here
这会找到所有以搜索字符串开头的字符串,并首先根据 %
运算符对最佳匹配项进行排序。
从 PostgreSQL 9.1 开始,表达式可以使用 GIN 或 GiST 索引! The manual :
Beginning in PostgreSQL 9.1, these index types also support index searches for
LIKE
andILIKE
, for example
如果您确实打算使用 %
运算符:
尝试 adapting the threshold对于相似性运算符 %
:
SET pg_trgm.similarity_threshold = 0.1; -- Postgres 9.6 or later
SELECT set_limit(0.1); -- Postgres 9.5 or older
或者更低?默认值为 0.3。只是为了查看阈值是否过滤了额外的匹配项。
关于postgresql - 自动完成字段的类似 UTF-8 字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10237366/