postgresql - 用于在 PostgreSQL 中对 JSONB 搜索结果进行排名的索引

标签 postgresql indexing full-text-search ranking jsonb

我目前正在优化 PostgreSQL jsonb 字段的搜索结果。我正在使用 Postgres 9.6。我的最终目标是搜索 jsonb 文档中的多个字段,并根据所有字段中的总点击率对结果进行排名。但我陷入困境,因为 ts_rank 函数不使用我的索引并极大地减慢了搜索速度。这是一个最小的例子:

CREATE TABLE book (
  id   BIGSERIAL NOT NULL,
  data JSONB     NOT NULL
);

CREATE INDEX book_title_idx
  ON book USING GIN (to_tsvector('english', book.data ->> 'title'));

INSERT INTO book (data)
VALUES (CAST('{"title": "Cats"}' AS JSONB));

当尝试搜索标题字段时,我使用以下查询:

EXPLAIN ANALYZE
SELECT *
FROM (
       SELECT
         id,
         data ->> 'title'              AS title,
         ts_rank(title_query, 'cat:*') AS score
       FROM
         book,
         to_tsvector('english', data ->> 'title') title_query
       WHERE title_query @@ to_tsquery('cat:*')
       ORDER BY score DESC) a
WHERE score > 0
ORDER BY score DESC;

在没有排名的情况下,对我的真实数据进行搜索需要 < 1 毫秒,而排名后大约需要 1800 毫秒。我搜索的领域越多,情况就会变得更糟。我需要排名只是为了让多个领域的点击更有值(value)。

最佳答案

您的查询给出了计划(在具有 500000 行的测试数据集上):

                                                                 QUERY PLAN                                                                  
---------------------------------------------------------------------------------------------------------------------------------------------
 Sort  (cost=216058.57..217308.57 rows=500001 width=63) (actual time=831.033..831.033 rows=1 loops=1)
   Sort Key: (ts_rank(title_query.title_query, '''cat'':*'::tsquery)) DESC
   Sort Method: quicksort  Memory: 25kB
   ->  Nested Loop  (cost=0.25..149927.55 rows=500001 width=63) (actual time=4.410..830.950 rows=1 loops=1)
         ->  Seq Scan on book  (cost=0.00..8677.01 rows=500001 width=31) (actual time=0.024..30.159 rows=500001 loops=1)
         ->  Function Scan on to_tsvector title_query  (cost=0.25..0.52 rows=1 width=32) (actual time=0.001..0.001 rows=0 loops=500001)
               Filter: ((ts_rank(title_query, '''cat'':*'::tsquery) > '0'::double precision) AND (title_query @@ to_tsquery('cat:*'::text)))
               Rows Removed by Filter: 1
 Planning time: 37.211 ms
 Execution time: 831.279 ms
(10 rows)

WHERE 子句中的别名 title_query 替换为索引定义中使用的表达式:

EXPLAIN ANALYZE
SELECT *
FROM (
       SELECT
         id,
         data ->> 'title'              AS title,
         ts_rank(title_query, 'cat:*') AS score
       FROM
         book,
         to_tsvector('english', data ->> 'title') title_query
       WHERE to_tsvector('english', data ->> 'title') @@ to_tsquery('cat:*')
       ORDER BY score DESC) a
WHERE score > 0
ORDER BY score DESC;

 Sort  (cost=9905.39..9930.39 rows=10000 width=63) (actual time=1.069..1.069 rows=1 loops=1)
   Sort Key: (ts_rank(title_query.title_query, '''cat'':*'::tsquery)) DESC
   Sort Method: quicksort  Memory: 25kB
   ->  Nested Loop  (cost=114.00..9241.00 rows=10000 width=63) (actual time=1.049..1.050 rows=1 loops=1)
         ->  Bitmap Heap Scan on book  (cost=113.75..8940.75 rows=10000 width=31) (actual time=0.052..0.052 rows=1 loops=1)
               Recheck Cond: (to_tsvector('english'::regconfig, (data ->> 'title'::text)) @@ to_tsquery('cat:*'::text))
               Heap Blocks: exact=1
               ->  Bitmap Index Scan on book_title_idx  (cost=0.00..111.25 rows=10000 width=0) (actual time=0.047..0.047 rows=1 loops=1)
                     Index Cond: (to_tsvector('english'::regconfig, (data ->> 'title'::text)) @@ to_tsquery('cat:*'::text))
         ->  Function Scan on to_tsvector title_query  (cost=0.25..0.27 rows=1 width=32) (actual time=0.994..0.994 rows=1 loops=1)
               Filter: (ts_rank(title_query, '''cat'':*'::tsquery) > '0'::double precision)
 Planning time: 0.639 ms
 Execution time: 1.120 ms
(13 rows)

关于postgresql - 用于在 PostgreSQL 中对 JSONB 搜索结果进行排名的索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41039869/

相关文章:

performance - 应该将 search_data tsvector 存储在同一张表还是外部表中?

r - R中矩阵的反向索引

php - 如何用 Doctrine 做全文检索?

postgresql - Spring MVC + Maven + JBoss : can't deploy (The application must supply JDBC connections)

postgresql - Azure Databrick 平台上的 pyspark 中的 Py4JJava 错误

sql - postgres index : single or multi column. only where or also in case

database - 为什么 Postgres 不为我的查询使用更好的索引?

sql-server - 你如何在sql server中实现多列的全文搜索?

sql - 如何为日期变量提供一个由 Postgresql 中的整数变量组成的间隔

postgresql - PostgreSQL 中的 "use database_name"命令