Postgres FTS包含复合类型数组

时间:2012-08-13 14:11:11

标签: database postgresql full-text-search relational-database data-modeling

假设我有以下伪模式,其中1-many关系使用Postgres数组建模:

CREATE TYPE quotes AS
(
  text  CHARACTER VARYING,
  is_direct CHARACTER VARYING
);

CREATE TABLE posts
(
    body  CHARACTER VARYING,
    q     quotes[]
);
insert into posts(body,q) VALUES('ninjas rock',ARRAY[ ROW('I AGREE',True)::quotes, ROW('I DISAGREE',FALSE)::quotes ]);

我的第一个问题是:如何执行选择以从整个数组中过滤掉quote->text

这有效:

test=# select body, q[1].text from posts;
     body     |  text   
--------------+---------
 hassan rocks | I AGREE
(1 row)

但这不是(注意正在检索整个复合类型):

test=# select body, (q).text from posts;
     body     |                      text                       
--------------+-------------------------------------------------
 hassan rocks | {"(\"I AGREE\",true)","(\"I DISAGREE\",false)"}
(1 row)

为了解决我真正的问题,我将如何创建一个杜松子酒或gist(带或不带to_tsvector)索引,其中包括帖子主体和所有帖子的文本报价文字?我不希望使用索引的额外列方法作为触发器make me sad

目前我的架构将帖子和引用表示为1-many关系,但我认为如果postgres支持我想要做的事情,它会大大简化事情。

3 个答案:

答案 0 :(得分:1)

您可以创建一个函数来获取数组部分并以SETOF quotes形式返回并调用SELECT上的函数:

CREATE OR REPLACE FUNCTION getquote(posts)
RETURNS SETOF quotes
LANGUAGE sql
AS $getquote$
SELECT $1.q[i].text, $1.q[i].is_direct
FROM generate_series(array_lower($1.q, 1), array_upper($1.q, 1)) AS i
$getquote$

SELECT将是:

SELECT body, (getquote(p)).* FROM posts p;

您可以创建一个视图以简化操作,还可以对函数本身执行过滤任务。

答案 1 :(得分:0)

以下代码将“过滤”您的数组。 select (unnest(q)).text from posts;unnest将数组转换为行。请注意,unnest包含在括号中,这很重要,因为如果没有括号,您将无法选择特定字段 - 即unnest(q).text无效,而unnest(q)本身会导致包含字符串形式的复合的行。

将post txt和quote txt作为单个文本单元处理的代码如下:

SELECT to_tsvector(q.b_txt || q.q_t) FROM
(
    SELECT b_txt,string_agg(p.q_txt,' ') as q_t 
    FROM ( SELECT 1 AS id,body b_txt, (unnest(q)).text AS q_txt FROM posts) AS p 
    GROUP BY p.id,b_txt
) AS q;

这可能需要适应UDF以便在gingist索引中使用。

答案 2 :(得分:0)

我可以回答第1部分。

为每个正文/引号返回一行:

SELECT body, q_unnest.text AS quote
FROM posts, UNNEST(q) AS q_unnest

使用引号文本数组为每个帖子返回一行:

SELECT posts.body, array_agg(q_unnest.text) AS quotes
FROM posts, UNNEST(q) AS q_unnest
GROUP BY posts.body

为每个帖子返回一行,引号文本用分隔符分隔:

SELECT posts.body, array_to_string(array_agg(q_unnest.text), '|') AS quotes
FROM posts, UNNEST(q) AS q_unnest
GROUP BY posts.body

我设置了SQLFiddle,因此您可以亲自尝试。

至于第2部分和索引复合类型数组,我认为它需要一个“运算符类”,根据Postgres扩展指南here。这对我来说似乎很麻烦,我还没有找到如何做到这一点的例子。