索引数组以进行全文搜索

问题描述 投票:0回答:3

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

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
,因为它并不总是不可变的

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

我尝试过创建一个自制的

array_to_string
不可变函数,但我感觉就像在玩火,因为我不知道自己在做什么。有什么办法不重新实现它吗?

看起来我可以重新打包相同的函数并将其标记为不可变,但看起来这样做有风险

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

postgresql indexing full-text-search
3个回答
14
投票

在我最初的回答中,我建议将纯文本转换为文本:

tags::text
。然而,虽然大多数从基本类型到文本的转换都被定义为
IMMUTABLE
,但数组类型的情况并非如此。显然是因为(在 pgsql-general 的帖子中引用 Tom Lane ):

因为它是通过 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,'')));
我确实

没有使用多态类型ANYARRAY

,就像你的答案中的
一样,因为我知道text[]
citext[]
是安全的,但我不能保证
所有
其他数组类型。 在 Postgres 9.4 中测试并且对我有用。

我在两个字符串之间添加了一个空格,以避免连接字符串之间出现误报匹配。手册中有一个

示例

如果您有时只想搜索

tags

或只是

notes
,请考虑使用多列索引:
CREATE INDEX doc_search_idx ON documents USING gin (
             to_tsvector('english', COALESCE(f_ciarr2text(tags), '')
          ,  to_tsvector('english', COALESCE(notes,''));

您所指的风险

主要适用于时间函数,这些函数在参考问题中使用。如果涉及时区(或仅类型timestamptz),结果实际上并不是一成不变的。我们不会在这里对不变性撒谎。我们的功能是

实际上
IMMUTABLE。 Postgres 只是无法从它使用的一般实现中看出。
相关

人们通常认为他们需要

文本搜索

,而使用三元组索引的相似性搜索会更合适:

    PostgreSQL LIKE 查询性能变化
  • 在这种情况下不相关,但在使用
citext

时,请考虑这一点:


    未使用数据类型为 citext 的列上的索引

3
投票

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



0
投票

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

https://www.postgresql.org/docs/current/functions-textsearch.html

© www.soinside.com 2019 - 2024. All rights reserved.