假设我有一个名为 movie
的表,其中有一个字段 name
,即 VARCHAR
字段。
我想在我的网站中实现一个搜索栏,以便当用户输入字符串时我可以查询具有该名称的电影。
我的第一个方法非常天真:
select *
from movie
where name like '%user_string%';
限制是:
- 特殊字符。假设用户字符串是“Let's go”,我希望它返回名称为“Let's go”的电影,即使撇号丢失也是如此。
- 口音。假设用户字符串是“Pokemon”,我希望它返回名称为“Pokémon”的电影,即使重音丢失。
我的想法是创建一个额外的 normalized_name
字段,该字段是使用 name
字段计算的,并删除所有特殊字符和重音符号。那么查询将变成:
select *
from movie
where normalized_name like '%user_string%';
例如:用户搜索pokemon
,数据库查询返回一部normalized_name
= pokemon
的电影,真实姓名为神奇宝贝
。显然,用户字符串也将首先被标准化 - 以便也允许通过电影真实姓名进行搜索。
现在,这是一个有效的方法吗?使用最广泛的是什么 - 也可能使搜索变得更好?有相关文献吗?
最佳答案
在列的剥离版本上创建三元组索引:
创建必要的扩展并创建一个名为
f_unaccent
的不可变unaccent
(有关详细信息,请参阅 here):CREATE EXTENSION pg_trgm; CREATE EXTENSION unaccent; CREATE OR REPLACE FUNCTION public.immutable_unaccent(regdictionary, text) RETURNS text LANGUAGE c IMMUTABLE PARALLEL SAFE STRICT AS '$libdir/unaccent', 'unaccent_dict'; CREATE OR REPLACE FUNCTION public.f_unaccent(text) RETURNS text LANGUAGE sql IMMUTABLE PARALLEL SAFE STRICT AS $func$ SELECT public.immutable_unaccent(regdictionary 'public.unaccent', $1) $func$;
在列上创建三元组索引:
CREATE INDEX ON movie USING gin (translate(f_unaccent(name), '''', '') gin_trgm_ops);
现在执行以下查询:
SELECT * FROM movie WHERE translate(f_unaccent(name), '''', '') ILIKE translate(f_unaccent('user_string'), '''');
关于sql - 通过数据库中的文本字段实现智能搜索,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65044931/