如何从文件中读取数据作为图形(GraphX)?

How to read data from a file as a Graph (GraphX)?

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

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

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

我正在尝试将其读作图形 (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))

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

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

谁能帮我解决这个问题,或者提供一些可能对我有帮助的资源?

我想有很多版本的解决方案可以写成 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)