2016-03-21 11 views
3

おそらくバグを提出する前にここに提示する。私はSpark 1.6.0を使用しています。スパーク結合が間違った結果をもたらす

これは私が扱っている問題の簡略化されたバージョンです。私はテーブルをフィルタリングして、そのサブセットとメインテーブルで左外部結合を行い、すべての列に一致させようとしています。

私はメインテーブルとフィルタリングされたテーブルに2つの行しか持っていません。私は結果のテーブルがサブセットからの単一の行だけを持つことを期待しています。

scala> val b = Seq(("a", "b", 1), ("a", "b", 2)).toDF("a", "b", "c") 
b: org.apache.spark.sql.DataFrame = [a: string, b: string, c: int] 

scala> val a = b.where("c = 1").withColumnRenamed("a", "filta").withColumnRenamed("b", "filtb") 
a: org.apache.spark.sql.DataFrame = [filta: string, filtb: string, c: int] 

scala> a.join(b, $"filta" <=> $"a" and $"filtb" <=> $"b" and a("c") <=> b("c"), "left_outer").show 
+-----+-----+---+---+---+---+ 
|filta|filtb| c| a| b| c| 
+-----+-----+---+---+---+---+ 
| a| b| 1| a| b| 1| 
| a| b| 1| a| b| 2| 
+-----+-----+---+---+---+---+ 

私はその結果がまったく期待できませんでした。私は第1列を期待したが、第2列は期待しなかった。私はそれがnull安全な平等だと思ったので、私はそれを試してみました。

scala> a.join(b, $"filta" === $"a" and $"filtb" === $"b" and a("c") === b("c"), "left_outer").show 
16/03/21 12:50:00 WARN Column: Constructing trivially true equals predicate, 'c#18232 = c#18232'. Perhaps you need to use aliases. 
+-----+-----+---+---+---+---+ 
|filta|filtb| c| a| b| c| 
+-----+-----+---+---+---+---+ 
| a| b| 1| a| b| 1| 
+-----+-----+---+---+---+---+ 

OK、これは私が期待した結果ですが、警告が表示されないことがあります。ここにその警告に対処する別のStackOverflow質問があります:Spark SQL performing carthesian join instead of inner join

したがって、警告を回避する新しい列を作成します。

scala> a.withColumn("newc", $"c").join(b, $"filta" === $"a" and $"filtb" === $"b" and $"newc" === b("c"), "left_outer").show 
+-----+-----+---+----+---+---+---+ 
|filta|filtb| c|newc| a| b| c| 
+-----+-----+---+----+---+---+---+ 
| a| b| 1| 1| a| b| 1| 
| a| b| 1| 1| a| b| 2| 
+-----+-----+---+----+---+---+---+ 

しかし、ここでも結果は間違っています。 私はヌルに安全な平等チェックをたくさんしています。警告は致命的ではありません。だから私はこれを扱う明確な道筋は見当たりません。

この動作はバグですか?これは予期された動作ですか?期待されるならば、なぜですか?

答えて

4

あなたが予想される動作での使用のいずれかの名前でjoinたい場合:

val b = Seq(("a", "b", 1), ("a", "b", 2)).toDF("a", "b", "c") 
val a = b.where("c = 1") 

a.join(b, Seq("a", "b", "c")).show 
// +---+---+---+ 
// | a| b| c| 
// +---+---+---+ 
// | a| b| 1| 
// +---+---+---+ 

または別名:

val aa = a.alias("a") 
val bb = b.alias("b") 

aa.join(bb, $"a.a" === $"b.a" && $"a.b" === $"b.b" && $"a.c" === $"b.c") 

をあなたにも<=>を使用することができます。

aa.join(bb, $"a.a" <=> $"b.a" && $"a.b" <=> $"b.b" && $"a.c" <=> $"b.c") 

を限り私は、しばらくの間、単純な平等のための特別なケースがあったことを覚えています。だからこそ、警告にもかかわらず正しい結果を得ることができます。

2番目の動作は、まだデータにa.cが残っているという事実に関連するバグのようです。 b.cの前に下流が選択され、評価された条件が実際にa.newc = a.cであるようです。

+1

Nullセーフな等価性の実装がないため(実際にはこれが欲しい)、私は結合を使用しませんでした。 null安全なエイリアスバージョンは、より重い構文でも回避策のようです。 問題のバグを報告します。 – kanielc

+0

あなたはJIRAリンクを使って私にpingを実行できますか? – zero323

+0

ここで作成したJira:https://issues.apache.org/jira/browse/SPARK-14040 – kanielc