型付きデータセットをフィルタリングするさまざまな方法を実験してきました。パフォーマンスはかなり異なる可能性があることがわかりました。
データセットは、33列と4226047行の1.6GB行のデータに基づいて作成されました。 DataSetは、csvデータをロードすることによって作成され、ケースクラスにマップされます。
val df = spark.read.csv(csvFile).as[FireIncident]
UnitId = 'B02'のフィルターは、47980行を返す必要があります。私は以下の3つの方法をテストしました:1)型付き列を使用する(ローカルホストで約500ミリ秒)
df.where($"UnitID" === "B02").count()
2)一時テーブルとSQLクエリを使用します(〜オプション1と同じ)
df.createOrReplaceTempView("FireIncidentsSF")
spark.sql("SELECT * FROM FireIncidentsSF WHERE UnitID='B02'").count()
3)強い型のクラスフィールドを使用します(14,987ms、つまり30倍遅い)
df.filter(_.UnitID.orNull == "B02").count()
python APIを使用して再度テストしました。同じデータセットの場合、タイミングは17,046ミリ秒で、scala APIオプション3のパフォーマンスに匹敵します。
df.filter(df['UnitID'] == 'B02').count()
誰かが3)とpython APIが最初の2つのオプションとは異なる方法で実行される方法に光を当てることができますか?
これはステップ3のせいです ここ 。
最初の2つでは、spark Java/Scalaオブジェクト全体を逆シリアル化する必要はありません。1つの列を調べて次に進みます。
3番目では、ラムダ関数を使用しているため、sparkは、1つのフィールドだけが必要かどうかわからないため、各行の33個のフィールドすべてをメモリから引き出します。 1つのフィールドを確認できます。
4番目がなぜそんなに遅いのかわかりません。最初と同じように機能するようです。
python)を実行すると、最初にコードがJVMにロードされて解釈され、最後にバイトコードにコンパイルされます。Scala APIを使用する場合、ScalaはJVMでネイティブに実行されるため、JVM部分への負荷pythonコード全体を切り取っています。