gpt4 book ai didi

arrays - 用于在 PostgreSQL 中搜索嵌套 JSONB 数组元素的索引

转载 作者:行者123 更新时间:2023-11-29 14:02:57 24 4
gpt4 key购买 nike

我是 postgres 的新手,目前使用的是 9.6。当尝试使用它的 jsonb 文档在 postgres 中实现全文搜索时,我注意到嵌套数组的搜索结果很慢。我使用了“解释”命令,但它没有使用任何索引。为简单起见,我创建了一个表来进行调查:

CREATE TABLE book (
id BIGSERIAL NOT NULL,
data JSONB NOT NULL
);

我的可用索引:

CREATE INDEX book_author_idx
ON book USING GIN (to_tsvector('english', book.data ->> 'author'));
CREATE INDEX book_author_name_idx
ON book USING GIN (to_tsvector('english', book.data -> 'author' ->> 'name'));

还有一些数据来填充文档:

INSERT INTO book (data)
VALUES (CAST('{"author": [{"id": 0, "name": "Cats"}, ' ||
' {"id": 1, "name": "Dogs"}]}' AS JSONB));

我可以使用以下查询来搜索书籍元素,但它不使用任何索引。我的 120k 产品的实际数据大约需要 1200 毫秒,而其他带有索引的搜索需要 0.2 毫秒。

EXPLAIN ANALYZE
SELECT
id,
data ->> 'author' AS author
FROM book, jsonb_array_elements(data #> '{author}') author_array
WHERE to_tsvector('english', author_array ->> 'name') @@ to_tsquery('cat');

相比之下,下一个查询使用 book_author_name_idx 但由于数组结构没有找到任何内容。

EXPLAIN ANALYZE
SELECT
id,
data ->> 'author' AS author
FROM book
WHERE to_tsvector('english', data -> 'author' ->> 'name') @@ to_tsquery('cat');

如何调整我的查询以使用语言索引?我知道,我可以为作者创建一个新表并仅引用 ID,但我宁愿将所有数据保存在一个表中以提高性能。

最佳答案

根据 posz comments 的提示,我找到了解决方案。因为'||'函数不能按我需要的方式工作,我为 tsvectors 使用了自定义 concat 函数。我使用了 github 上 glittershark 的代码并将 to_tsvector 从“默认”更改为“英语”以满足我的需要。

CREATE OR REPLACE FUNCTION concat_tsvectors(tsv1 TSVECTOR, tsv2 TSVECTOR)
RETURNS TSVECTOR AS $$
BEGIN
RETURN coalesce(tsv1, to_tsvector('english', ''))
|| coalesce(tsv2, to_tsvector('english', ''));
END;
$$ LANGUAGE plpgsql;

CREATE AGGREGATE tsvector_agg (
BASETYPE = TSVECTOR,
SFUNC = concat_tsvectors,
STYPE = TSVECTOR,
INITCOND = ''
);

这是我写的自定义函数。输入是 JSONB 形式的数据,输出是具有聚合作者姓名的 tsvector。

CREATE OR REPLACE FUNCTION author_function(
IN data JSONB,
OUT resultNames TSVECTOR
)
RETURNS TSVECTOR AS $$
DECLARE
authorRecords RECORD;
combinedAuthors JSONB [];
singleAuthor JSONB;
BEGIN
FOR authorRecords IN (SELECT value
FROM jsonb_array_elements(data #> '{author}'))
LOOP
combinedAuthors := combinedAuthors || authorRecords.value;
END LOOP;
FOREACH singleAuthor IN ARRAY coalesce(combinedAuthors, '{}')
LOOP
resultNames := concat_tsvectors(resultNames, to_tsvector('english', singleAuthor ->> 'name'));
END LOOP;
END; $$
LANGUAGE plpgsql
IMMUTABLE;

然后我为我的书籍对象设置了一个索引。

CREATE INDEX book_author_function_idx
ON book USING GIN (author_function(book.data));

作者姓名已经通过 to_tsvector('english', singleAuthor) 函数,所以我可以像这样查询它们:

EXPLAIN ANALYSE
SELECT
id,
data ->> 'author' AS author
FROM book
WHERE author_function(book.data) @@ to_tsquery('cat');

因此,对我的实际数据的查询从 1100-1200 毫秒减少到 ~0.5 毫秒。我不确定这是否是最佳解决方案,所以如果您有更好的建议,请告诉我。

关于arrays - 用于在 PostgreSQL 中搜索嵌套 JSONB 数组元素的索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40848903/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com