2016-04-13 15 views

答えて

3

としては、この質問に対するコメントで指摘していない、どちらもGraphFramesもGraphXが内蔵されている二部グラフのためのサポート。しかし、どちらも、2部グラフを作成するのに十分な柔軟性を備えています。 GraphXソリューションについては、this previous answerを参照してください。このソリューションは、異なる頂点/オブジェクトタイプ間で共有された特性を使用します。そして、それはRDDsで動作しますが、それはDataFramesでは動作しません。 DataFrameの行には固定スキーマがあります。時にはprice列を含むことはできません。 price列を持つこともできますが、その列は時々nullですが、列はすべての行に存在する必要があります。

代わりに、GraphFramesのためのソリューションを使用すると、基本的にあなたの二部グラフ内のオブジェクトの両方のタイプのリニアサブタイプですDataFrameを定義する必要があることのようです - それは、両方のタイプのすべてのフィールドを含んでいなければなりませんオブジェクト。これは実際にはかなり簡単です - joinfull_outerはあなたにそれを与えるつもりです。このような何か:

val players = Seq(
    (1,"dave", 34), 
    (2,"griffin", 44) 
).toDF("id", "name", "age") 

val teams = Seq(
    (101,"lions","7-1"), 
    (102,"tigers","5-3"), 
    (103,"bears","0-9") 
).toDF("id","team","record") 

あなたは、このようなスーパーセットDataFrameを作成することができます。

val teamPlayer = players.withColumnRenamed("id", "l_id").join(
    teams.withColumnRenamed("id", "r_id"), 
    $"r_id" === $"l_id", "full_outer" 
).withColumn("l_id", coalesce($"l_id", $"r_id")) 
.drop($"r_id") 
.withColumnRenamed("l_id", "id") 

teamPlayer.show 

+---+-------+----+------+------+ 
| id| name| age| team|record| 
+---+-------+----+------+------+ 
|101| null|null| lions| 7-1| 
|102| null|null|tigers| 5-3| 
|103| null|null| bears| 0-9| 
| 1| dave| 34| null| null| 
| 2|griffin| 44| null| null| 
+---+-------+----+------+------+ 

あなたはおそらくstructsでそれを少しクリーナーを行うことができ:

val tpStructs = players.select($"id" as "l_id", struct($"name", $"age") as "player").join(
    teams.select($"id" as "r_id", struct($"team",$"record") as "team"), 
    $"l_id" === $"r_id", 
    "full_outer" 
).withColumn("l_id", coalesce($"l_id", $"r_id")) 
.drop($"r_id") 
.withColumnRenamed("l_id", "id") 

tpStructs.show 

+---+------------+------------+ 
| id|  player|  team| 
+---+------------+------------+ 
|101|  null| [lions,7-1]| 
|102|  null|[tigers,5-3]| 
|103|  null| [bears,0-9]| 
| 1| [dave,34]|  null| 
| 2|[griffin,44]|  null| 
+---+------------+------------+ 

私は」また、GraphXでは、同じソリューションがRDDsで動作することを指摘しています。あなたはいつもどのtraits共有していない2 case classesに参加を経由して頂点作成することができます: - 共有することなく、前の回答にすべてに関して

case class Player(name: String, age: Int) 
val playerRdd = sc.parallelize(Seq(
    (1L, Player("date", 34)), 
    (2L, Player("griffin", 44)) 
)) 

case class Team(team: String, record: String) 
val teamRdd = sc.parallelize(Seq(
    (101L, Team("lions", "7-1")), 
    (102L, Team("tigers", "5-3")), 
    (103L, Team("bears", "0-9")) 
)) 

playerRdd.fullOuterJoin(teamRdd).collect foreach println 
(101,(None,Some(Team(lions,7-1)))) 
(1,(Some(Player(date,34)),None)) 
(102,(None,Some(Team(tigers,5-3)))) 
(2,(Some(Player(griffin,44)),None)) 
(103,(None,Some(Team(bears,0-9)))) 

を、これはそれを処理するために、より柔軟な方法のように思えますtraitを組み合わせたオブジェクトです。

関連する問題