第19期 Gremlin Steps:
sack()
本系列文章的Gremlin示例均在HugeGraph图数据库上执行,环境搭建可参考准备Gremlin执行环境,本文示例均以其中的“TinkerPop关系图”为初始数据,如下图所示:
结果存取口袋说明
Gremlin在路径游走的时候,可以将中间结果存放到一个叫口袋(sack)的结构里面,以备在后续步骤中使用;此外在放入数据到口袋的时候,还可以做一些灵活的操作比如:分裂(split)、合并(merge)等。sack相关step属于Gremlin语言里面的高级操作,在处理较为复杂的任务时可以灵活的实现一些特殊功能。
下面讲解实现上述功能的具体Step:
-
withSack(): 创建一个口袋,并给定一个初始结构,比如可以是一个返回Map或者随机数的lambda函数,也可以是一个对象或常数;另外还可以提供lambda分裂函数,以指定当traverser分裂时的行为,比如进行clone操作。 -
sack(): 将数据放入口袋,或者从口袋取出数据。当传入lambda合并函数作为参数时,可指定放入口袋的行为如何执行;当不传入参数时表示读取口袋中的内容。
实例讲解
下面通过实例来深入理解每一个操作。
-
Step
withSack()…sack(): 利用口袋来存取结果示例1:
// 创建一个包含常数1的口袋, // 并且在最终取出口袋中的值 g.withSack(1).V().sack()示例2:
// 创建一个包含常数1的口袋, // 并且在最终取出口袋中的值 g.withSack{new Random().nextFloat()} .V().sack()试一试:将
g.withSack{}的大括号换为小括号g.withSack()看看有什么区别示例3:
// 通过sum求和的方式把数据放入口袋 g.withSack(0).V() .repeat(outE().sack(sum).by('weight').inV()) .times(3).sack()试一试:通过以下gremlin查看路径及其权重:
g.withSack(0).V() .repeat(outE().sack(sum).by('weight').inV()) .times(3).path().by().by('weight')示例4:
// 通过lambda函数来指定放入口袋的行为 // 注意:提供的初始值为Map类型,而且 // 当traverser分裂时会拷贝Map g.withSack{[:]}{it.clone()} .V().out().out().dedup() .sack{m,v -> m[v.value('name')] = v.value('lang'); m} .sack()试一试:去掉分裂函数后看看效果:
g.withSack{[:]} .V().out().out().dedup() .sack{m,v -> m[v.value('name')] = v.value('lang'); m} .sack()示例5:
// 平均获取口袋中的值 g.withSack(1.0).V('javeme') .out('knows').out('created') .barrier(normSack).sack()
综合运用
-
获取路径并计算路径权重之和
// 获取路径的同时通过sack(sum)计算权重之和 // 最终通过select把权重和路径选取出来 g.withSack(0).V() .repeat(outE().sack(sum).by('weight').inV().as('p')) .times(3).sack().as('w') .select('w', 'p').by().by{p->p.toString()}.limit(3) -
获取路径并根据路径权重之和排序
// 获取路径的同时通过sack(sum)计算权重之和 // 最终通过order().by(sack())根据总权重排序 g.withSack(0).V() .repeat(outE().sack(sum).by('weight').inV()) .times(3).order().by(sack(),decr) .path().limit(3)
下一期:深入学习Gremlin(20):barrier