索引数组以进行全文搜索

时间:2015-07-03 16:09:11

标签: postgresql indexing full-text-search

我正在尝试索引可在其标记数组上搜索的文档。

CREATE INDEX doc_search_idx ON documents
      USING gin( 
    to_tsvector('english', array_to_string(tags, ' ')) ||
    to_tsvector('english', coalesce(notes, '')))
)

tags(ci)text[]的位置。但是,PG将拒绝对array_to_string进行索引,因为它is not always immutable

PG::InvalidObjectDefinition: ERROR:  functions in index expression must be marked IMMUTABLE

我尝试过创建一个自制的array_to_string不可变函数,但我觉得我喜欢玩火,因为我不知道自己在做什么。有什么方法不重新实现它?

看起来我可以重新打包相同的函数并将其标记为不可变,但在执行此操作时看起来像there are risks

如何为全文搜索索引数组?

2 个答案:

答案 0 :(得分:8)

在我最初的回答中,我提出了一个简单的演员文字:tags::text。但是,虽然大多数基于类型的文本转换都是IMMUTABLE定义的,但数组类型不是这种情况。显然是因为(quoting Tom Lane in a post to pgsql-general):

  

因为它是通过array_out / array_in实现的,而不是更多   直接方法,那些标记稳定,因为它们可能   调用非不可变元素I / O函数

大胆强调我的。

我们可以与之合作。一般情况不能标记为IMMUTABLE。但对于手头的情况(演员citext[]text[]text),我们可以安全地承担不变性。创建一个包装函数的简单IMMUTABLE SQL函数。然而,我的简单解决方案的吸引力现在大部分消失了。您也可以将array_to_string()(就像您已经考虑过的那样)包装起来,以适用类似的考虑因素。

对于citext[](如果需要,为text[]创建单独的函数):

(基于普通演员到text):

CREATE OR REPLACE FUNCTION f_ciarr2text(citext[]) 
  RETURNS text LANGUAGE sql IMMUTABLE AS 'SELECT $1::text';

这更快。
或者(使用array_to_string()获得没有花括号的结果):

CREATE OR REPLACE FUNCTION f_ciarr2text(citext[]) 
  RETURNS text LANGUAGE sql IMMUTABLE AS $$SELECT array_to_string($1, ',')$$;

这更正确一点 然后:

CREATE INDEX doc_search_idx ON documents USING gin (
   to_tsvector('english', COALESCE(f_ciarr2text(tags), '')
                || ' ' || COALESCE(notes,'')));

使用类似in your answer的多态类型ANYARRAY,因为我知道text[]citext[]是安全的,但我可以'保证所有其他数组类型。

在Postgres 9.4中测试并为我工作。

我在两个字符串之间添加了一个空格,以避免在连接字符串中出现误报。有example in the manual

如果您有时只想搜索tags或仅搜索notes,请考虑使用多列索引:

CREATE INDEX doc_search_idx ON documents USING gin (
             to_tsvector('english', COALESCE(f_ciarr2text(tags), '')
          ,  to_tsvector('english', COALESCE(notes,''));

您所指的风险主要适用于referenced question中使用的时间函数。如果涉及时区(或只是类型timestamptz),结果实际上不是不可变的。我们不在乎这里的不变性。我们的功能实际上 IMMUTABLE。 Postgres无法从它使用的一般实现中分辨出来。

相关

通常人们认为他们需要text search,而使用trigram索引进行相似性搜索会更合适:

在这种情况下不相关,但在使用citext时,请考虑以下事项:

答案 1 :(得分:1)

这是我天真的解决方案,包装它并将其称为不可变的,如怀疑的那样。

  CREATE FUNCTION immutable_array_to_string(arr ANYARRAY, sep TEXT)
    RETURNS text
    AS $$
      SELECT array_to_string(arr, sep);
    $$
    LANGUAGE SQL
    IMMUTABLE
  ;