PySparkとSparkSQLは組織のどこに最もフィットするのか

[Where PySpark and SparkSQL Fit Best in the Enterpr\.\.\. \- Databricks Community \- 111021](https://community.databricks.com/t5/technical-blog/where-pyspark-and-sparksql-fit-best-in-the-enterprise/ba-p/111021)の翻訳です。

:::note warn
本書は著者が手動で翻訳したものであり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
:::

# 1. 文脈

データアーキテクチャを構築する際によくある質問は: データエンジニアはブロンズ/シルバーレイヤーでPySparkを使い、データアナリストはシルバー/ゴールドレイヤーでSparkSQLに頼るべきか？ということです。

表面上はこの分割は合理的なものであり、PySparkは複雑な変換処理のためのパワフルなものでありますが、SparkSQLはアナリストにとってよりシンプルで宣言型のインタフェースを提供します。しかし、このように結論づける前に2つの主要な要素を検討すべきです:

 - パフォーマンス: SparkSQLとPySparkの間には実行スピードにおいて特筆すべき違いがあるのか？
 - 機能: PySparkにはSparkSQLにはない機能があるのか？

このブログでは、品質とアクセシビリティを改善するためにデータをブロンズ、シルバー、ゴールドに整理する[メダリオンアーキテクチャ](https://docs.databricks.com/aws/ja/lakehouse/medallion)におけるすべて、Databricks環境における異なるペルソナに対するベストなアプローチを決定する助けとなるように、これらの質問にダイブします。

# 2. SparkSQLとPySparkデータフレームAPIのパフォーマンスの違い

SparkSQLとPySparkデータフレームAPIの両方は同じCatalystオプティマイザを活用し、同じクエリーに対して同じ実行計画を生成します。これは、理論上は2つのAPIに固有のパフォーマンスの違いがないことを意味します。しかし、いくつかの実践的な要因が受容するパフォーマンスに影響を与えることがあります:

1. オペレーションの表現:
    1. パフォーマンスの違いはAPI自身によるものではなく、変換処理をどのように表現するのかによります。
    1. 貧弱に構造化されたPySparkデータフレームのオペレーション(不必要な`.collect()`、ビルトインの関数ではなくPython UDFを使うなど)はパフォーマンスに影響を与えることがあります。
    1. 同様に、非効率的なSQLクエリー(joinではなく複雑なサブクエリーなど)は最適化されていない実行計画につながることがあります。
1. 宣言型 vs. 命令型の特性:
    1. SQLはオプティマイザが初期段階で意図を推定し、より効率的に最適化をかけられるようにする純粋に宣言型となります。
    1. PySparkデータフレームAPIはより命令型であり、開発者が自身の変換処理を最適に構造化しない場合には、非効率性を導入することがあることを意味します。
1. 受容するパフォーマンスの違い:
    1. 一般的に、データフレームのオペレーションは本来SQLよりも遅いとは受け止められていません。
    1. 主な違いは基盤となるAPIの制限ではなく、開発者がどのように自分のクエリーを記述するのかによります。

**サマリー**

同じ変換処理意においては、SparkSQLとPySparkデータフレームAPIは同じように動作します。これらの選択配下に基づくべきです:

- 個人的な好み
- 複雑な変換処理の表現しやすさ
- 他のツールとのインテグレーション(MLワークフローでのPython、アナリストフレンドリーなクエリーのためのSQLなど)

# 3. SparkSQLとPySparkの機能の違い

両方のAPIは同じ実行エンジンを共有しますが、使いやすさ、柔軟性、テスト機能では大きな違いがあります。

| 機能 | PySparkデータフレームAPI | SparkSQL |
|:--|:--|:--|
| 実行エンジン  | ✅ Catalystオプティマイザを使用  | ✅ Catalystオプティマイザを使用  |
| パフォーマンス  | 	🔄 ロジックが同じならSparkSQLと同じ  | 🔄 ロジックが同じならPySparkと同じ  |
| ユニットテスト  | ✅ サポート(pytest、unittest、データフレームのモックなど)  |  ❌ 直接のサポートは無し(SQLクエリーを分離してテストすることは困難) |
| コードの再利用  |  ✅ Pythonで再利用可能な変換処理関数を記述可能 | ❌ SQLクエリーはモジュール化しにくく、再利用は困難  |
| エラー対応&デバッグ  | ✅ Pythonの例外対応で簡単  | ❌ SQLのエラーのデバッグは限定的なスタックトレースのために困難な場合あり  |
| 複雑な変換処理  | ✅ 簡単(UDF、ループ、ビジネスロジックなど)  | ❌ 純粋なSQLでの表現は困難  |
| 相互運用性  |  ✅ 外部Pythonライブラリと連携可能(ML、Pandasなど) | ❌ Spark SQL関数に限定  |
| パフォーマンスの最適化  | 🔄 同等だが、データフレームはパーティショニングやキャッシュを通じたさらなるコントロールを提供  | 🔄 同等だが、SQLではオプティマイザが意図を早期に推定可能  |

# 4. 現実世界での利用における追加の検討事項

- SQLでのユニットテスト: SQLは分離したユニットテストが困難なので、SQLベースの変換処理に過度に依存している組織は、SQLのユニットテストを探索しなくてはなりません。例には以下のようなものがあります:
    - Dbt-ユニットテスト
    - Databricks SQLコネクタとpytest。
    - [DQX](https://databrickslabs.github.io/dqx/docs/guide/)は、あなたのデータパイプラインにおけるデータ品質問題を定義、監視、対応できるようにするための、Apache Spark用データ品質フレームワークです。
- ハイブリッドアプローチ: SparkSQLは可読性とアナリスト支援の観点から好まれますが、複雑な変換処理においては([こちら](https://medium.com/@j.wang.mlds/how-to-make-a-python-function-a-spark-sql-function-1f70be14ee0a)で説明されているようにSparkSQLの中でPython UDFを登録するなどして)SparkSQLの中からPython関数を用いて対応することができます。
- 同時実行性: 複数のユーザーが同じようなクエリーを実行するなど、あなたのワークロードでより多い同時実行性を必要とする場合、Databricks SQL(DBSQL)がもっとも効率的な選択肢となります。しかし、ETLスタイルのワークロードにおいては、ジョブクラスターの方がフィットする可能性が高いです。両方の選択肢ではPhotonをサポートしており、データ変換におけるコスト効率性を改善し、クエリーのパフォーマンスを向上します。
- アナリストの支援: 組織は、ETLでSparkSQLを使うことが透明性を高めることに気づきました。アナリストはPythonの知識を必要としなくても、ジョブでどのような変換処理が行われているのかを追跡することができ、ETLロジックに関する毎日の問い合わせを減らすことができます。

# 5. まとめ

- データエンジニア(ブロンズ→シルバー): ユニットテスト能力、優れたデバッグツール、変換処理の柔軟性からPySparkが好ましいです。
- データアナリスト(シルバー→ゴールド): SQLに慣れたアナリストが使いやすく、パフォーマンスが同等のSparkSQLが自然にフィットします。
- メンテナンス性 & テスト可能性: PySparkが優れた選択肢となります。
- アドホック分析 & 可読性: SparkSQLが理想的です。

究極的には、組織は変換処理ロジックのためのPySparkのパワーと、分析と発見のためのSparkSQLのアクセシビリティのバランスをとったハイブリッドアプローチを活用することができます。現実世界のワークロードの評価、コストの示唆、開発者のスキルセットが、Databricks環境における最適な選択肢のガイドとなることでしょう。

### はじめてのDatabricks

[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)