-
Notifications
You must be signed in to change notification settings - Fork 558
Euler 2.0 GQL查询接口
Euler-2.0在Euler-1.0的基础上,进一步将上层算法和Euler底层接口解耦,开发了GQL编译执行引擎。上层算法直接调用GQL引擎来获取图的子结构,GQL引擎将GQL查询命令转化为Euler-2.0底层的基础算子调用,使得Euler可以兼容更加丰富的图结构查询。
在graphsage,gcn,random walk等模型中,获取图结构信息的操作只需要一次GQL语句查询,相较于1.0版本大大减少了运行过程中Euler和tensorflow的交互次数;同时Euler-2.0中内置了图查询编译优化规则,可以捕捉查询语句的潜在优化模式,提高执行效率。
Euler-2.0根据图神经网络算法设计了GQL语法。Euler-2.0的GQL采用了有向无环图(DAG)作为中间语言表达(IR),采用DAG更加适用于面向吞吐优化的场景。下面是graphsage算法所需要的GQL查询语句:
sampleN(node_type, count).as(n)
.sampleNB(edge_type, nb_count, -1).as(nb1)
.sampleNB(edge_type, nb_count, -1).as(nb2)
.v_select(n).values(f1).as(n_f1)
.v_select(nb1).values(f1).as(nb1_f1)
.v_select(nb2).values(f1).as(nb2_f1)
这条语句的含义是采样根节点n,然后获取两跳邻居nb1,nb2,最后将根节点n,邻居nb1,nb2的f1特征获取出来。这条GQL语句生成的DAG形式如下,其中sample_node表示采样节点,sample_nb表示采样邻居节点,get_p表示获取节点的属性:
Euler-2.0会先将GQL语句生成一个单机版本的DAG,然后根据Euler的不同运行模式(单机/分布式)来决定采用哪些DAG优化策略。下面会用graphsage的DAG介绍一下优化的方法。
- unique gather优化
在图查询过程中,有一些操作会返回很多重复的节点、边,比如从一大批根节点出发获取其邻居节点,对于服从幂律分布的图而言,可能会搜索到很多相同的热门节点。然后当获取这些邻居节点属性的时候就会有很多冗余查询,在分布式模式下也会造成热点问题。为了缓解这种情况,GQL优化器会在生成的计算图中添加相应的unique、gather算子,从而优化整个查询过程。
- 分布式RPC调用优化
在分布式运行环境下,由于图查询无法在单机上获取到所有结果,所以原本的单机运行的计算图会被拆分成多个子计算图,在不同的server上查询结果,然后将结果汇总。因此优化器会在计算图中根据事先设定的规则,找到某些需要分拆的算子,在其前后添加相应的split算子和merge算子,并将该算子复制为服务器的shard数目,将原本的单机运行计算图转化为分布式计算图。
比如获取一批节点的特征这个任务,首先就会将输入的节点通过split算子拆分,然后将拆分结果发送给每个get_p算子,每个get_p算子会被包装在一个叫remote_op的rpc调用算子中发送给远端的服务器。最后merge算子将不同分片的结果聚合。
某些情况下,多个操作可以在一次rpc调用中完成,这时候GQL优化器会将这几个操作一起fusion到一个remote_op中去,降低了rpc调用的次数。
- 公共子表达式消除
生成的计算图中会产生一些冗余的子表达式,这些子表达式会在DAG优化的最后一步——公共子表达式消除中被优化掉。比如graphsage中出现的模式,在分布式执行优化过程中出现的冗余split节点最终会被优化为一个,这在Euler-1.0中是无法实现的:
最终graphsage在分布式模式下运行的计算图将是下面这种形式: