【问题标题】:Implement smart search by text field in database通过数据库中的文本字段实现智能搜索
【发布时间】:2021-03-10 16:25:56
【问题描述】:

假设我有一个名为movie 的表,其中包含一个字段name,即VARCHAR 字段。

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

我的第一个方法很幼稚:

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。显然,用户字符串也将首先被规范化 - 以便也允许通过电影真实姓名进行搜索。

现在,这是一种有效的方法吗?什么是最广泛使用的 - 也可能使搜索变得更好?有没有这方面的文献?

【问题讨论】:

    标签: sql database postgresql search


    【解决方案1】:

    在列的剥离版本上创建三元索引:

    1. 创建必要的扩展并创建一个不可变的unaccent,称为f_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$;
      
    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'), '''');
      

    【讨论】:

      猜你喜欢
      • 2018-10-12
      • 2010-09-18
      • 2015-04-10
      • 2011-02-10
      • 2011-03-09
      • 2019-04-15
      • 1970-01-01
      • 2013-02-09
      • 1970-01-01
      相关资源
      最近更新 更多