bet*_*max 10 sql postgresql full-text-search
在我的PostgreSQL 9.3数据库中,我有一个名为的表articles.它看起来像这样:
+------------+--------------------------------------------------------------+
| Name | Information |
+------------+--------------------------------------------------------------+
| id | Auto incrememnt integer ID |
| title | text |
| category | character varying(255) with index |
| keywords | String with title and extra words used for indexing |
| tsv | Trigger updates w/ tsvector_update_trigger based on keywords |
+------------+--------------------------------------------------------------+
Run Code Online (Sandbox Code Playgroud)
表格中有更多列,但我认为它们对这个问题并不重要.该表的总大小为94GB,大约29M行.
我正在尝试对23M article行的子集上的关键字搜索运行查询.为此,我使用以下查询:
SELECT title, id FROM articles, plainto_tsquery('dog') AS q
WHERE (tsv @@ q) AND category = 'animal'
ORDER BY ts_rank_cd(tsv, q) DESC LIMIT 5
Run Code Online (Sandbox Code Playgroud)
这样做的问题在于,它可以先显示ts_rank_cd每个结果,然后才能对它们进行排序,因此这个查询非常慢,大约需要2-3分钟.我已经阅读了很多尝试找到解决方案,并建议我将搜索查询包装在另一个查询中,以便排名仅应用于找到的结果,如下所示:
SELECT * FROM (
SELECT title, id, tsv FROM articles, plainto_tsquery('dog') AS q
WHERE (tsv @@ q) AND category = 'animal'
) AS t1
ORDER BY ts_rank_cd(t1.tsv, plainto_tsquery('dog')) DESC LIMIT 5;
Run Code Online (Sandbox Code Playgroud)
但是,因为查询太短,所以子集中有450K结果.所以它仍然需要很长时间,它可能会更快一些,但我需要这个基本上是即时的.
问题:我有什么办法可以在PostgreSQL中保留这个搜索功能吗?
将这个逻辑保存在数据库中很好,这意味着我不需要任何额外的服务器或配置Solr或Elasticsearch之类的东西.例如,增加数据库实例容量会有所帮助吗?或者,与将此逻辑转移到专用的Elasticsearch实例相比,成本效率是否有意义.
第一个查询的EXPLAIN响应如下:
Limit (cost=567539.41..567539.42 rows=5 width=465)
-> Sort (cost=567539.41..567853.33 rows=125568 width=465)
Sort Key: (ts_rank_cd(articles.tsv, q.q))
-> Nested Loop (cost=1769.27..565453.77 rows=125568 width=465)
-> Function Scan on plainto_tsquery q (cost=0.00..0.01 rows=1 width=32)
-> Bitmap Heap Scan on articles (cost=1769.27..563884.17 rows=125567 width=433)
Recheck Cond: (tsv @@ q.q)
Filter: ((category)::text = 'animal'::text)
-> Bitmap Index Scan on article_search_idx (cost=0.00..1737.87 rows=163983 width=0)
Index Cond: (tsv @@ q.q)
Run Code Online (Sandbox Code Playgroud)
对于第二个查询:
Aggregate (cost=565453.77..565453.78 rows=1 width=0)
-> Nested Loop (cost=1769.27..565139.85 rows=125568 width=0)
-> Function Scan on plainto_tsquery q (cost=0.00..0.01 rows=1 width=32)
-> Bitmap Heap Scan on articles (cost=1769.27..563884.17 rows=125567 width=351)
Recheck Cond: (tsv @@ q.q)
Filter: ((category)::text = 'animal'::text)
-> Bitmap Index Scan on article_search_idx (cost=0.00..1737.87 rows=163983 width=0)
Index Cond: (tsv @@ q.q)
Run Code Online (Sandbox Code Playgroud)
小智 0
也许...如果您使用 HASH 索引,您的类别子句可能会得到优化,您对 tsv 的查询可能会使用 GIN 索引进行优化,如果您的类别是一个(相当小的)有限集,也许您应该使用枚举类别而不是变化(或至少不使用varchar)。(我想知道重量对你的情况是否真的很重要)。
SELECT *
FROM (SELECT *,ts_rank_cd(sub.tsv, plainto_tsquery('dog')) AS rank
FROM (SELECT title,id,tsv FROM articles WHERE category = 'animal')) AS sub,
plainto_tsquery('dog') AS q
WHERE (tsv @@ q)
ORDER BY rank DESC LIMIT 5
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1705 次 |
| 最近记录: |