索引 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' 因为用作键。然后每一行都将无法通过其他条件检查,但只有在做了很多工作之后。
这是以下内容的后续:
我有一个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' 因为用作键。然后每一行都将无法通过其他条件检查,但只有在做了很多工作之后。