Jon*_*ard 6 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, '')))
)
Run Code Online (Sandbox Code Playgroud)
哪里tags
是(ci)text[]
.但是,PG会拒绝索引,array_to_string
因为它并不总是不可变的.
PG::InvalidObjectDefinition: ERROR: functions in index expression must be marked IMMUTABLE
Run Code Online (Sandbox Code Playgroud)
我已经尝试创建一个自制的array_to_string
不可变函数,但我觉得我喜欢玩火,因为我不知道我在做什么.有什么办法不重新实施吗?
看起来我可以重新打包相同的功能并将其标记为不可变,但看起来这样做有风险.
如何索引数组以进行全文搜索?
在我最初的回答中,我提出了一个简单的演员文字:tags::text
.但是,虽然定义了大多数来自基本类型的文本转换IMMUTABLE
,但对于数组类型却不是这种情况.显然是因为(引用Tom Lane的帖子中的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';
Run Code Online (Sandbox Code Playgroud)
这更快.
或者(使用array_to_string()
没有花括号的结果):
CREATE OR REPLACE FUNCTION f_ciarr2text(citext[])
RETURNS text LANGUAGE sql IMMUTABLE AS $$SELECT array_to_string($1, ',')$$;
Run Code Online (Sandbox Code Playgroud)
这是更正确的一点.
然后:
CREATE INDEX doc_search_idx ON documents USING gin (
to_tsvector('english', COALESCE(f_ciarr2text(tags), '')
|| ' ' || COALESCE(notes,'')));
Run Code Online (Sandbox Code Playgroud)
我并没有使用多态类型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,''));
Run Code Online (Sandbox Code Playgroud)
您所指的风险主要适用于时间函数,这些函数在引用的问题中使用.如果timestamptz
涉及时区(或仅涉及类型),结果实际上不是不可变的.我们不在乎这里的不变性.我们的功能实际上是 IMMUTABLE
.Postgres无法从它使用的一般实现中分辨出来.
通常人们认为他们需要文本搜索,而使用trigram索引进行相似性搜索会更合适:
在这个确切的情况下不相关,但在使用时citext
,请考虑以下事项:
这是我天真的解决方案,将其包装起来并称其为不可变的,正如所怀疑的那样。
CREATE FUNCTION immutable_array_to_string(arr ANYARRAY, sep TEXT)
RETURNS text
AS $$
SELECT array_to_string(arr, sep);
$$
LANGUAGE SQL
IMMUTABLE
;
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2037 次 |
最近记录: |