如何以Graph(GraphX)形式从文件中读取数据?

时间:2019-04-22 02:00:19

标签: scala apache-spark spark-graphx

我是Scala的新手,正在尝试从文本文件中将无向图读取为Graph(GraphX)。文本文件的格式为:

1,8,9,10
2,5,6,7,3,1

表示节点1连接到节点8,9和10(邻接列表),节点2连接到节点5,6,7,3,1。

我正在尝试将其读为Graph(GraphX)

我正在尝试使用fromEdge [VD,ED]方法(GraphX)完成此操作,在这里我必须传递成对的边缘。

 val graph = sc.textFile("Path to file").map(line=>line.split(",").map(line=>line.toLong)).map{case Array(a,z @ _*)=>(z.map(m=>(a,m) ))}

这给了我

Vector((1,8), (1,9), (1,10))
Vector((2,5), (2,6), (2,7), (2,3), (2,1))

由于图形属于单位类型,因此不能与fromEdge方法(GraphX)一起使用。

我无法找出一种方法来从这些边缘制造边缘。 有更好的方法吗?

有人可以帮我这个忙吗,或者为我提供一些可以帮助我的资源?

1 个答案:

答案 0 :(得分:0)

我想可以用Spark / Scala编写解决方案的许多版本,以从您指定的文件格式加载图形。

以下是使用RDD的动态解决方案的示例:

// Loading sample data
scala> val graphData = sc.parallelize(Seq("1, 8, 9, 10", "2,5,6,7,3,1"))
graphData: org.apache.spark.rdd.RDD[String] = ParallelCollectionRDD[5]

// Trim whitespaces and map the String into an Array[Long]
scala> val graphList = graphData.map( x => {
     |    x.replace(" ", "").split(",").map(_.toLong)
     | })
graphList: org.apache.spark.rdd.RDD[Array[Long]] = MapPartitionsRDD[6]

// Here is how graphList looks like now
scala> graphList.collect
res11: Array[Array[Long]] = Array(Array(1, 8, 9, 10), Array(2, 5, 6, 7, 3, 1))

// Generating edges by crossProduct element(0) with the rest of Array elements
scala> val edges = graphList.flatMap(x => x.drop(1).map(y => (x(0), y) )).map(x => Edge(x._1, x._2, "attr"))
edges: Array[org.apache.spark.graphx.Edge[String]] = Array(Edge(1,8,attr), Edge(1,9,attr), Edge(1,10,attr), Edge(2,5,attr), Edge(2,6,attr), Edge(2,7,attr), Edge(2,3,attr), Edge(2,1,attr))

// Generating vertices, and adding name/attr for each vertex
scala> val vertices = graphList.flatMap(x => x).map(x => (x, ("name", "attr"))).distinct.sortBy(x => x)
vertices: org.apache.spark.rdd.RDD[(Long, (String, String))] = MapPartitionsRDD

//A default value is defined in case a connection or vertex is missing; the graph is then constructed from the RDD-based structures vertices and edges and the default record:
val default = ("Unknown", "Missing")

// Finally, declare your Graph
scala> val graph = Graph(vertices, edgesRDD, default)
graph: org.apache.spark.graphx.Graph[(String, String),String] = org.apache.spark.graphx.impl.GraphImpl@8097e8f

// Checking how vertices look like
scala> graph.vertices.collect
res26: Array[(org.apache.spark.graphx.VertexId, (String, String))] = Array((8,(name,attr)), (1,(name,attr)), (9,(name,attr)), (10,(name,attr)), (2,(name,attr)), (3,(name,attr)), (5,(name,attr)), (6,(name,attr)), (7,(name,attr)))

注意,您还应该考虑分区(用于并行性)和缓存(顶点,边缘)以进一步优化作业。

构造图的更好方法

GraphFrames现在是GraphX的更好替代品,得益于DataFrames的可伸缩性和高性能。

我鼓励您阅读并尽可能使用它。

一种更原始​​的格式,用于表示GraphX或GraphFrames的图形

作为示例,这是一个仅包含六行的顶点文件。每个顶点代表一个人,并具有一个顶点ID号,一个名称和属性,在这种情况下为年龄值:

1,Mike,48
2,Sarah,45
3,John,25
4,Jim,53
5,Kate,22
6,Flo,52

另一个边缘文件包含一组有向边缘值,其形式为源顶点ID,目标顶点ID和关系。因此,记录1在Flo和Mike之间形成了姐妹关系:

6,1,Sister
1,2,Husband
2,1,Wife
5,1,Daughter
5,2,Daughter
3,1,Son
3,2,Son
4,1,Friend
1,5,Father
1,3,Father
2,5,Mother
2,3,Mother

现在您的代码将变得简单:

val vertex = spark.read.option("header","true").load("csvgraph1_vertex.csv")
val edges = spark.read.option("header","true").load("csvgraph1_edges.csv")
val graph = GraphFrame(vertex, edges)

更新

GraphFrames与GraphX集成

GraphFrames通过两种表示形式之间的转换与GraphX完全集成,而没有任何数据丢失。我们可以将图转换为GraphX图,再转换回GraphFrame。

val gx: Graph[Row, Row] = g.toGraphX()
val g2: GraphFrame = GraphFrame.fromGraphX(gx)