web-dev-qa-db-ja.com

Sparkデータフレームは非常に遅い

結合からの少数のレコードで新しいDataFrameを作成しています。

val joined_df = first_df.join(second_df, first_df.col("key") ===
second_df.col("key") && second_df.col("key").isNull, "left_outer")
joined_df.repartition(1)
joined_df.cache()
joined_df.count()

カウント操作を除いて、すべてが高速(1秒未満)です。 RDD変換が開始され、文字通り完了するまでに数時間かかります。スピードアップする方法はありますか?

INFO MemoryStore: Block rdd_63_140 stored as values in memory (estimated size 16.0 B, free 829.3 MB)
INFO BlockManagerInfo: Added rdd_63_140 in memory on 192.168.8.52:36413 (size: 16.0 B, free: 829.8 MB)
INFO Executor: Finished task 140.0 in stage 10.0 (TID 544). 4232 bytes result sent to driver
INFO TaskSetManager: Starting task 142.0 in stage 10.0 (TID 545, localhost, executor driver, partition 142, PROCESS_LOCAL, 6284 bytes)
INFO Executor: Running task 142.0 in stage 10.0 (TID 545)
INFO TaskSetManager: Finished task 140.0 in stage 10.0 (TID 544) in 16 ms on localhost (executor driver) (136/200)
INFO ShuffleBlockFetcherIterator: Getting 0 non-empty blocks out of 200 blocks
INFO ShuffleBlockFetcherIterator: Started 0 remote fetches in 0 ms
INFO ShuffleBlockFetcherIterator: Getting 0 non-empty blocks out of 200 blocks
INFO ShuffleBlockFetcherIterator: Started 0 remote fetches in 0 ms
7
br0ken.pipe

カウント操作を除いて、すべてが高速(1秒未満)です。

これは次のように正当化されます:countの前のすべての操作は変換と呼ばれ、このタイプのspark操作は遅延します。つまり、アクション(例ではcount)を呼び出す前に計算は行われません)。

2番目の問題はrepartition(1)にあります。

sparkによって提供されるすべての並列処理が失われ、計算が1つのエグゼキューター(スタンドアロンモードの場合はコア)で実行されるため、このステップを削除するか変更する必要があることに注意してください。 1は、CPUコアの数(スタンドアロンモード)またはエグゼキューターの数(クラスターモード)の命題です。

RDD変換が開始され、文字通り完了するまでに数時間かかります。

DataFrameRDDに変換することを正しく理解している場合、これは実際にはsparkでの悪い習慣であり、できる限りこのような変換を避ける必要があります。これは、DataFrameDataset特別なsparkエンコーダー(よく覚えていればタンススタントと呼ばれます)を使用してエンコードされるため、JVMシリアライゼーションエンコーダーよりもメモリの消費量が少ないため、このような変換は= sparkはあなたのデータのタイプを彼自身のものから変更します(それははるかに少ないメモリを必要とし、spark optimizeエンコードされたデータを処理し、処理するためにデータをシリアル化せずにデータを逆シリアル化しないことにより、多くの交換が行われます)JVMデータ型にこのため、DataFramesとDatasetsはRDDsよりも非常に強力です

これがあなたを助けることを願っています

22

他の人が述べたように、countの前の操作は「遅延」で、実際には強制的に計算ではなく変換を登録のみです。

countを呼び出すと、計算がトリガーされます。これはSparkがデータを読み取り、以前に登録されたすべての変換を実行し、要求した結果(この場合はcount)を計算するときです。

RDD変換が開始され、文字通り完了するまでに数時間かかる

「変換」という言葉はおそらく少し不正確だと思います。実際に起こっていることは、登録したDataFrame変換がRDDオペレーションに変換され、これらがDataFrameの基礎となるRDDに適用されることです。ここで指定したコードには変換はありませんper se

余談ですが、DataFrame.rddプロパティを介してDataFrameRDDに明示的に変換することが可能です。 この答え で述べたように、適切に構造化されたデータを持つことで(パフォーマンスとAPIの両方で)いくつかの利点が失われるため、これは一般に悪い考えです。

1
timchap