Postgres 全文搜索 Jsonb 数组列不显示第一行

Postgres Full Text Search Jsonb Array column does not show first row

当查找 table 中的第一行时,Pgsql 无法对包含数组的 jsonb 列执行索引全文搜索。

Table 只不过是 IdFoo,即 jsonb 列。

情况是我有一个空数据库,在 make_tsvector 函数上具有预定义的杜松子酒索引 repro_fts_idxmake_tsvector 从给定的 jsonb 列创建 tsvector

当我向 table 添加新项目时,我希望它以 tsvector 的形式出现在 make_tsvector 函数中。在那。 另外,我希望如果我对它进行 运行 全文搜索查询,它就会出现在搜索结果中。但是,情况并非如此,因为它 returns 专门为第一行留空。它根本不考虑它。 如果我再添加一行完全相同的行,系统可以使用相同的查询找到它。

这里有一个小的复现案例:


-- drop table cp."Repro" cascade

CREATE TABLE cp."Repro" (
    "Id" serial NOT NULL,
    "Foo" jsonb NULL
);

CREATE OR REPLACE FUNCTION cp.make_tsvector(in_t cp."Repro")
 RETURNS tsvector
 LANGUAGE plpgsql
 IMMUTABLE
AS $function$ begin    
                        return to_tsvector(jsonb_agg(x.prop))
                        from (SELECT CONCAT( jsonb_array_elements(in_t."Foo") ->> 'Name', ' ', jsonb_array_elements(in_t."Foo") ->> 'Address' ) as prop from cp."Repro" f) as x;
                        END;
                        $function$
;


CREATE INDEX repro_fts_idx ON cp."Repro" USING gin (cp.make_tsvector(cp."Repro".*)) WITH (fastupdate=off, gin_pending_list_limit='64');


INSERT INTO cp."Repro"
("Foo")
VALUES('[{"Name": "Sup", "Address": "Adress", "IsCurrent": true}]');

-- just in case it's the indexing issue
-- REINDEX INDEX cp.repro_fts_idx;

select * from cp."Repro"

select cp.make_tsvector(x) from cp."Repro" x

select * from ts_stat('select cp.make_tsvector(x) from cp."Repro" x')

-- explain analyze
SELECT *
 FROM "cp"."Repro" x where cp.make_tsvector(x) @@ 'sup:*'::tsquery


 INSERT INTO cp."Repro"
("Foo")
VALUES('[{"Name": "Sup", "Address": "Adress", "IsCurrent": true}]');


-- explain analyze
SELECT *
 FROM "cp"."Repro" x where cp.make_tsvector(x) @@ 'sup:*'::tsquery

UPD:答案

该函数是错误的,因为它引用了输入行和整个 table。 正确的函数是:

CREATE OR REPLACE FUNCTION cp.make_tsvector(in_t cp."Repro")
 RETURNS tsvector
 LANGUAGE plpgsql
 IMMUTABLE
AS $function$
                    BEGIN
                        return string_agg(lower(regexp_replace(coalesce(x::text, ''), '[|&\*:()'']+', ' ', 'g')), ' ')::tsvector FROM (SELECT CONCAT( jsonb_array_elements(in_t."Foo") ->> 'Name', ' ', jsonb_array_elements(in_t."Foo") ->> 'Address' ) AS x) AS x;
                    END;
                $function$
;

肯定是你的函数有问题。它不应同时引用其输入记录 in_t 和整个基础 table、cp."Repro"。 (而且因为它指的是 cp."Repro",所以它并不是真正的 immutable。当你对系统撒谎说函数的不可变性时,就会发生不好的事情。)

由于在插入第一行时 table 为空,因此从函数内部的空 table 中进行选择不会给出任何结果,从而产生要索引的 NULL 结果。这可以通过以下方式看到:

truncate cp."Repro" ;
select cp.make_tsvector(row(1,'[{"Name": "Sup", "Address": "Adress", "IsCurrent": true}]'));
 make_tsvector 
---------------
 (null)

就算你的make_tsvector没坏,好像也没用。它基本上只是 to_tsvector 的一个失败的重新实现。它应该完成什么?