累加器101

累加器101

GSQL是一种图灵完备的图数据库查询语言。与其他图查询语言相比,最大的优势在于它支持累加器——全局的累加器以及附加到每个顶点上的累加器。

GSQL提供了经典的模式匹配语法,这比较容易掌握。除此以外,GSQL还支持强大的局部累加器(运行过程中产生的顶点属性)和全局累加器(全局范围的状态变量)。我看到有些用户只花了10分钟就能学习掌握模式匹配语法,相比之下,我发现新手学习起累加器就显得力不从心。

这个简短的教程旨在缩短累加器的学习曲线。您读完这篇文章后,就可以牢牢掌握累加器的本质,然后开始用这种便捷的语言特性来解决现实中的图问题。

什么是累积器?

Screen-Shot-2019-07-13-at-12.48.25-700x513

图1.左侧框是用不同类型的累加器进行累加的GSQL代码。右侧框显示各累加器变量的最终结果。

累加器是GSQL中的状态变量。它的状态在查询的整个生命周期中都是可变的。它具有初始值,然后用户可以多次使用它内置的运算符“+=”,不断地把新值累加到它身上。定义每个累加器变量时都要声明它的类型,这个类型决定了执行“+=”运算时会进行怎样的操作。

在图1的左侧框中,从第3行到第8行,声明了六个不同的累加器变量(带有前缀@@的变量),每个变量都具有唯一的类型。下面,我们解释它们的语义和用法。

SumAccum <INT>允许用户不断地将INT值与其内部状态变量相加。如第10行和第11行所示,我们将1和2加到累加器中,最后得到值3(右侧框中的第3行所示)。

MinAccum <INT>始终保存着它看到的最小的INT类型的数值。如第14行和第15行所示,我们将1和2累加到MinAccum累加器,最后得到值1(右侧框中的第6行)。

MaxAccum <INT>与MinAccum相反。它返回它看到的最大的INT值。第18行和第19行显示我们将传值1和2给它,最后得到值2(在右侧框中的第9行中显示)。

OrAccum持续接收累加到它上面的布尔值,每次它把接收的布尔值与累加器中存的布尔状态变量进行Or操作,然后将状态变量更新为Or后的结果值。初始默认值为FALSE。第22行和第23行显示我们向其发送TRUE和FALSE,最终结果值就是TRUE(如右框中的第12行所示)。

AndAccum与OrAccum相似,只是它不进行OR操作,而是进行AND操作。第26行和第27行显示我们将TRUE和FALSE累加到累加器后,最终结果值为FALSE(如右框中的第15行所示)。

ListAccum <INT>持续将新INT值添加到累加器中存的List变量中。第30-32行显示我们将1,2和[3,4]累加到累加器中,最终得到[1,2,3,4](如右框中的第19-22行所示)。

 

全局累加器与附加到顶点的累加器

到目前为止,我们了解到,累加器是GSQL语言中有特定类型的变量。现在我们解释一下什么是全局范围和局部范围的累加器。

全局累加器属于整个查询。在查询中的任何位置,语句都可以更新它的值。局部累加器属于每个顶点。只有在可以访问拥有它的顶点时才能更新它。为了区分它们,我们在声明它们时,给它们的名称使用了特殊前缀。

@@前缀用于声明全局累加器变量。它总是单独使用的。比如:@@cnt += 1。

@前缀用于声明局部累加器变量。它必须与查询块中的顶点别名一起使用。例如,v.@cnt += 1,其中v是SELECT-FROM-WHERE查询块的FROM子句中所指定的顶点别名。

Screen-Shot-2019-07-23-at-1.12.42-PM-700x550

图2.这个社交关系图由7个“人”类型的顶点和7条“朋友关系”的边组成

现在看一个简易版的社交关系图如图2,它由“人”类型的顶点和“人-人”友谊关系类型的边构成。下面我们编写一个查询,输入为一个“人”类型的顶点,然后从这个顶点向它的邻居做一跳遍历。我们使用@@global_edge_cnt这个累加器来统计共遍历了多少边,使用@vertex_cnt向所有邻居顶点写入一个整数1。

Screen-Shot-2019-07-23-at-1.13.50-PM-700x309

Screen-Shot-2019-07-13-at-13.49.11-700x1015

图3.上一个框是一段查询语句,输入一个人,将其朋友关系的边进行计数,输入到@@global_edge_cnt中,再对所有朋友,累加1到朋友的@vertex_cnt中去。下面的框展示了计算结果。

如图2所示,Dan有4个直接的朋友–Tom,Kevin,Jenny和Nancy,每个朋友都拥有一个本地累加器@vertex_cnt。@@ global_edge_cnt的值则为4,反映了对于每条边,我们各累加1到这个累加器中。

ACCUM VS. POST-ACCUM

ACCUM和POST-ACCUM子句分步骤执行。在SELECT-FROM-WHERE查询块中,首先执行ACCUM子句,然后执行POST-ACCUM子句。

ACCUM:找到与FROM子句的模式匹配得上的边后,这些边会各执行一次ACCUM子句,而且ACCUM子句在这些边上是并发执行的。

POST-ACCUM:POST_ACCUM会对每个涉及的顶点执行一次语句。要注意的是,这里说的“涉及的顶点”可以取源顶点,也可以取目标顶点,但两者只能取一。

 

结论

我们已经解释了累加器的机制、它们的类型以及两个不同的范围——全局范围和局部范围。我们还阐述了ACCUM和POST-ACCUM子句的语义。一旦你掌握了这些基础知识,剩下的就是多练习了。我们已经提供了46个基于LDBC的模式的查询。这46个查询分为三组。

IS: https://github.com/tigergraph/ecosys/tree/ldbc/ldbc_benchmark/tigergraph/queries_pattern_match/interactive_short

IC: https://github.com/tigergraph/ecosys/tree/ldbc/ldbc_benchmark/tigergraph/queries_pattern_match/interactive_complex

BI: https://github.com/tigergraph/ecosys/tree/ldbc/ldbc_benchmark/tigergraph/queries_pattern_match/business_intelligence

您可以按照GSQL 102来设置环境。 您还可以在GSQL社区论坛上发布您的反馈和问题。 我们的社区成员和开发人员喜欢听到您使用GSQL过程中的任何反馈,并随时准备帮助解答您的疑问。