跳到主要内容

OlapBase API

此文档主要详细介绍了OlapBase API的使用说明

1. 概述

本手册将介绍使用TuGraph图计算系统需要的简单配置,同时结合代码对TuGraph中几个共同的重要文件和接口进行解释。

2. 配置要求

如果要使用TuGraph图计算编写以及编译自己的应用程序,需要的配置要求为:

  • linux操作系统,目前在Ubuntu16.04, Ubuntu18.04, Ubuntu20.04和Centos7, Centos8系统上可成功运行。
  • 支持C++17的编译器,要求GCC版本为8.4.0或更新的版本。

3. 原子操作

TuGraph使用了多线程技术进行批处理操作,在这种情况下可能会出现访存冲突现象。为了保证并行计算时修改操作的正确性,TuGraph实现了原子操作。代码部分见lgraph文件夹下的lgraph_atomic.cpp文件。 TuGraph还自定义了4个常用的原子操作。当我们需要在多线程模式下修改点的数据时,我们都应该使用原子操作来确保并行环境下修改操作的正确性。除了这4个原子操作外,用户也可以使用“cas”来构建自己的原子操作函数。

  • bool cas(T * ptr, T oldv, T newv):如果ptr指向的值等于oldv,则将ptr指向的值赋为newv并返回true,否则返回false
  • bool write_min(T *a, T b):如果b比a指向的值更小,那么将a指向的值赋为b并返回true,否则返回false。
  • bool write_max(T *a, T b):如果b比a指向的值更大,那么将a指向的值赋为b并返回true,否则返回false。
  • void write_add(T *a, T b):将b的值加到a指向的值上。
  • void write_sub(T *a, T b):将a指向的值减去b的值。

4. 点集合类ParallelBitset

在使用TuGraph进行批处理操作时,需要使用点集合来表示需要处理的点。ParallelBitset实现了点集合类,以bit为单位表示点,因此能够节省大量内存。对应的代码见lgraph文件夹下的olap_base.h文件。

4.1 ParallelBitset类成员

  • size_t Size():表示Bitmap中的点个数。
  • ParallelBitset(size_t size):初始化size和data,data长度为(size >> 6)+1
  • void Clear():清空集合
  • void Fill():将所有点加入集合
  • bool Has(size_t i):检查点i是否在集合中
  • bool Add(size_t i):将点i加入集合中
  • void Swap(ParallelBitset &other):和另一组ParallelBitset集合交换元素

5. 点数组类ParallelVector

在使用TuGraph进行批处理操作时,需要使用点数组来表示对点的处理结果。ParallelVector实现了点数组类。对应的代码见lgraph文件夹下的olap_base.h文件。

5.1 ParallelVector类成员

  • ParallelVector(size_t capacity) 构建ParallelVector,capacity为点数组的初始容量大小
  • T &operator[](size_t i):下标为i的数据
  • T *begin():ParallelVector的起始指针
  • T *end():ParallelVector的结束指针。begin和end的用法类似于vector容器的begin和end指针,可以使用这两个指针对数组进行顺序访问
  • T &Back():ParallelVector最后一个数据
  • T *Data():表示数组本身数据
  • void Destroy():清空ParallelVector数组内数据并删除数组
  • size_t Size():表示ParallelVector中的数据个数
  • size_t Capacity():表示ParallelVector的容量大小
  • void Resize(size_t size):更改ParallelVector为size大小,该size应大于等于更改前的大小且小于capacity
  • void Clear():清空ParallelVector内数据
  • void ReAlloc(size_t capacity):给ParallelVector分配新的容量大小,若数组有数据则将数据迁移至新内存
  • void Fill(T elem):为ParallelVector的全部数据赋值为elem
  • void Append(const T &elem, bool atomic = true):向ParallelVector结尾添加一个数据
  • void Swap(ParallelVector<T> &other):和其他的ParallelVector交换数据
  • ParallelVector<T> Copy():复制当前的ParallelVector数据存至Copy数组中

6. 自定义数据结构

6.1 基本数据类型

我们自定义了点和边的数据结构表示,用于在覆盖所有点的同时节省内存空间:

  • Empty:内容为空的特殊数据类型。

6.2 组合数据结构

为了便于计算,我们根据计算场景不同,定义了几种点和边数据的数据结构,分别是:

  • EdgeUnit<EdgeData>:表示权值类型为EdgeData的边,用于解析输入文件,包含三个成员变量:
    • size_t src:边的起始点
    • size_t dst:边的终点
    • EdgeData edge_data:边的权值
  • AdjUnit<EdgeData>:表示权值类型为EdgeData的边,用于批处理计算过程中,包含两个成员变量:
    • size_t neighbour:边的邻居点
    • EdgeData edge_data:边的权值
  • AdjList<EdgeData>:权值类型为EdgeData的点的邻接表,常用于表示点的入边和出边集合,包含两个成员变量:
    • AdjUnit<T> * begin:列表的起始指针
    • AdjUnit<T> * end:列表的结束指针。begin和end的用法类似于vector容器的begin和end指针,可以使用这两个指针对邻接表进行循环访问。

