2017-07-15 8 views
1

こんな質問には申し訳なく思っていますが、postgres documentationの意見はまばらです。フルテキスト検索に複数のテーブルのビューを使用できますか?

私は3つのテーブルのPostgresで全文検索を実装しようとしています。具体的には、ユーザの検索クエリは、一致する1)他のユーザ名、2)メッセージ、3)トピックを返す。

ビューを使用すると、3つのテーブルが1つにまとめられているので、スケールをうまく調整できないことが懸念されます。これは正当な懸念ですか?もしそうでなければ、私はこれにどのように接近するのでしょうか?

+0

このようなことができます。元の表の必要な列(または式)に正しい索引があることを確認します。また、ビューをクエリするときに生成された実行計画をテストし、インデックスの使用状況を確認します。それ以外の場合は動作しますが、実際は非常にゆっくりです。あるいは、*マテリアライズド・ビュー*を持ち、その上に直接索引を付けることもできます。頻繁に更新するようにしてください。 – joanolo

答えて

2

お願いしたことができます。具体的な例(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 Searchto_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


NOTEにすべてを確認することができます。'english'は、インデックスとクエリに選ばれたtext search configurationです。あなたのケースに適したものを選んでください。既存のものがあなたのニーズを満たしていない場合は、自分で作成することができます。

+0

ありがとう、これは本当に役に立ちます。スピードは懸念です。多数のレコード(2M +)を含むパフォーマンスの経験はありますか?マテリアライズド・ビューの場合は、更新に制限があるため、検索に使用することは現実的ではないと言っても過言ではありません。 – dmr07

+0

最良の解決策は、テーブルを作成し、他のテーブルから引き出されたその派生コンテンツをトリガすることです。 – dmr07

+0

私は100.000sの範囲で経験があります。検索は高速です。この問題は、100秒または1000秒の結果がある場合、通常は*ソート*( 'ts_rank'を使用)になります。なぜならその関数は計算集約的なためです。あなたがトリガの方法で行くなら、私はあなたがそのテーブルに 'to_tsvector'結果だけを格納し、それをインデックスすることをお勧めします。あなたが5つ以上のテーブルを扱わない限り、それはずっと速くなるとは思わない。 – joanolo

関連する問題