基于Azure CosmosDB的Gremlin图查询:分组排序检索特定顶点
Gremlin + Azure CosmosDB 图查询问题
图结构定义
1. 添加object1类型顶点
g.addV('object1').property('id','1').addV('object1').property('id','2')
2. 添加object2类型顶点
g.addV('object2').property('id','1').property('date', '01-08-2023').property('type', 'ordinary').property('object1', '1') .addV('object2').property('id', '2').property('date', '02-08-2023').property('type', 'special').property('object1', '1') .addV('object2').property('id', '3').property('date', '31-07-2023').property('type', 'ordinary').property('object1', '1') .addV('object2').property('id','4').property('date', '01-07-2023').property('type', 'ordinary').property('object1', '2') .addV('object2').property('id','5').property('date', '02-07-2023').property('type', 'special').property('object1', '2') .addV('object2').property('id','6').property('date', '30-06-2023').property('type', 'ordinary').property('object1', '2')
3. 添加object2与object1的关联边
g.V().hasLabel('object1').has('id', '1').addE('SCANNED').from(g.V().hasLabel('object2').has('id', '1')) g.V().hasLabel('object1').has('id', '1').addE('SCANNED').from(g.V().hasLabel('object2').has('id', '2')) g.V().hasLabel('object1').has('id', '1').addE('SCANNED').from(g.V().hasLabel('object2').has('id', '3')) g.V().hasLabel('object1').has('id', '2').addE('SCANNED').from(g.V().hasLabel('object2').has('id', '4')) g.V().hasLabel('object1').has('id', '2').addE('SCANNED').from(g.V().hasLabel('object2').has('id', '5')) g.V().hasLabel('object1').has('id', '2').addE('SCANNED').from(g.V().hasLabel('object2').has('id', '6'))
关联关系说明
object2顶点[id:1,2,3] —SCANNED—> object1[id:1]
object2顶点[id:4,5,6] —SCANNED—> object1[id:2]
查询需求
针对每个object1,完成以下操作:
- 找出类型为
ordinary的最新object2顶点; - 找出类型为
special且时间晚于步骤1中object2的最新顶点; - 收集步骤1和2中的object2顶点,用于后续遍历。
预期输出:[object2 id:1, object2 id:2, object2 id:4, object2 id:5]
已尝试的分组查询
已实现按object1分组的查询:
g.V().hasLabel("object1").in("SCANNED").group().by("object1")
分组结果:
[ { 1: [ { 'id' : '1', 'date': '01-08-2023', 'type': 'ordinary', "object1": '1'}, { 'id' : '2', 'date': '02-08-2023', 'type': 'special', "object1": '1'}, { 'id' : '3', 'date': '31-07-2023', 'type': 'ordinary', "object1": '1'} ], 2:[ { 'id' : '4', 'date': '01-07-2023', 'type': 'ordinary', "object1": '2'}, { 'id' : '5', 'date': '02-07-2023', 'type': 'special', "object1": '2'}, { 'id' : '6', 'date': '30-06-2023', 'type': 'ordinary', "object1": '2'} ] } ]
待解决问题及解决方案
1. 如何对object2排序,获取类型为ordinary的最新顶点?
通过类型过滤+日期降序排序+取第一条的方式实现:
// 单个object1查询示例 g.V().hasLabel('object1').has('id','1').in('SCANNED').has('type','ordinary').order().by('date', desc).limit(1) // 批量按object1分组获取 g.V().hasLabel('object1').group().by('id').by( in('SCANNED').has('type','ordinary').order().by('date', desc).limit(1) )
2. 如何获取类型为special且时间晚于步骤1中顶点的最新object2?
先获取步骤1的最新ordinary顶点日期,再过滤符合条件的special顶点并取最新:
// 单个object1查询示例 g.V().hasLabel('object1').has('id','1').as('o1'). in('SCANNED').has('type','ordinary').order().by('date', desc).limit(1).as('latestOrdinary'). select('o1').in('SCANNED').has('type','special'). where('date', gt(select('latestOrdinary').values('date'))). order().by('date', desc).limit(1) // 批量按object1分组处理 g.V().hasLabel('object1').group().by('id').by( union( // 步骤1:获取最新ordinary顶点 in('SCANNED').has('type','ordinary').order().by('date', desc).limit(1), // 步骤2:获取符合条件的special顶点 in('SCANNED').has('type','ordinary').order().by('date', desc).limit(1).as('lo'). select('$$').in('SCANNED').has('type','special').where('date', gt(select('lo').values('date'))). order().by('date', desc).limit(1) ).fold() )
3. 如何检索这些顶点以用于后续遍历?
用flatMap+union收集所有符合条件的顶点,直接用于后续操作:
// 收集所有目标顶点,返回的集合可直接用于后续遍历 g.V().hasLabel('object1').flatMap( union( in('SCANNED').has('type','ordinary').order().by('date', desc).limit(1), in('SCANNED').has('type','ordinary').order().by('date', desc).limit(1).as('lo'). select('$$').in('SCANNED').has('type','special').where('date', gt(select('lo').values('date'))). order().by('date', desc).limit(1) ) ).dedup()
内容的提问来源于stack exchange,提问作者ajj
相关产品推荐
相关产品推荐

