postgres 中 jsonb 数组数据索引的 ILIKE 查询

时间:2021-06-14 13:49:38

标签: postgresql indexing jsonb

我有一张表,其中有城市作为 jsonb 列,其中有 json 数组,如下所示

[{"name":"manchester",..},{"name":"liverpool",....}]

现在我想用 ILIKE 查询查询“name”列上的表。

我已经尝试过以下但对我不起作用

select * from data where city->>'name' ILIKE '%man%'

虽然我知道,我可以通过以下查询进行完全匹配的搜索

select * from data where city->>'name' @> 'manchester'

我也知道我们可以使用 jsonb 函数来制作平面数据和搜索,但它不会使用索引。

无论如何都可以用 ilike 搜索数据,它也使用索引吗?

2 个答案:

答案 0 :(得分:0)

索引支持会很困难;为此,遵循第一范式的模式将是有益的。

除此之外,您可以从 v12 开始使用 JSONPATH 语言:

WITH t(c) AS (
   SELECT '[{"name":"manchester"},{"name":"liverpool"}]'::jsonb
)
SELECT jsonb_path_exists(
          c,
          '$.**.name ? (@ like_regex "man" flag "i")'::jsonpath
       )
FROM t;

 jsonb_path_exists 
═══════════════════
 t
(1 row)

答案 1 :(得分:0)

您确实应该以不同的方式存储数据。

您可以“自然地”执行 ilike 查询,但无需索引支持,如下所示:

select * from data where exists (select 1 from jsonb_array_elements(city) f(x) where x->>'name' ILIKE '%man%');

您可以像这样获得索引支持:

create index on data using gin ((city::text) gin_trgm_ops);
select * from data where city::text ilike '%man%';

但它会在键的文本中找到匹配,以及值,并且使用任何存在的不相关键/值。您可以通过创建一个只返回值的函数来解决这个问题,所有值都组合成一个字符串,然后使用函数索引。但是,随着字符串长度变长,索引的效果会越来越差,因为会有更多的误报需要追踪和剔除。

create or replace function concat_val(jsonb, text) returns text immutable language sql as $$
    select string_agg(x->>$2,'   ') from jsonb_array_elements($1) f(x)
$$ parallel safe;

create index on data using gin (concat_val(city,'name')  gin_trgm_ops);

select * from data where concat_val(city,'name') ilike '%man%';

您确实应该以不同的方式存储数据。

相关问题