使用spark 进行图数据按类型/全量导出实践

353 阅读2分钟

一、 业务需求和背景

  1. 官方的spark-computing包是闭源收费的,主要功能是读取 HugeGraph 中的数据并转换成 Spark GraphX 的 RDD,然后执行 GraphX 中的各种图算法。
  2. 业务方需要经常按label类型导出数据进行分析,此前一直是将全部数据(千亿点边)导出再进行label的,效率很低。因此需要进行数据的批量导出并使用graphx进行分析。也相当于自行实现了计算包的内容(spark(scala+java))官方计算包介绍传送门 (鉴于官方包收费,因此考虑后期将其开源出来,提供大家使用,性能和yarn资源有关,资源越充足越快,此外导出性能瓶颈主要取决于磁盘io)

二、核心流程

  1. schema读取解析:
    • 读取图数据的点label(vl)、边label(el)、属性(pk)表,解析元数据信息用于后续匹配点边,这里需要重写下hugegraph的元数据相关类,不可直接使用
  2. 点(g_v)/边(oe)表读取解析:
    • 需要读取点边数据按条解析并以json导出到hdfs

3. 导出核心细节

  1. 连接hbase集群

  2. spark进行序列化

 val sparkConf = new SparkConf().setMaster("local").setAppName("testHbase")
    //对ImmutableBytesWritable这个类进行了序列化
    sparkConf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
    sparkConf.registerKryoClasses(Array(classOf[ImmutableBytesWritable]))
  1. 在解析点边数据前需要先获得pk\vl\el的元数据信息并解析,此处需结合hugegraph代码进行解码。解码后重新组合元信息提供给解析点边的rdd,(此处将结果使用collectadMap载入内存)

  2. 获得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)
  1. 转换为json数据并写入
//pkmap为点边属性  edgemap/vertexmap为点边id
 (compact(render(pkMap)), compact(render(EdgeMap)))