postgresql - PostgreSQL 中的 Edge NGram 搜索

标签 postgresql elasticsearch full-text-search pg-trgm

我需要为大量公司(超过 80,000,000 家)进行搜索时自动完成。公司名称应包含以这样的搜索查询开头的单词

+-------+----------------------------------+
| term  | results                          |
+-------+----------------------------------+ 
| gen   | general motors; general electric |
| geno  | genoptix; genomic health         |
| genom | genoma group; genomic health     |
+-------+----------------------------------+

pg_trgm模块和 GIN index实现类似的行为,但不解决我的问题。

例如,ElasticSearch 有特征 Edge NGram Tokenizer完全符合我的要求。

从文档:
The edge_ngram tokenizer first breaks the text down into words 
whenever it encounters one of a list of specified characters, 
then it emits N-grams of each word 
where the start of the N-gram is anchored to the beginning of the word.

Edge N-Grams are useful for search-as-you-type queries.

PostgreSQL中是否有类似的解决方案?

最佳答案

我创建了一个自定义标记器

CREATE OR REPLACE FUNCTION edge_gram_tsvector(text text) RETURNS tsvector AS
$BODY$
BEGIN
    RETURN (select array_to_tsvector((select array_agg(distinct substring(lexeme for len)) from unnest(to_tsvector(text)), generate_series(1,length(lexeme)) len)));
END;
$BODY$
IMMUTABLE
language plpgsql;

这个函数像这样创建所有边缘 ngram
postgres=# select edge_gram_tsvector('general electric');
                               edge_gram_tsvector
-----------------------------------------------------------------------------------------
 'e' 'el' 'ele' 'elec' 'elect' 'electr' 'g' 'ge' 'gen' 'gene' 'gener' 'genera' 'general'
(1 row)

然后我创建一个 GIN tsquery 的索引
create index on company using gin(edge_gram_tsvector(name));

搜索查询将如下所示
b2bdb_master=# select name from company where edge_gram_tsvector(name) @@ 'electric'::tsquery limit 3;
                    name
--------------------------------------------
 General electric
 Electriciantalk
 Galesburg Electric Industrial Supply
(3 rows)

解决方案的性能相当高
explain analyse select * from company where edge_gram_tsvector(name) @@ 'electric'::tsquery;


Bitmap Heap Scan on company  (cost=175.13..27450.31 rows=20752 width=2247) (actual time=0.224..1.019 rows=343 loops=1)
  Recheck Cond: (edge_gram_tsvector((name)::text) @@ '''electric'''::tsquery)
  Heap Blocks: exact=342
  ->  Bitmap Index Scan on company_edge_gram_tsvector_idx  (cost=0.00..169.94 rows=20752 width=0) (actual time=0.138..0.138 rows=343 loops=1)
        Index Cond: (edge_gram_tsvector((name)::text) @@ '''electric'''::tsquery)
Planning Time: 0.216 ms
Execution Time: 1.100 ms

关于postgresql - PostgreSQL 中的 Edge NGram 搜索,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56894979/

相关文章:

django - 如何使用来自 Postgres 的数据正确填充 Docker Django 图像?

elasticsearch - 如何获得Elasticsearch 5.6.3跨集群搜索?

c# - 如何使用NLog登录到Amazon ElasticSearch?

elasticsearch - Elasticsearch:间隔5年的date_histogram

MySQL全文关键字顺序?

c# - 如何在特定选定项目内的 TFS 源代码管理中搜索特定文件?

ruby-on-rails - database.yml 文件中的 Postgres 数据库用户名

postgresql - 如何使用 JPA 创建 PostgreSql 序列?

database - Perl 中的表游标

java - 检索每个文档 Neo4j Lucene 的分数,而不仅仅是顺序