假设我有一个PostgreSQL中的user表,其中包含列

first_name (PK)
last_name (PK)
email

现在有数百万用户在里面.一个用户有记录

(John, Smith, john.smith@gmail.com)

现在我找他,错误地输入了Johny Smit.

我怎么能找到唱片而且这么快? SQLAchemy也可以吗?

推荐答案

您可以使用基于trigram的索引和pg_trgm扩展名中包含的搜索:demo

create extension pg_trgm;
create index trgm_idx on my_table using GiST ( first_name gist_trgm_ops
                                              ,last_name  gist_trgm_ops);
select * from my_table 
where    first_name % 'Johny' 
  and    last_name  % 'Smit' 
order by last_name <->'Smit'
        ,first_name<->'Johny'
limit 5;
first_name last_name email
John Smith john.smith@gmail.com
QUERY PLAN
Limit (cost=0.28..8.31 rows=1 width=119) (actual time=19.341..19.353 rows=1 loops=1)
  Output: first_name, last_name, email, ((first_name <-> 'Johny'::text)), ((last_name <-> 'Smit'::text))
  -> Index Scan using trgm_idx on public.my_table (cost=0.28..8.31 rows=1 width=119) (actual time=19.337..19.348 rows=1 loops=1)
        Output: first_name, last_name, email, (first_name <-> 'Johny'::text), (last_name <-> 'Smit'::text)
        Index Cond: ((my_table.first_name % 'Johny'::text) AND (my_table.last_name % 'Smit'::text))
        Order By: ((my_table.first_name <-> 'Johny'::text) AND (my_table.last_name <-> 'Smit'::text))
Planning Time: 1.364 ms
Execution Time: 19.416 ms
  1. 在现实生活中,它不会像现在这样快,因为我刚刚把John Smith埋在一堆John Smithk随机uuid下.
  2. 你将不得不调整你的相似性目标,仍然可能搜索一些最匹配的,并以某种方式从中挑选出来--可能有很多人的名字也与你的搜索匹配.
  3. 您可能希望使用一个表达式索引来合并这两个字段,这样您就可以只处理一个搜索短语和一个结果相似性度量,而不必解析两个.
drop index trgm_idx ;
create index trgm_idx2 on my_table 
   using GiST ((first_name||' '||last_name) gist_trgm_ops);
prepare find_john_smith_using_pg_trgm(text) as 
select *,$1 as search_phrase
        , (first_name||' '||last_name)<->  $1 as "<->"
        , (first_name||' '||last_name)<<-> $1 as "<<->"
        , (first_name||' '||last_name)<<<->$1 as "<<<->"
        , word_similarity(first_name||' '||last_name,$1)
        , strict_word_similarity(first_name||' '||last_name,$1)
from my_table 
where    (first_name||' '||last_name) % $1
order by (first_name||' '||last_name)<->$1
limit 5;

execute find_john_smith_using_pg_trgm('Johny Smit');
first_name last_name email search_phrase <-> <<-> <<<-> word_similarity strict_word_similarity
John Smith john.smith@gmail.com Johny Smit 0.4285714 0.38461536 0.4285714 0.61538464 0.5714286
Johan Smittson johan.smittson@gmail.com Johny Smit 0.6315789 0.6111111 0.6315789 0.3888889 0.36842105
execute find_john_smith_using_pg_trgm('Johny');
first_name last_name email search_phrase <-> <<-> <<<-> word_similarity strict_word_similarity
John Smith john.smith@gmail.com Johny 0.6923077 0.6363636 0.6923077 0.36363637 0.30769232
execute find_john_smith_using_pg_trgm('Smitt');
first_name last_name email search_phrase <-> <<-> <<<-> word_similarity strict_word_similarity
Johan Smittson johan.smittson@gmail.com Smitt 0.6875 0.6666666 0.6875 0.33333334 0.3125
John Smith john.smith@gmail.com Smitt 0.6923077 0.6363636 0.6923077 0.36363637 0.30769232
  1. 如果你确实将它们分开,你可以建立优先级,例如,按两者的加权平均值排序—可以安全地假设last_name上的匹配比first_name上的匹配具有一些优先级,特别是因为姓氏不经常被更改(小号、缩写、昵称、第二名等).

Postgresql相关问答推荐

如何使用postgr sql regex删除重复项和inc表记录

在Axum 0.5中,如何在一个请求处理程序中同时使用数据库和路径解析?

Heroku Rails 4 无法连接到服务器:connection refused

如何 Select 列值为空的行?

PostgreSQL如何连接间隔值'2天'

当记录包含 json 或字符串的混合时,如何防止 Postgres 中的invalid input syntax for type json

错误:must be owner of language plpgsql

设置 Phoenix 框架和 Ecto 以使用 UUID:如何插入生成的值?

将属性添加到 Sequelize FindOne 返回的对象

在 PostgreSQL 中的表上禁用 DELETE?

如何语法判断 PostgreSQL 配置文件?

在 PostgreSQL 中使用 Cursors进行分页

如何从 CSV 为 PostgreSQL 副本生成模式

每个数据库提供程序类型允许的最大参数数是多少?

docker postgres 无法从指定端口启动

PG::ConnectionBad FATAL:role "Myname" does not exist

安装了 Postgres.app 但它不起作用

PostgreSQL 中跨多个表的索引

当从 Heroku pg:pull 数据库时提示:role "root" does not exist.

Rails 5 db 迁移:如何修复 ActiveRecord::ConcurrentMigrationError