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

标签 sql database postgresql search

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

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

我的第一个方法非常天真:

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

限制是:

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

我的想法是创建一个额外的 normalized_name 字段,该字段是使用 name 字段计算的,并删除所有特殊字符和重音符号。那么查询将变成:

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

例如:用户搜索pokemon,数据库查询返回一部normalized_name = pokemon的电影,真实姓名为神奇宝贝。显然,用户字符串也将首先被标准化 - 以便也允许通过电影真实姓名进行搜索。

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

最佳答案

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

  1. 创建必要的扩展并创建一个名为 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$;
    
  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'), '''');
    

关于sql - 通过数据库中的文本字段实现智能搜索,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65044931/

相关文章:

MYSQL 检索一个表中在另一个表中出现最多的行

sql - 关于哪些操作索引效果不佳或未使用

c# - School Project- 当 nchar 设置为 9 位时,为什么我的数据会插入 8 位?

.net - 在 SQL Server 2008 中处理大量存档记录的最佳解决方案是什么?

ruby-on-rails - 使用多个连接在 Rails 3.2 中编写一个简单的 SQL 查询

postgresql - 如何在 postGIS 中存储路线图?

database - 在大 PostgreSQL 表上更新查询太慢

php - 一次更新两个 ID SQL - PHP

java - 更改数据库表时对 JAVA Web 应用程序的提示

php - 如何比较两个选择?