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,否则返回falsebool 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)+1void 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应大于等于更改前的大小且小于capacityvoid Clear()
:清空ParallelVector内数据void ReAlloc(size_t capacity)
:给ParallelVector分配新的容量大小,若数组有数据则将数据迁移至新内存void Fill(T elem)
:为ParallelVector的全部数据赋值为elemvoid 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
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中的所有元素赋值为valueParallelBitset 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);