7. 图类OlapBase

图类OlapBase是TuGraph用于加载图以及进行图计算操作的主类,常用OlapBase表示权值类型为EdgeData的图,代码部分见lgraph文件夹下的olap_base.hpp。本章将介绍Graph类中常用的类型和API接口。上文介绍Procedure、Embed及Standalone功能所使用的类均为该类的子类。

7.1 基本信息

  • size_t NumVertices():获取点数
  • size_t NumEdges():获取边数
  • size_t OutDegree(size_t vid):点vid的出度
  • size_t InDegree(size_t vid):点vid的入度

7.2 点集和边集及其相关操作

  • ParallelVector<VertexData> AllocVertexArray<VertexData>():分配一个类型为VertexData的数组,大小为点个数
  • void fill_vertex_array<V>(V * array, V value):将数组array中的所有元素赋值为value
  • ParallelBitset AllocVertexSubset():分配一个ParallelBitset集合,用于表示所有点的状态是否激活
  • AdjList<EdgeData> OutEdges(size_t vid):获取点v的所有出边集合
  • AdjList<EdgeData> InEdges(size_t vid):获取点v的所有入边集合
  • void Transpose():对有向图进行图反转
  • LoadFromArray(char * edge_array, VertexId input_vertices, EdgeId input_edges, EdgeDirectionPolicy edge_direction_policy):从数组中加载图数据,包含四个参数,其含义分别表示:
    • edge_array:将该数组中的数据读入图,一般情况下该数组包含多条边。
    • input_vertices:指定数组读入图的点个数。
    • input_edges:指定数组读入图的边的条数。
    • edge_direction_policy:指定图为有向或无向,包含三种模式,分别为DUAL_DIRECTION、MAKE_SYMMETRIC以及INPUT_SYMMETRIC。对应的详细介绍见include/lgraph/olap_base.h文件的enum EdgeDirectionPolicy

7.3 锁机制

TuGraph实现了一对锁机制,来控制程序对于点数据的访存权限。分别是:

  • void AcquireVertexLock(size_t vid):对点vid加锁,禁止其它线程对该锁对应的点数据进行访存
  • void ReleaseVertexLock(size_t vid):对点vid解锁,所有线程均可访存该锁对应的点数据
  • VertexLockGuard GuardVertexLock(size_t vid):在对vid操作时,对点vid加锁,退出作用域时时自动释放锁

7.4 批处理操作

TuGraph提供了两个批处理操作来并行地进行以点为中心的批处理过程。分别是:

/*
函数名称:ReducedSum ProcessVertexInRange(std::function<ReducedSum(size_t)> work, size_t lower, size_t upper,
ReducedSum zero = 0,std::function<ReducedSum(ReducedSum, ReducedSum)> reduce =reduce_plus<ReducedSum>)

函数用途:对Graph中节点编号介于lower和upper之间的节点执行work函数。第四个参数表示累加的基数,默认为0;
第五个参数表示对每个work处理后的节点返回值进行迭代reduce函数操作,默认为累加操作。
具体实现请参考include/lgraph/olap_base.h中具体代码

使用示例:统计数组parent数组中有出边的点个数
*/

auto vertex_num = graph.ProcessVertexInRange<size_t>(
[&](size_t i) {
if (graph.OutDegree(parent[i]) > 0) {
return 1;
}
},
0, parent.Size()
);
printf("the number is %lu\n",vertex_num);

其中graph为图类OlapBase的实例化对象

/*
函数名称:ReducedSum ProcessVertexActive(std::function<ReducedSum(size_t)> work, ParallelBitset &active_vertices,
ReducedSum zero = 0,std::function<ReducedSum(ReducedSum, ReducedSum)> reduce =reduce_plus<ReducedSum>)

函数用途:对active_vertices中对应为1的节点执行work函数,第三个参数表示累加的基数,默认为0;
第四个参数表示对每个work处理后的节点返回值进行迭代reduce函数操作,默认为累加操作。
具体实现请参考/include/lgraph/olap_base.h中具体代码

使用示例:输出Graph中节点1,2,3的所有出度邻居,并统计这三个节点的总出度
*/

auto active_in = graph.AllocVertexSubset();
active_in.Add(1);
active_in.Add(2);
active_in.Add(3);
auto total_outdegree = graph.ProcessVertexActive<size_t>(
[&](size_t vi) {
size_t local_outdegree = 0;
for (auto & edge : graph.OutEdges(vi)) {
size_t dst = edge.neighbour;
printf("node %lu has neighbour %lu\n",vi,dst);
local_outdegree += 1;
}
return local_outdegree;
},
active_in
);
printf("total outdegree of node1,2,3 is %lu\n",total_outdegree);