Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 基于嵌套字符串数组的Postgres JSONB查询和索引_Arrays_Postgresql_Indexing_Jsonb - Fatal编程技术网

Arrays 基于嵌套字符串数组的Postgres JSONB查询和索引

Arrays 基于嵌套字符串数组的Postgres JSONB查询和索引,arrays,postgresql,indexing,jsonb,Arrays,Postgresql,Indexing,Jsonb,在以下情况下,如何制定查询并提供适当的索引是我遇到的一些麻烦。我有这样的JSON表示的客户实体(只保留相关属性): } 客户存储在以下客户表中: CREATE TABLE Customer ( id BIGSERIAL PRIMARY KEY, resource JSONB )) 我设法对资源列进行简单查询,例如,像这样的投影查询(检索以“bo”开头的城市的所有小写地址行): 我很难做到以下几点:我的目标是查询至少有一个地址行以“12”开头的所有客户。用例不敏感是我的用例的一个要求。示例客户将

在以下情况下,如何制定查询并提供适当的索引是我遇到的一些麻烦。我有这样的JSON表示的客户实体(只保留相关属性):

}

客户存储在以下客户表中:

CREATE TABLE Customer (
id BIGSERIAL PRIMARY KEY,
resource JSONB
))

我设法对资源列进行简单查询,例如,像这样的投影查询(检索以“bo”开头的城市的所有小写地址行):

我很难做到以下几点:我的目标是查询至少有一个地址行以“12”开头的所有客户。用例不敏感是我的用例的一个要求。示例客户将匹配我的查询,因为第一个地址对象有一个以“12”开头的地址行。请注意,“line”是JSON字符串的数组,而不是复杂的对象。到目前为止,我能想到的最接近的事情是:

SELECT c.resource FROM Customer c, jsonb_array_elements(c.resource #> '{address}') a WHERE a->'line' ?| array['123 Harris Plaza'];
显然,这不是一个不区分大小写的查询。非常感谢任何关于如何制定查询和伴随的GIN索引的帮助/建议。我的第一个查询已经选择了所有的地址行作为文本,所以也许这可以用于GIN索引


我使用的是Postres 9.5,但如果这只能在较新的Postgres版本中实现,我很乐意升级。

虽然GIN索引有支持前缀匹配的机制,但这一机制仅用于tsvectors。array_ops没有连接,json_ops或json_path_ops也没有连接。因此,除非您想创建新的运算符类/族(或将数据规范化为单独的表),否则您必须将数据转换为tsvector

下面是一种粗略的方法,它不考虑地址行可能包含文字单引号或其他有意义的字符:

create function addressline_tsvector(jsonb) returns tsvector immutable language SQL as $$ 
   select string_agg('''' || lower(value) || '''', ' ')::tsvector 
   from jsonb_array_elements($1->'address') a(a),
        jsonb_array_elements_text(a->'line') 
$$;

create index on customer using gin (addressline_tsvector(resource));

select * from customer where addressline_tsvector(resource) @@ lower('''2nd Main'':*')::tsquery;

假设您的示例表只有一行,除非您首先
设置enable_seqscan=off
,否则可能不会实际使用索引。

虽然GIN索引具有支持前缀匹配的机制,但该机制仅用于tsvectors。array_ops没有连接,json_ops或json_path_ops也没有连接。因此,除非您想创建新的运算符类/族(或将数据规范化为单独的表),否则您必须将数据转换为tsvector

下面是一种粗略的方法,它不考虑地址行可能包含文字单引号或其他有意义的字符:

create function addressline_tsvector(jsonb) returns tsvector immutable language SQL as $$ 
   select string_agg('''' || lower(value) || '''', ' ')::tsvector 
   from jsonb_array_elements($1->'address') a(a),
        jsonb_array_elements_text(a->'line') 
$$;

create index on customer using gin (addressline_tsvector(resource));

select * from customer where addressline_tsvector(resource) @@ lower('''2nd Main'':*')::tsquery;

假设示例表只有一行,除非首先
设置enable_seqscan=off
,否则可能不会实际使用索引。

示例是否区分大小写并不重要,因为数字没有大小写。你能提供一个例子来证明这种区别吗?没错,这只是一个例子。对于实际数据,大小写确实很重要,主要是因为“line”数组确实包含以下非英语地址:“line”:[“Hauptstrasse 17”,“Erlenweg 82”]您的示例是否区分大小写并不重要,因为数字没有大小写。你能提供一个例子来证明这种区别吗?没错,这只是一个例子。实际数据的大小写确实很重要,这主要是因为“line”数组确实包含非英语地址,例如:“line”:[“Hauptstrasse 17”,“Erlenweg 82”]这太完美了!我不知道tsvector类型,因此我从未想到过这种方法。我在更真实的数据集(100万行,接近真实的数据)上尝试了您的解决方案,索引确实得到了使用。非常感谢你!这太完美了!我不知道tsvector类型,因此我从未想到过这种方法。我在更真实的数据集(100万行,接近真实的数据)上尝试了您的解决方案,索引确实得到了使用。非常感谢你!
create function addressline_tsvector(jsonb) returns tsvector immutable language SQL as $$ 
   select string_agg('''' || lower(value) || '''', ' ')::tsvector 
   from jsonb_array_elements($1->'address') a(a),
        jsonb_array_elements_text(a->'line') 
$$;

create index on customer using gin (addressline_tsvector(resource));

select * from customer where addressline_tsvector(resource) @@ lower('''2nd Main'':*')::tsquery;