关于PostgreSQL JSONB的匹配和交集问题


Posted in PostgreSQL onSeptember 14, 2021

PostgreSQL 自从支持 JSONB 到现在,已经有十余年,这十多年来,社区为 JSONB 提供了很多强大的功能。就我个人而言,其实最常用的还是匹配操作 @> 。

把JSON数据看作一个抽象语法树(AST)的话,这个操作符判断右参数是不是左参数的子图。

这里本来应该有个图示, 但是周末的时候临时有个数据集在处理,所以没有时间去找合适的工具了。简单举几个例子,下面这个例子得到true,这应该很好理解:

select '{"a": 1, "b": 2, "c": 3}'::jsonb @> '{"b":2}' ;
--------------
t

而它也可以匹配更复杂的情况,下面这个例子也是 true:

select '{"a": 1, "b": 2, "c": {"value": 3}}'::jsonb @> '{"c":{"value": 3}}';
 ?column?
----------
 t
(1 row)

下面这个例子可能新用户会有点儿迷惑,但是其实也很好的契合了这个规则:

select '{"a": 1, "b": 2, "c": {"value": 3}}'::jsonb @> '{"c":{}}';
 ?column?
----------
 t
(1 row)

但是应该注意的是,下面这个例子结果是 false:

select '{"a": 1, "b": 2, "c": {"value": 3}}'::jsonb @> '{"c":[]}';
 ?column?
----------
 f
(1 row)

这也不难理解,{} 和 [] 不相等。

下面这个例子比较有意思:

select '{"a": 1, "b": 2, "c": {"value": [1, 2, 3]}}'::jsonb @> '{"c":{"value": [2]}}';
 ?column?
----------
 t
(1 row)

这里要注意的是,比较一个 JSON 数组是否匹配另一个时,它并不要求两个数组的顺序相等,只要右边是左边的真子集就可以:

select '{"a": 1, "b": 2, "c": {"value": [1, 2, 3]}}'::jsonb @> '{"c":{"value": [2]}}';
 ?column?
----------
 t
(1 row)
 
select '{"a": 1, "b": 2, "c": {"value": [1, 2, 3]}}'::jsonb @> '{"c":{"value": [5, 2]}}';
 ?column?
----------
 f
(1 row)
 
select '{"a": 1, "b": 2, "c": {"value": [1, 2, 3]}}'::jsonb @> '{"c":{"value": [3, 2]}}';
 ?column?
----------
 t
(1 row)

这个规则契合了PostgreSQL的倒排索引,PostgreSQL的gin索引,JSONB 字段类型和匹配操作 @> 成为了一个非常有力的组合。在过去几年里,我习惯为一些重要的业务表加上一个类型为 JSONB 的meta 字段,并对其建立 gin 索引

create index idx_xxx_meta on xxx using(gin);

需要注意的是指定索引类型时的 create index 语法。

这样的设计可以解决很多传统上难以解决的问题,例如我可以给每个条目打上一个 tag 列表,取带有某几个 tag 的条目就是一个简单的匹配查询:

select xxx from data_table where meta @> '{"tags": ["tag1", "tagx", "tagy"]}'

因为有gin索引的帮助,这个搜索的性能足够常规的互联网应用所需。

甚至我的在 CSDN NLP 组的同事还挖掘出了新的用法。我们在一个存储树节点的表里,保存了一个 meta 字段,其中有一个 path 列表,存储当前字段在树中的路径,它的每一项都是 {"id": node_id, "title": something}这样的结构,而我们搜索某一个节点下面的所有子节点,包括其隔代的子节点时,仅需要执行这样一个查询:

select xxx from tree_node where meta @> '{"path": [{"id": node_id}]}'

当然这个匹配操作也有它的限制,它在右边是左边的真子图的情况下才会匹配成功。例如我希望查找 tags 列表中包含我搜索项中的任何一个(即两者存在非空交集)的情况,用这种方法就不行了。此时我们需要另一个运算符 ?|

select '["tag1", "tag2", "tag3"]'::jsonb ?| '{tag2, tag3}';
 ?column?
----------
 t
(1 row)
 
select '["tag1", "tag2", "tag3"]'::jsonb ?| '{tag2, tag3, tag5}';
 ?column?
----------
 t
(1 row)
 
select '["tag1", "tag2", "tag3"]'::jsonb ?| '{tag5}';
 ?column?
----------
 f
(1 row)

注意这几个例子,首先右边的运算符不再是jsonb,而必须是 text[],其次它其实是检查 key 值——也就是可以通过 gin 索引存储的值:

select '{"tag1":1, "tag2":2, "tag3":3}'::jsonb ?| '{tag5}';
 ?column?
----------
 f
(1 row)
 
select '{"tag1":1, "tag2":2, "tag3":3}'::jsonb ?| '{tag3}';
 ?column?
----------
 t
