2017-07-15 39 views
1

我很抱歉问这样一个noob问题,但postgres documentation的意见是稀疏的,我很难找到一个很好的答案。多个表格视图可以用于全文搜索吗?

我试图在Postgres上实现全文搜索三个表。具体来说,用户的搜索查询将返回匹配1)其他用户名,2)消息,3)主题。

我担心为此使用视图可能无法很好地扩展,因为它将三个表合并为一个。这是一个合理的担忧吗?如果不是,我还可以怎样处理这个问题?

+0

你可以做这样的事情。确保原始表上所需的列(或表达式)具有正确的索引。另外,测试查询视图时产生的执行计划,以确保它们显示索引使用情况。否则,它会工作,但真的很慢。或者,你可以有一个*物化视图*,并直接在它上面有索引;并确保足够频繁地更新它。 – joanolo

回答

2

你可以做什么。为了有一个实际的例子(只有两个表),你可以有:

CREATE TABLE users 
(
    user_id SERIAL PRIMARY KEY, 
    username text 
) ; 

-- Index to find usernames 
CREATE INDEX idx_users_username_full_text 
    ON users 
    USING GIN (to_tsvector('english', username)) ;   

CREATE TABLE topics 
(
    topic_id SERIAL PRIMARY KEY, 
    topic text 
) ; 

-- Index to find topics 
CREATE INDEX idx_topics_topic_full_text 
    ON topics 
    USING GIN (to_tsvector('english', topic)) ; 

见PostgreSQL的文档。请致电Controlling Text Search获取to_tsvector的解释。

...填充表

INSERT INTO users 
    (username) 
VALUES 
    ('Alice Cooper'), 
    ('Boo Geldorf'), 
    ('Carol Burnet'), 
    ('Daniel Dafoe') ; 

INSERT INTO topics 
    (topic) 
VALUES 
    ('Full text search'), 
    ('Fear of void'), 
    ('Alice in Wonderland essays') ; 

...创建两个表

CREATE VIEW search_items AS 
SELECT 
    text 'users' AS origin_table, user_id AS id, to_tsvector('english', username) AS searchable_element 
FROM 
    users 
UNION ALL 
SELECT 
    text 'topics' AS origin_table, topic_id AS id, to_tsvector('english', topic) AS searchable_item 
FROM 
    topics ; 

我们寻找这一观点结合值的观点:

SELECT 
    * 
FROM 
    search_items 
WHERE 
    plainto_tsquery('english', 'alice') @@ searchable_element 

..并获得以下回复(你应该大多忽略searchable_element)。你最感兴趣的是origin_tableid

 
origin_table | id | searchable_element    
:----------- | -: | :-------------------------------- 
users  | 1 | 'alic':1 'cooper':2    
topics  | 3 | 'alic':1 'essay':4 'wonderland':3 

见解析查询的plainto_tsquery功能的说明,也@@ operator


要确保使用索引:

EXPLAIN ANALYZE 
SELECT 
    * 
FROM 
    search_items 
WHERE 
    plainto_tsquery('english', 'alice') @@ searchable_element 
 
| QUERY PLAN                                 | 
| :----------------------------------------------------------------------------------------------------------------------------------------- | 
| Append (cost=12.05..49.04 rows=12 width=68) (actual time=0.017..0.031 rows=2 loops=1)              | 
| -> Bitmap Heap Scan on users (cost=12.05..24.52 rows=6 width=68) (actual time=0.017..0.018 rows=1 loops=1)        | 
|   Recheck Cond: ('''alic'''::tsquery @@ to_tsvector('english'::regconfig, username))             | 
|   Heap Blocks: exact=1                            | 
|   -> Bitmap Index Scan on idx_users_username_full_text (cost=0.00..12.05 rows=6 width=0) (actual time=0.005..0.005 rows=1 loops=1) | 
|    Index Cond: ('''alic'''::tsquery @@ to_tsvector('english'::regconfig, username))            | 
| -> Bitmap Heap Scan on topics (cost=12.05..24.52 rows=6 width=68) (actual time=0.012..0.012 rows=1 loops=1)       | 
|   Recheck Cond: ('''alic'''::tsquery @@ to_tsvector('english'::regconfig, topic))             | 
|   Heap Blocks: exact=1                            | 
|   -> Bitmap Index Scan on idx_topics_topic_full_text (cost=0.00..12.05 rows=6 width=0) (actual time=0.002..0.002 rows=1 loops=1) | 
|    Index Cond: ('''alic'''::tsquery @@ to_tsvector('english'::regconfig, topic))            | 
| Planning time: 0.098 ms                             | 
| Execution time: 0.055 ms                             | 

索引是真正使用(见Bitmap Index Scan on idx_topics_topic_full_textBitmap Index Scan on idx_users_username_full_text)。

您可以在检查一切dbfiddle here


注:'english'是选择索引和查询的text search configuration。为你的情况选择一个合适的。如果现有的不满足您的需求,您可以创建自己的。

+0

谢谢,这真的很有帮助。速度虽然是一个问题。您是否有过大量记录(即2M +)的表演经验?在物化视图的情况下,由于其更新的局限性,可以说使用搜索不切实际吗? – dmr07

+0

看来最好的解决方案是创建一个表并触发从其他表中提取的派生内容。 – dmr07

+0

我有100.000s的经验。搜索速度很快。如果你有100或1000的结果,问题通常是*排序*(使用'ts_rank'),因为该函数是计算密集型的。如果你采用触发方式,我建议你只在表中存储'to_tsvector'结果并对其进行索引。我不认为这会更快,除非你处理5个以上的表格。 – joanolo

相关问题