GraphLite 实现子图匹配

同步图运算模型

许多大数据都以图的形式存在,非图结构的大数据也通常会被转化为图数据结构进行分析。对于大型图数据的计算,一些常见的处理软件如Neo4j等采用的是遍历的方法,另一些采用的如Giraph、Pregel等则采用的是同步图运算的方式。

后者采用的同步图运算模型主要有两个特点,一是BSP(Bulk Synchronous Processing)模型,即块同步计算模型,其主要思想是将全部计算分为多个超步(Superstep),超步内部的多个运算单元进行分布式地并行计算,每一个超步结束之后进行全局同步。超步与超步之间存在依赖关系,上一个超步的运算产生下一个超步的输入。二是基于顶点的编程模型。在该模型下,图中的每一个顶点都视为一个计算节点,程序员通过实现一个compute函数,在每一个超步中对每一个顶点都进行调用,实现基于顶点的计算。函数的内容主要包含三个部分,一是接受来自其他顶点的消息,二是进行运算,三是向其他顶点发送消息。与compute函数的主要内容相似的是在PowerGraph中也存在这样的计算过程,但是被细分割成了Gather、Apply、Scatter三个步骤,当然这偏离了本文主要内容,暂不赘述。

图运算的停止与各个顶点的状态有关,顶点包括两种状态active和inactive,其状态转换可以参照下图。初始情况下顶点的状态都是active的。当所有的顶点都是inactive状态的时候本次运算结束
GraphLite 实现子图匹配
最终同步图运算模型可以表示为下图所示的过程。
GraphLite 实现子图匹配

同步图运算系统架构

同步图运算采用Master/Worker形式的系统架构,每个Worker对应一个图的Partition(Partition的策略有很多例如hash partition),超步执行过程中,每个Worker进行本地计算,收集定点发送的信息。超步结束后,由Master进行全局同步操作,即Workers向Master发送本地全局信息由Master进行整合为全局信息再发送给Wokers。
GraphLite 实现子图匹配

GraphLite的使用

GraphLite是陈士敏团队实现的同步图运算框架,该框架利用C++实现了Pregel论文中的API。
在实际的使用过程中有一下几个接口需要程序员实现来满足不同的计算需求:

  1. InputFormatter
    InputFormatter负责图数据的载入,其中的loadGraph方法是数据载入的具体细节。
  2. OutputFormatter
    该接口负责结果的输出操作,利用接口提供的ResultIterator迭代器,可以获取所有Worker上的结果并输出
  3. Vertex
    该接口是同步图运算的核心部分,所有基于同步图运算的算法过程都实现在这里。编程人员需要实现的是接口中的compute函数,在函数中通过getSuperstep()获取当前超步数来决定此时compute应该执行什么样的程序。compute函数的参数是一个消息队列(MessageIterator),内部记录着每次同步时收到的消息,通过遍历消息队列就可以获取到上一个超步其他节点发送来的消息。此外Vertex中还可以利用getOutEdgeIterator()获取到当前节点的出边,通过遍历出边就可以向当前节点的邻居发送消息。
  4. Aggregator
    前文中提及的专门负责汇总信息的程序,提供了累加(accumulate),编程人员通过在Vertex::compute()函数中调用accumulateAggr()即可实现结果的累加。值得注意的是,Aggregator在Master以及各个Worker进程中分别独立存在,这里我们通过Global_Aggregator和Local_Aggregator来区分。在程序运行过程中,compute函数调用的accumulateAggr()首先由Local_Aggregator来进行累加,在每个超步结束后的同步阶段Global_Aggregator通过和并(merge)的方式将各个Local_Aggregator的累加信息合并,随后在下一个超步开始时将和并的结果发送至Local_Aggregator。
  5. Graph
    实现此接口的init()函数,从而进行同步图运算的一些基本设置如Master和Worker的数量、地址、监听的接口,图数据文件的位置以及结果输出的位置、Aggregator的数量等等。

基于同步图运算的子图匹配算法

