2017-07-15 70 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

相關問題