(1 row)
 
select '{"tag1":1, "tag2":2, "tag3":3}'::jsonb ?| '{tag3, tag1}';
 ?column?
----------
 t
(1 row)

PostgreSQL 支持 JSON 和 JSONB 已经有十余年,每一个版本都在积极的增强其 JSON 数据处理能力,即使我近十年来的积极探索和学习,也没有全面的了解。这个交集运算也是近期在 NLP 组的工作过程中才注意到的。

到此这篇关于PostgreSQL JSONB的匹配和交集的文章就介绍到这了,更多相关PostgreSQL JSONB内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

PostgreSQL 相关文章推荐
PostgreSQL将数据加载到buffer cache中操作方法
Apr 16 PostgreSQL
通过Qt连接OpenGauss数据库的详细教程
Jun 23 PostgreSQL
基于PostgreSQL/openGauss 的分布式数据库解决方案
Dec 06 PostgreSQL
PostGIS的安装与入门使用指南
Jan 18 PostgreSQL
PostgreSQL并行计算算法及参数强制并行度设置方法
Apr 06 PostgreSQL
PostgreSQL数据库去除重复数据和运算符的基本查询操作
Apr 12 PostgreSQL
PostgreSQL基于pgrouting的路径规划处理方法
Apr 18 PostgreSQL
PostgreSQL怎么创建分区表详解
Jun 25 PostgreSQL
postgresql 删除重复数据案例详解
Aug 02 #PostgreSQL
PostgreSQL解析URL的方法
Aug 02 #PostgreSQL
postgresql使用filter进行多维度聚合的解决方法
Jul 16 #PostgreSQL
浅谈PostgreSQL表分区的三种方式
通过Qt连接OpenGauss数据库的详细教程
postgres之jsonb属性的使用操作
Jun 23 #PostgreSQL
postgresql无序uuid性能测试及对数据库的影响
Jun 11 #PostgreSQL
You might like
php数组函数序列 之shuffle()和array_rand() 随机函数使用介绍
2011/10/29 PHP
PHP代码网站如何防范SQL注入漏洞攻击建议分享
2012/03/01 PHP
探讨如何在PHP开启gzip页面压缩实例
2013/06/09 PHP
简单说说PHP优化那些事(经验分享)
2014/11/27 PHP
用JavaScript和注册表脚本实现右键收藏Web页选中文本
2007/01/28 Javascript
Javascript Web Slider 焦点图示例源码
2013/10/10 Javascript
Javascript selection的兼容性写法介绍
2013/12/20 Javascript
javascript中定义类的方法汇总
2014/12/28 Javascript
jQuery+css实现的时钟效果(兼容各浏览器)
2016/01/27 Javascript
详解JavaScript的AngularJS框架中的作用域与数据绑定
2016/03/04 Javascript
js 自带的 map() 方法全面了解
2016/08/16 Javascript
概述jQuery的元素筛选
2016/11/23 Javascript
解读ES6中class关键字
2017/11/20 Javascript
Javascript防止图片拉伸的自适应处理方法
2017/12/26 Javascript
ExtJs整合Echarts的示例代码
2018/02/27 Javascript
JS实现图片上传多次上传同一张不生效的处理方法
2018/08/06 Javascript
原生js实现点击按钮复制内容到剪切板
2020/11/19 Javascript
[01:39:04]DOTA2-DPC中国联赛 正赛 SAG vs CDEC BO3 第二场 2月1日
2021/03/11 DOTA
Python开发微信公众平台的方法详解【基于weixin-knife】
2017/07/08 Python
Python实现简单的HttpServer服务器示例
2017/09/25 Python
TensorFlow 模型载入方法汇总(小结)
2018/06/19 Python
对python捕获ctrl+c手工中断程序的两种方法详解
2018/12/26 Python
python学习——内置函数、数据结构、标准库的技巧(推荐)
2019/04/18 Python
python rsa实现数据加密和解密、签名加密和验签功能
2019/09/18 Python
python被修饰的函数消失问题解决(基于wraps函数)
2019/11/04 Python
Python如何使用BeautifulSoup爬取网页信息
2019/11/26 Python
基于Django集成CAS实现流程详解
2020/11/28 Python
Django 权限管理(permissions)与用户组(group)详解
2020/11/30 Python
Python字符串的15个基本操作(小结)
2021/02/03 Python
HTML5 body设置自适应全屏
2020/05/07 HTML / CSS
Hanky Panky官方网站:内衣和睡衣
2019/07/25 全球购物
Tenstickers法国:墙贴和装饰贴纸
2019/08/26 全球购物
营业员实习自我鉴定
2013/12/07 职场文书
法制教育观后感
2015/06/17 职场文书
gateway与spring-boot-starter-web冲突问题的解决
2021/07/16 Java/Android
php双向队列实例讲解
2021/11/17 PHP