子图匹配算法简单来说就是给定一个查询图S, 在一个数据图G中找到于图S结构相同的图,该类问题有很多相关的工作可以参考,例如许文[1]将按照一定规则查询图拆解为多个高度为2的树,在数据图中查询出对应的树,再根据原有的图关系对树进行“修剪”得到结果。bi[2]利用笛卡尔积解决了子图匹配的问题。此外QFrag[3]和zhao2016[4]给出了基于同步图运算的子图匹配算法。
通过查询文献我们的子图匹配算法最终参考了xu2018[5]的文章,通过自底向上的方式从查询图的叶子结点开始逐层查询直至根节点,达到子图匹配的目的。主要过程如下:

  • 首先将查询图进行处理,将其转换成高度最低的生成树(MHT), 将这棵树作为查询图算法的输入。
  • 接下来进入如图所示的环节,算法的第7-9行对应超步0的工作,对于输入的MHT的每一个叶子,如果该叶子节点l于数据图的当前节点v匹配则将他们记录在一个pair<l,v>中,将该pair发送给它的邻居。
  • 在余下的步数中,做算法10-17行的操作。
    line10: 遍历消息队列, Ω(u)对应T的子树,u是子树的根节点。
    line11: 如果u的父亲节点u’与当前节点匹配, 则继续执行否则节点进入非活跃状态
    line12: 将他们放入一个pair<u',v>
    line13: 将子树Ω(u)放入集合Mp中
    line14: 如果顶点v收到了u’的所有子树(根据Mp进行判断), 则继续执行否则节点进入非活跃状态
    line15: 将μ<u',v>并入Ω(u)生成新的子树Ω(u’)
    line16: 如果u’是根节点则表明匹配完成,Ω(u‘)就是一个查询结果,将其并入结果集Res
    line17: 否则继续将子树Ω(u’)发给其他节点,进行进一步匹配。
    GraphLite 实现子图匹配
  • 上述算法中的sendMessage在此需要特别说明,由于发送消息时可以遍历边,所以借此机会可以查看数据图的边是否与查询图相匹配,不匹配的话就没有必要继续发送了
    GraphLite 实现子图匹配

总结

事实证明查询图所转换的生成树并不一定要求是最小的,树的高度仅仅决定了查询的超步数,当然从效率的角度考虑还是推荐生成最小高度的树。

在开发过程中遇到的最大的问题是Graphlite框架下传递消息以及Aggregator所能存储的全局消息全部是定长的。然而在子图匹配的过程中所匹配到的子树Ω(u)是不断生长的。所以这里采用一个足够长的bitset存储全局信息。bitset的结构如图所示,将整个bitset分割成u1 -un个部分,其中u1-un是查询用MHT的所有节点,每个部分的比特位表示数据图的顶点vi是否是ui子树的匹配,如果是则该位置1否则置0。也就是说ui是子树的根节点id,如果子树的后代与顶点vi匹配,则在ui对应的区域内vi的位置置1即可,这样一来利用一个定长的bitset缓存了全部的结果,每个超步结束同步时将bitset于原来的全局变量做或运算即可。

自图匹配算法实现代码地址:

参考文献

[1] 许文,宋文爱,富丽贞,吕伟.面向大规模图数据的分布式子图匹配算法[J].计算机科学,2019,46(04):28-35.
[2] Bi F, Chang LJ, Lin XM, Qin L, Zhang WJ. Efficient Subgraph Matching by Postponing Cartesian Products[A]. ACM SIGMOD International Conference on Management of Data[C]. NY USA: ACM New York,2016: 1199-1214.
[3] SERAFINI, Marco; DE FRANCISCI MORALES, Gianmarco; SIGANOS, Georgos. Qfrag: Distributed graph search via subgraph isomorphism [A]. Proceedings of the 2017 Symposium on Cloud Computing[C] NY USA: ACM New York, 2017: 214-228.
[4] Zhao X, Chen Y, Xiao C, Ishikawa Y, Tang J. Frequent subgraph mining based on Pregel[J]. The Computer Journal, 2016, 59(8): 1113-1128.
[5] Xu Q, Wang X, Xin Y, Feng Z, Chen R. PDSM: Pregel-Based Distributed Subgraph Matching on Large Scale RDF Graphs[A].Companion Proceedings of the The Web Conference[C] . International World Wide Web Conferences Steering Committee, 2018: 17-18.