【问题标题】:Postgres FTS with array of composite types具有复合类型数组的 Postgres FTS
【发布时间】:2012-08-09 18:52:30
【问题描述】:

假设我有以下伪模式,其中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)

为了解决我真正的问题,我将如何创建一个包含帖子正文和所有引用的文本的 gin 或 gist(有或没有 to_tsvector)索引文本 ?我不喜欢将索引的额外列方法用作触发器make me sad

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

【问题讨论】:

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


    【解决方案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;
    

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

    【讨论】:

      【解决方案2】:

      我可以回答第 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。这对我来说似乎很麻烦,我还没有找到如何做到这一点的示例。

      【讨论】:

        【解决方案3】:

        以下代码将“过滤”您的数组。 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 索引。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-06-02
          • 1970-01-01
          • 2015-03-26
          • 1970-01-01
          • 1970-01-01
          • 2017-11-25
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多