Warm tip: This article is reproduced from serverfault.com, please click

sql-通过数据库中的文本字段实现智能搜索

(sql - Implement smart search by text field in database)

发布于 2020-11-27 23:28:28

假设我有一个以moviefield命名的表name,即VARCHARfield。

我想在我的网站中实现一个搜索栏,以便当用户输入字符串时,我可以查询具有该名称的电影。

我的第一种方法很幼稚:

select *
from movie
where name like '%user_string%';

限制是:

  1. 特殊的角色。假设用户字符串是“ Lets go”,即使缺少撇号,我希望它返回名称为“ Let's go”的电影。
  2. 口音。假设用户字符串是“ Pokemon”,即使缺少重音符号,我希望它返回名称为“Pokémon”的电影。

我的想法是创建一个附加normalized_name字段,该name字段使用去除了所有特殊字符和重音符号字段进行计算然后查询将变为:

select *
from movie
where normalized_name like '%user_string%';

例如:用户搜索pokemon,数据库查询返回带有normalized_name=的电影pokemon,真实名称为Pokémon显然,用户字符串也将首先进行规范化-以便也允许通过电影真实姓名进行搜索。

现在,这是一种有效的方法吗?什么是最广泛使用的-可能还会使搜索变得更好?有关于这个问题的文献吗?

Questioner
Matteo Silvestro
Viewed
0
Laurenz Albe 2020-11-30 14:56:23

在该列的精简版本上创建一个三字母索引:

  1. 创建必要的扩展并创建一个不可变的unaccent被称为f_unaccent有关更多信息,请参见此处):

    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$;
    
  2. 在列上创建三元组索引:

    CREATE INDEX ON movie USING gin (translate(f_unaccent(name), '''', '') gin_trgm_ops);
    
  3. 现在执行以下查询:

    SELECT * FROM movie
    WHERE translate(f_unaccent(name), '''', '') ILIKE translate(f_unaccent('user_string'), '''');