一、 业务需求和背景
- 官方的spark-computing包是闭源收费的,主要功能是读取 HugeGraph 中的数据并转换成 Spark GraphX 的 RDD,然后执行 GraphX 中的各种图算法。
- 业务方需要经常按label类型导出数据进行分析,此前一直是将全部数据(千亿点边)导出再进行label的,效率很低。因此需要进行数据的批量导出并使用graphx进行分析。也相当于自行实现了计算包的内容(spark(scala+java))官方计算包介绍传送门 (鉴于官方包收费,因此考虑后期将其开源出来,提供大家使用,性能和yarn资源有关,资源越充足越快,此外导出性能瓶颈主要取决于磁盘io)
二、核心流程
- schema读取解析:
- 读取图数据的点label(vl)、边label(el)、属性(pk)表,解析元数据信息用于后续匹配点边,这里需要重写下hugegraph的元数据相关类,不可直接使用
- 点(g_v)/边(oe)表读取解析:
- 需要读取点边数据按条解析并以json导出到hdfs
3. 导出核心细节
-
连接hbase集群
-
spark进行序列化
val sparkConf = new SparkConf().setMaster("local").setAppName("testHbase")
//对ImmutableBytesWritable这个类进行了序列化
sparkConf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
sparkConf.registerKryoClasses(Array(classOf[ImmutableBytesWritable]))
-
在解析点边数据前需要先获得pk\vl\el的元数据信息并解析,此处需结合hugegraph代码进行解码。解码后重新组合元信息提供给解析点边的rdd,(此处将结果使用collectadMap载入内存)
-
获得hbaseRDD进行计算,使用按region切分task,我们共有700个region 就是700个excutor
- 获得点数据后,首先进行filter算子,过滤点不符合目标label的点数据。
//此处isTargerLabel进行判断是否为目标label数据
hbaseRDD.filter(t=> isTargetLabel(t._2.getRow,targetLabel))
//时间戳过滤以及各种定制化需求
- 解析点边数据存入map
.map{ case (_, result) => {
//edgeid
val rowkey = result.getRow
//edgevalue
val value = result.getValue("f".getBytes(),"".getBytes())
val buffer = BytesBuffer.wrap(rowkey);
val sourceVertexId = buffer.readId.asString() //?
val direction = buffer.read
val labelId = buffer.readId.asString()
val sk = buffer.readString
val otherVertexId = buffer.readId.asString()
EdgeMap += ("sourceVertexId"->sourceVertexId)
EdgeMap += ("label"->elrdd.get(labelId).get.name)
EdgeMap += ("sk"->sk)
EdgeMap += ("targetVertexId"->otherVertexId)
val buffervalue = XByteBuffer.wrap(value)
val size = buffervalue.readVInt
for (i <- 0 to size-1) {
val pkeyId = IdGenerator.of(buffervalue.readVInt)
val pk = pkrdd.get(pkeyId.asString())
val value = buffervalue.readProperty(pk.get)
pkMap += (pk.get.name->value.toString)
}
//转换为json数据输出
(compact(render(pkMap)), compact(render(EdgeMap)))
}
}.saveAsTextFile(path)
- 转换为json数据并写入
//pkmap为点边属性 edgemap/vertexmap为点边id
(compact(render(pkMap)), compact(render(EdgeMap)))