【问题标题】:Indexing an array for full text search索引数组以进行全文搜索
【发布时间】:2015-09-21 12:43:57
【问题描述】:

我正在尝试索引文档以便在其标签数组上进行搜索。

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

如何索引数组以进行全文搜索?

【问题讨论】:

  • 看起来我找到了duplicate,虽然它没有说明函数是如何制作的。

标签: postgresql indexing full-text-search


【解决方案1】:

在我最初的回答中,我建议对文本进行简单的转换: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

如果您有时只想搜索 tagsnotes,请考虑使用多列索引:

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,而使用三元索引的相似性搜索会更合适:

在这种确切情况下不相关,但在使用 citext 时,请考虑:

【讨论】:

  • 实际上,我刚刚有机会尝试这个,看起来 PG 将 ::text 解释为不是不可变的。 ERROR: functions in index expression must be marked IMMUTABLE : CREATE INDEX doc_search_idx ON documents USING gin( to_tsvector('english', coalesce(tag_cache::text, '')) )。你试过了吗?
【解决方案2】:

这是我的幼稚解决方案,将其包装起来并称其为不可变,正如怀疑的那样。

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

【讨论】:

    猜你喜欢
    • 2014-10-15
    • 1970-01-01
    • 2014-06-22
    • 2018-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-29
    • 2021-04-08
    相关资源
    最近更新 更多