多个表的视图可以用于全文搜索吗?

dmr*_*r07 3 sql postgresql full-text-search

我很抱歉问这样一个菜鸟问题,但是关于视图的postgres 文档很少,我很难找到一个好的答案。

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

我担心使用视图可能无法很好地扩展,因为它将三个表合并为一个。这是一个合理的担忧吗?如果没有,我还能如何解决这个问题?

joa*_*olo 7

你的要求可以做到。举一个实际的例子(只有两个表),你可以:

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)) ;
Run Code Online (Sandbox Code Playgroud)

请参阅 PostgreSQL 文档。关于控制文本搜索的解释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') ;
Run Code Online (Sandbox Code Playgroud)

... 创建一个结合两个表中值的视图

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 ;
Run Code Online (Sandbox Code Playgroud)

我们搜索该视图:

SELECT 
    *
FROM
    search_items
WHERE
    plainto_tsquery('english', 'alice') @@ searchable_element
Run Code Online (Sandbox Code Playgroud)

...并获得以下响应(您应该主要忽略searchable_element)。您最感兴趣的是origin_tableand id

origin_table | 身份证 | searchable_element               
:----------- | -: | :--------------------------------
用户 | 1 | 'alic':1 '库珀':2              
主题 | 3 | 'alic':1 'essay':4 '仙境':3

有关plainto_tsquery函数的说明,请参阅解析查询,以及@@操作符


确保使用索引:

EXPLAIN ANALYZE
SELECT 
    *
FROM
    search_items
WHERE
    plainto_tsquery('english', 'alice') @@ searchable_element
Run Code Online (Sandbox Code Playgroud)
| 查询计划 |
| :------------------------------------------------- -------------------------------------------------- ------------------------------- |
| Append (cost=12.05..49.04 rows=12 width=68) (实际时间=0.017..0.031 rows=2 loops=1) |
| -> Bitmap Heap Scan on users (cost=12.05..24.52 rows=6 width=68) (实际时间=0.017..0.018 rows=1 loops=1) |
| 重新检查条件:('''alic'''::tsquery @@to_tsvector('english'::regconfig, username)) |
| 堆块:精确=1 |
| -> idx_users_username_full_text 上的位图索引扫描 (cost=0.00..12.05 rows=6 width=0) (actual time=0.005..0.005 rows=1 loops=1) |
| 索引条件:('''alic'''::tsquery @@to_tsvector('english'::regconfig, username)) |
| -> 主题上的位图堆扫描(成本=12.05..24.52 行=6 宽度=68)(实际时间=0.012..0.012 行=1 循环=1)|
| 重新检查条件:('''alic'''::tsquery @@to_tsvector('english'::regconfig, topic)) |
| 堆块:精确=1 |
| -> idx_topics_topic_full_text 上的位图索引扫描 (cost=0.00..12.05 rows=6 width=0) (actual time=0.002..0.002 rows=1 loops=1) |
| 索引条件:('''alic'''::tsquery @@to_tsvector('english'::regconfig, topic)) |
| 规划时间:0.098 ms |
| 执行时间:0.055 毫秒 |

真正使用了索引(请参阅Bitmap Index Scan on idx_topics_topic_full_textBitmap Index Scan on idx_users_username_full_text)。

您可以在dbfiddle此处检查所有内容


注意:'english'是选择用于索引和查询的文本搜索配置。为您的情况选择合适的一种。如果现有的不能满足您的需求,您可以创建自己的。