索引 jsonb 数据以进行模式匹配搜索

Indexing jsonb data for pattern matching searches

这是以下内容的后续:

我有一个table如下

CREATE TABLE "PreStage".transaction (
  transaction_id serial NOT NULL,
  transaction jsonb
  CONSTRAINT pk_transaction PRIMARY KEY (transaction_id)
);

我的交易jsonb栏的内容是这样的

{"ADDR": "abcd", "CITY": "abcd", "PROV": "",
 "ADDR2": "",
 "ADDR3": "","CNSNT": "Research-NA", "CNTRY": "NL", "EMAIL": "@.com",
             "PHONE": "12345", "HCO_NM": "HELLO", "UNQ_ID": "", 
             "PSTL_CD": "1234", "HCP_SR_NM": "", "HCP_FST_NM": "",
             "HCP_MID_NM": ""}

我需要像这样的搜索查询:

SELECT transaction AS data FROM   "PreStage".transaction
WHERE  transaction->>'HCP_FST_NM' ILIKE '%neer%';

但我需要让我的用户灵活地即时搜索任何 key/value。

上一个问题的答案建议创建索引为:

CREATE INDEX idxgin ON "PreStage".transaction
USING gin ((transaction->>'HCP_FST_NM') gin_trgm_ops);

这行得通,但我也想索引其他键。因此正在尝试类似的东西:

CREATE INDEX idxgin ON "PreStage".transaction USING gin
((transaction->>'HCP_FST_NM'),(transaction->>'HCP_LST_NM') gin_trgm_ops) 

这是行不通的。这里最好的索引方法是什么,或者我必须为每个键创建一个单独的索引,在这种情况下,如果将新的 key/value 对添加到数据中,该方法将不是通用的。

语法错误撇开,
一些 流行键(包含在许多行和/或经常搜索)加更多稀有键(包含在几行中和/或很少搜索,新键可能会动态弹出)我建议这样组合:

流行键的三字母索引

您似乎不会经常在一次搜索中组合多个键,并且具有许多键的单个索引会变得非常大和缓慢。所以我会为每个流行的键创建一个单独的索引。使其成为大多数行中未包含的键的部分索引:

CREATE INDEX trans_idxgin_HCP_FST_NM ON transaction  -- contained in most rows
USING gin ((transaction->>'HCP_FST_NM') gin_trgm_ops);

CREATE INDEX trans_idxgin_ADDR ON transaction  -- not in most rows
USING gin ((transaction->>'ADDR') gin_trgm_ops)
WHERE transaction ? 'ADDR';

等就像我之前的回答中详述的那样:

基本jsonb GIN索引

如果您有许多不同的密钥和/或动态添加新密钥,您可以用基本(默认)jsonb_ops GIN 索引覆盖其余部分:

CREATE INDEX trans_idxgin ON "PreStage".transaction USING gin (transaction);

除其他外,这还支持搜索 keys。但是您不能将它用于值的模式匹配。

  • What's the proper index for querying structures in arrays in Postgres jsonb?

查询

合并寻址两个索引的谓词:

SELECT transaction AS data
FROM   "PreStage".transaction
WHERE  transaction->>'HCP_FST_NM' ILIKE '%neer%'
AND    transaction ? 'HCP_FST_NM';  -- even if that seems redundant.

第二个条件发生也匹配我们的部分索引。

所以要么给定的(流行/常见)键有一个特定的三元组索引,or 至少有一个索引来查找包含稀有键的(少数)行 - 然后过滤匹配值。同一个查询应该让您两全其美。

一定要运行最新版本的Postgres,最近有各种成本估算的更新。 Postgres 使用良好的估计和当前 table 统计数据来选择最佳查询计划至关重要。

没有内置索引可以精确地满足您的需求,即搜索确切的键和相应的通配符匹配值,而无需提前指定要使用的键。应该可以创建一个可以执行此操作的扩展程序,但这需要大量工作,而且我不知道是否存在任何扩展程序。

开箱即用的最佳选择可能是将 jsonb 转换为文本并索引该文本:

create index on transaction using gin ((transaction::text) gin_trgm_ops);

然后在您的查询中添加次要条件:

SELECT transaction AS data FROM transaction
WHERE  transaction->>'HCP_FST_NM' ILIKE '%neer%'
AND transaction::text ilike '%neer%';

现在它可以使用索引查找包含 'neer' 的任何内容,然后重新检查 'neer' 是否出现在 'HCP_FST_NM' 键的值中,而不是仅仅JSONB 中的其他某个地方。

如果您的查询词出现在所需键的值以外的许多地方,那么这可能不会给您很好的性能。例如,如果有人搜索:

transaction->>'EMAIL' ilike '%ADDR%'
AND transaction::text ilike '%ADDR%';

索引将 return 每行,假设所有记录都具有与您显示的结构相同的结构,因为每行都包含 'ADDR' 因为用作键。然后每一行都将无法通过其他条件检查,但只有在做了很多工作之后。