Spark结合了DataFrames和GraphX

时间:2016-09-19 00:10:10

标签: apache-spark apache-spark-sql spark-graphx

是否可以组合GraphX和DataFrames?我希望Graph中的每个节点都有一个自己的DataFrame。我知道GraphX和DataFrame扩展了RDD,嵌套的RDD是不可能的,SparkContext也不是Serializable。但在Spark 2.0.0中,我看到SparkSession是Serializable。我试过了,但它还没有用。 我还试图将DataFrames全局存储在一个数组中。但是我无法在workernode中访问Array。忽略方法sendMsg并合并:

object Main{
  def main(args: Array[String]) : Unit = {    
    val spark = SparkSession
      .builder
      .appName("ScalaGraphX_SQL")
      .master("spark://home:7077")
      .enableHiveSupport()
      .getOrCreate()

    val sc = spark.sparkContext

    val node_pair : RDD[(Array[String],Long)] = sc.textFile(args(0)).map(l=>l.split(" ")).zipWithIndex()

    //set array size
    Tables.tables = new Array[Dataset[Row]](node_pair.count().toInt)

    //insert dataframe inside array tables
    node_pair.collect().foreach{ case (arr,l) => {
        val fields = arr.takeRight(arr.length-2).map(fieldName => StructField(fieldName, BooleanType, nullable = true))
        val schema = StructType(fields)
        val rows = new util.ArrayList[Row]
        Tables.tables{l.toInt} = spark.createDataFrame(rows, schema)
        //val f =
      }
    }

    //create vertices
    val vertices : RDD[(VertexId,TreeNode)]= node_pair.map{ case (arr,l) => {
      (l,new TreeNode(l,false))
     }
    }

    //create edges
    val edges : RDD[Edge[Boolean]] = node_pair
      .filter{ case (arr,l) => arr(0).toLong != -1}
      .map{ case (arr,l) => Edge(l,arr(0).toLong,true)
      }

    var init_node : TreeNode =  new TreeNode(-1,false)
    val graph = Graph(vertices,edges,init_node)
    val graph_pregel = Pregel(graph,init_node,Int.MaxValue,EdgeDirection.Out)(vProg,sendMsg,merge)

    graph_pregel.vertices.collect().foreach(v => println(v._2.index))
  }

  def vProg(id:VertexId, act: TreeNode, other: TreeNode): TreeNode = {
    println(Tables.tables{act.index.toInt})
    act
  }

  def sendMsg(et : EdgeTriplet[TreeNode,Boolean]) : Iterator[(VertexId, TreeNode)] = {

    if(et.srcAttr.v){
      println(et.srcId + "--->" + et.dstId)
      Iterator((et.dstId,et.srcAttr))
    }else{
      //println(et.srcId + "-/->" + et.dstId)
      Iterator.empty
    }
  }

  def merge(n1:TreeNode, n2:TreeNode): TreeNode = {
    n1
  }
}

object Tables extends Serializable{
  var tables : scala.Array[Dataset[Row]] = null
}

class TreeNode(val index:Long, var v: Boolean) extends Serializable {
}

也许有可能使用RDD访问全局数组?或者有人为此问题提供了其他解决方案?

1 个答案:

答案 0 :(得分:1)

请查看GraphFrames - 它是一个为GraphX提供DataFrame API的软件包。一旦GraphFrame提供了诸如在GraphX中很重要的分区以及API进行更详尽的测试时,它将被考虑包含在Spark中。

对于下面评论中描述的问题,您有一个带节点的DataFrame,即机场:

val airports = sqlContext.createDataFrame(List(
    ("A1", "Wrocław"),
    ("A2", "London"),
    ("A3", "NYC")
)).toDF("id", "name")

ID是唯一的。您可以使用以下结构创建其他DataFrame,即detailsDF: ID | AirPortID | other data。然后你有一对多和一个机场(所以GraphFrame verticle)你在detailsDF中有很多条目。现在您可以查询: spark.sql("select a.name, d.id as detailID from airports a join detailsDF d on a.id = d.airportID");。如果您想在那里存储其他信息,您还可以在Airports DataFrame中拥有多列