Warning

注: 以下の翻訳の正確性は検証されていません。AIPを利用して英語版の原文から機械的に翻訳されたものです。

スタイルガイド

PySparkは、Apache Sparkバックエンドとやり取りしてデータを迅速に処理するためのラッパー言語です。Sparkは、分散ネットワーク上のサーバー間で非常に大きなデータセットを操作することができ、適切に使用されると大きなパフォーマンスと信頼性の利点があります。それは経験豊富なPython開発者にとっても挑戦となります。なぜなら、PySparkの構文はSparkのJVMの遺産に基づいており、したがって、見慣れないコードパターンを実装するからです。

この意見的なPySparkコードスタイルガイドは、私たちが遭遇したPySparkのリポジトリ全体で最も頻繁に再発するトピックに基づいたベストプラクティスと共に、一般的な状況を提示します。

一貫したコードスタイルを強制するために、各メインリポジトリにはPylint ↗が有効になっていて、同じ設定を使用している必要があります。私たちは、このドキュメントに記載されているルールに一致するように、ユーザーのPylintに追加で含めることができるPySpark固有のチェッカー ↗を提供しています。Pythonリポジトリ用の組み込みPylintプラグインに関する詳細は、スタイルチェックの有効化に関するドキュメンテーションを参照してください。

PySparkに固有のことを超えて、クリーンなコードの一般的な慣行はPySparkリポジトリでは重要です。Google PyGuide ↗は良い出発点です。

直接アクセスよりも暗黙的な行選択を優先し、あいまいさを解消するために使用します

優先されるオプションは、より複雑で長く、汚れているように見えるかもしれませんが、それは正確です。実際、F.col()をまったく使用しない方が良いでしょう。ただし、それを使用するか、代替の明示的な選択を行うことが避けられない場合があります。ただし、最初の例よりも第2の例を優先する非常に良い理由があります。

最初のケースのように明示的な列を使用すると、データフレーム名とスキーマがデータフレーム変数に明示的にバインドされます。これは、df1が削除されたり名前が変更されたりすると、参照df1.colAが壊れることを意味します。

対照的に、F.col("colA")は常に操作対象のデータフレームにある"colA"という名前の列を参照します。この場合、dfという名前です。他のデータフレームの状態をまったく追跡する必要はないため、コードがよりローカルになり、「距離のあるスプーキーな相互作用」が発生しにくくなります。これは、デバッグが困難な場合がよくあります。

最初のケースを避けるための他の良い理由:

  • データフレーム変数名が大きい場合、それに関連する式はすぐに扱いにくくなります。
  • 列名にスペースやその他のサポートされていない文字が含まれていて、ブラケット演算子でアクセスが必要な場合、df1["colA"]F.col("colA")と同じくらい書きにくくなります。
  • F.col("prod_status") == 'Delivered'のような抽象的な式を変数に割り当てると、複数のデータフレームで再利用できますが、df.prod_status == 'Delivered'は常にdfにバインドされます。

幸いなことに、通常、F.col()を使用した複雑な式は必要ありません。例外はF.lowerF.upperなどです。そしてこれら ↗

注意事項

一部のコンテキストでは、複数のデータフレームからの列へのアクセスがあり、名前に重複がある場合があります。一般的な例は、df.join(df2, on=(df.key == df2.key), how='left')のようなマッチング式です。このような場合、データフレームを直接参照しても問題ありません。また、データフレームのエイリアスを使用して結合を曖昧にすることもできます(このガイドの結合セクションで詳しく説明しています)。

列を反復処理する代わりにリスト内包表記を使用してください

一般的に、Sparkではforループが非効率的です。これは、Sparkが遅延評価され、一度に1つのforループしか処理しないためです。ループのすべての部分が一度に処理できる場合、実行時間が遅くなる可能性がありますし、ドライバーのメモリ不足エラー(OOM)が発生する可能性があります。データセットのすべての列名を大文字から小文字に変更するには、以下の最初の例(# badとラベル付けされている)の代わりに、リスト内包表記を使用することをお勧めします(# goodとラベル付けされた2番目の例と同様に)。