データベース

Apache Beamとは|バッチとストリームを同じコードで書く仕組みとランナー選定の判断基準

Apache Beamは、有限データのバッチ処理と無限データのストリーミング処理を1つのプログラミングモデルで記述し、実行エンジン(ランナー)を差し替えて動かすためのOSSです。最新版は2.75.0で、2026年7月8日に公開されました。この記事では、PCollectionとPTransformという中核の抽象、無限データを区切るウィンドウとトリガーの設計、Java・Python・Go・YAMLで実装できる範囲の差、そしてPrism・Flink・Spark・Dataflowのどれで動かすかの判断基準を扱います。移植性という売り文句が実務でどこまで通用するかを、見送るべき条件まで含めて整理します。

まとめ|Beamの採否条件とランナー選定・SDK言語の結論

Beamが効くのは、実行基盤を将来的に乗り換える可能性がある案件と、バッチとストリーミングを同じ処理ロジックで回したい案件に限られます。1つのエンジンで完結し乗り換えの予定もないなら、そのエンジンのネイティブAPIを直接書いたほうが速い。抽象化の層を1枚増やす費用を移植性が上回るかが分かれ目です。

SDKはJavaかPythonの二択で考えてください。Go SDKはコントリビュータ不足によりバグ修正中心だと公式ロードマップに明記されており、新規案件で選ぶ理由がありません。ランナーは、ローカル検証をPrism、本番をマネージドのDataflowかセルフホストのFlinkという組み合わせが標準形です。ただしPrismはOrderedListStateやカスタムウィンドウが未対応で、ローカルで通ったから本番でも通るという前提は置けません。

版の管理は依存ライブラリと同じ厳密さで扱ってください。直近のリリース間隔は30〜36日で、Flinkのサポート版も入れ替わります。2.75.0ではFlink 2.1・2.2への対応が入り、1.17・1.18が外れました。Java 8はdeprecated扱いで、Beam 3.0.0での削除も公表済みです。

PCollectionとPTransformで組み立てるBeamの処理モデルの基本構造

Beamのコードは、データを表す型と変換を表す型の2つだけで組み上がります。

有限データと無限データをPCollectionで同一に扱う抽象化の中身

PCollectionは、パイプラインが扱うデータ集合を表す型です。要素数が確定した有限データ(bounded)と、終わりが来ない無限データ(unbounded)を同じ型で表します。ファイルを読んだ結果も、メッセージキューを購読し続けた結果も、コード上は同じPCollectionです。

この統一があるため、日次バッチとして書いた集計処理を、入力を差し替えるだけでストリーミングに転換できます。差分は後述するウィンドウとトリガーの指定だけ。両者の処理モデルそのものの違いはストリーム処理の仕組みとバッチ処理との使い分けで扱っています。

ParDoとGroupByKey・Combineが担う変換処理の役割分担

PTransformは、PCollectionを受け取ってPCollectionを返す変換の単位です。日常的に書くのは次の4つに集約されます。

  • ParDo:要素ごとに処理を適用する。0件でも複数件でも出力でき、フィルタも展開もここで書く
  • GroupByKey:キー単位でまとめる。無限データではウィンドウ境界が確定するまで結果が出ない
  • Combine:合計や最大値のように結合可能な集約を行う。GroupByKeyより通信量が減る
  • Flatten:複数のPCollectionを1本に統合する

まず押さえるべきはCombineとの使い分けです。集約をGroupByKeyParDoで書くと同一キーの全要素が1ワーカーへ集まり、キーの偏りが大きいデータでは処理時間の大半をここが占めます。結合可能な集約ならCombineを選んでください。

パイプライン記述が実行計画へ変換されランナーへ渡るまでの内部処理

実装者が書いたコードは、その場で実行されません。SDKはコードを読み取って有向非巡回グラフ(DAG)を組み立て、ランナーに渡します。並列度やワーカー配置を決めるのはランナー側です。ポータビリティフレームワークの対応先は、Dataflow・Flink・Jet・Nemo・Prism・Spark・Twister2です。

裏を返せば、実行時の挙動を細かく制御したい場面ではこの分離が制約になります。ワーカー数や再試行の挙動はランナー固有のオプションで指定することになり、その部分は移植できません。バッチ層と速度層を別建てにするLambdaアーキテクチャの構成と比べると、Beamは両層のロジックを1本へ寄せる代わりに実行制御をランナーへ委ねる設計です。

無限データを扱うウィンドウとウォーターマーク・トリガーの設計判断

ストリーミングでBeamを使うとき、実装の難所はここに集中します。ウィンドウとトリガーの設定を誤ると、結果が出ない、あるいは重複して出ます。

固定・スライディング・セッションの各ウィンドウを選ぶ際の判断基準

ウィンドウは、終わりのないデータを集計可能な単位へ区切る仕組みです。既定では全要素が1つのグローバルウィンドウに入るため、無限データにGroupByKeyを適用しても結果が確定しません。5分ごとの件数のように区間が重ならない集計は固定ウィンドウ、直近1時間の移動平均のように区間を重ねるならスライディングウィンドウ、操作が途切れるまでを1単位とするならセッションウィンドウで無操作の許容時間を指定します。

スライディングウィンドウでは1要素が複数ウィンドウに属します。ウィンドウ長1時間・スライド幅1分なら、1要素が60個のウィンドウで数えられます。出力量と状態サイズが同じ倍率で膨らむため、書き込み先の想定と合わせて幅を決めてください。

ウォーターマークの進み方と遅延データに対するトリガー設定の指針

ウォーターマークは、「この時刻より前のデータはもう来ないだろう」というシステム側の推定値です。ウィンドウの終端を越えた時点で、そのウィンドウの結果が出力されます。問題になるのは推定が外れて遅れて届くデータで、Beamでは到達前に途中結果を出す早期トリガー、到達後の遅延データで再出力する遅延トリガー、遅延データを何日分受け付けるかを決める許容遅延(allowed lateness)を個別に指定できます。

再出力のたびに前回結果へ足し込むか置き換えるかは、アキュムレーションモードで選びます。書き込み先が同一キーの上書きに耐えるなら置き換え、追記しかできないなら足し込みにして重複排除を下流に持たせてください。許容遅延は長いほど状態を保持し続けます。1時間で足りるところに7日を設定すれば、状態ストアが不要に膨らむ。

State APIとTimerで書く要素単位の状態管理と再処理時の注意点

ウィンドウとトリガーで表現しきれない制御は、State APIとTimerで書きます。キーごとに値を保持し指定時刻に処理を起動する仕組みで、「同一ユーザーの直前イベントと比較する」「一定件数たまるまで待って一括送信する」といった要件が該当します。

ランナー依存が最も強く出るのがこの領域です。PrismではOrderedListStateやループタイマー、GroupIntoBatchesが使うOnWindowExpiryが未対応で、処理時間タイマーも実時間では動きません。State APIを使う設計を選んだ時点で、ローカル検証と本番実行の等価性は保証されなくなる。本番と同じランナーでの検証環境を別に用意してください。

Java・Python・Go・YAMLで分かれるSDK成熟度と言語選定の基準

Beamは複数言語のSDKを提供していますが、機能の充実度は横並びではありません。

Java SDKが先行しPython SDKが追う機能差の現状と選定への影響

新機能はJava SDKから入るのが通例です。2.75.0でもDelta Lakeの読み取り対応はJava、Dataflow Streaming Engineの新規ジョブに対する状態タグエンコーディングv2の既定化もJavaで、Python側はMemrayによるメモリプロファイリング対応とQdrant向け書き込み設定の追加でした。公式が対応を明示するJavaの版は8・11・17・21・25ですが、Java 8はdeprecated扱いのため、新規に組むなら17以上を選んでください。

Python SDKを選ぶ判断が成り立つのは、前処理から機械学習の推論までを同じ言語で通したい場合です。逆に、必要なI/Oコネクタが未提供だと判明した時点で、次に説明するクロス言語変換に頼ることになります。

Go SDKがバグ修正中心となった経緯と新規採用を避ける際の判断

Go SDKについて、公式ロードマップは「コントリビュータ不足のため、バグ修正を超える開発は積極的に行われていない」と明記しています。停止ではないものの、新機能が追随する前提は置けません。

それでもGoを選ぶ余地があるのは、既存システムがGoで統一され、処理が基本的な変換と定番コネクタで収まる場合だけ。State APIやクロス言語変換を使う想定があるなら避けてください。

コードを書かずに組むBeam YAMLの適用範囲と安定性の見方

Beam YAMLは、パイプラインをYAMLの宣言だけで記述する方式です。公式ドキュメントは「Beam YAMLは開発途上だが、すでに含まれている機能は安定とみなす」と述べています。収録済みの変換で要件が満たせるかで判断してください。パーサはPython SDKに同梱され、pip install apache_beam[yaml,gcp] で導入します。2.75.0ではMongoDBとDatadogへの書き込み変換が加わりました。

避けるべきなのは、要素単位の分岐ロジックが業務要件の中心にある場合です。YAMLに条件式を積み上げるより、ParDoで書いてテストを当てるほうが読みやすい。

クロス言語変換でJava製コネクタをPythonから呼ぶ実装の勘所

クロス言語変換は、あるSDKで実装された変換を別のSDKのパイプラインから呼び出す仕組みです。JavaのI/OコネクタをPythonから使う、Beam SQLをGoから使うといった用途が想定されており、Python SDKにコネクタが無い場面での回避策になります。

ただし実行時の構成は複雑になります。呼び出される側のSDKハーネスが別プロセスとして起動するため、コンテナイメージの用意とネットワーク到達性が前提に加わります。ローカルで動いた構成がそのまま本番へ移らない典型例です。採用するなら、検証の初期段階で本番相当のランナー上での起動確認まで済ませてください。

PrismとFlink・Spark・Dataflowのランナー選定と機能差の見極め

「どのランナーでも同じコードが動く」は、正確には「同じコードを渡せる」であって「同じ挙動になる」ではありません。

ローカル検証をPrismで行う際の未対応機能と切り分けの実務手順

Prismは、Goで実装された可搬な実行エンジンで、Go SDKの既定ランナーです。他のSDKからも指定でき、静的にコンパイルされた単一バイナリとWeb UIを備えます。公式が挙げる未対応機能は具体的で、OrderedListStateOnWindowExpiry、カスタムウィンドウ、マージ可能なウィンドウ関数、トリガー関連機能、バンドル確定処理、ループタイマーが並びます。

切り分けは、ローカルで失敗したときに「実装のバグ」と「Prismの未対応」を分けることから始めます。上記に触れる機能を使っているなら、本番と同じランナーで再現するかを先に確認してください。ここを飛ばすと、存在しないバグを追う時間が積み上がります。

自前運用のFlink・Sparkとマネージド実行の運用コスト比較

本番ランナーの選択は、クラスタを自前で持つかどうかで決まります。

ランナー 運用形態 向く条件 留意点
Dataflow マネージド GCP中心の構成 実行基盤がGCP固定
Flink 自前または各社基盤 低遅延と細かな制御 対応版が版ごとに変動
Spark 既存クラスタ流用 バッチ資産が既にある 実行系が2系統に分岐
Prism ローカル単一バイナリ 開発時の検証 未対応機能が残る

Flinkを選ぶ場合、Beam側の対応版を必ず確認してください。2.75.0でFlink 2.1・2.2の対応が加わり、1.17・1.18のサポートが外れました。実行エンジンとしての特性はApache Flinkのリアルタイム処理エンジンとしての特徴で扱っています。マネージド実行の料金内訳やオートスケーリングの挙動はCloud DataflowによるBeamパイプラインの実行と課金の仕組みにまとめました。

ランナー移植で壊れる箇所とCapability Matrixの読み方

公式のRunner Capability Matrixには、Dataflow、Prism、Flink、Spark(RDD・DStream系とStructured Streaming系の2系統)、Nemo、Hazelcast Jet、Twister2、PythonのDirect FnRunnerが並びます。同じSparkでも実行系が2つに分かれている点が、移植時の注意箇所です。

移植で壊れやすいのは、決まってウィンドウ・トリガー・状態管理の周辺です。基本的なParDoCombineだけのパイプラインは移りますが、遅延データの再出力やキー単位の状態を使い込むほど、対応状況の差が表面化します。移植性を前提に設計するなら、State APIとカスタムウィンドウの使用を意識的に絞ってください。

2.75系のリリース周期とBeam 3.0移行を見据えた版固定の運用

Beamはコンパイラや言語ランタイムほど版が安定していません。更新の見通しを運用計画に織り込む必要があります。

2.71から2.75まで30日前後で刻むリリース間隔と追随の方針

直近5回の公開日は、2.71.0が2026年1月22日、2.72.0が3月30日、2.73.0が4月29日、2.74.0が6月2日、2.75.0が7月8日です。2.72.0以降の間隔は30日・34日・36日で、月1回のペースに収まっています。

この頻度に毎回追随する必要はありません。本番の版を固定し、四半期に1度まとめて上げる形が実務的です。ただし破壊的変更の欄だけは毎回確認してください。2.75.0ではPythonでdataclassのフィールド型ヒントが型推論に反映されるようになり、既存パイプラインの型指定によっては修正が要ります。

Beam 3.0でのJava 8削除とPython対応範囲を踏まえた更新計画

公式ロードマップは、Java 8のサポートがdeprecatedであり、Beam 3.0.0で削除予定であることを明記しています。Java 8のまま運用しているパイプラインは、メジャー更新の時点で動かなくなる前提で計画を組んでください。順序としては、Beamの版を上げる前にJavaの実行環境を17以上へ移すのが安全です。同時に行うと原因の切り分けができません。

Python SDKの対応範囲は、2.69.0時点で3.9から3.13です。3.14への対応は予定に留まるため、新しいPythonへ先に移行するとBeam側が追いつくまで動かせません。要件定義の段階で、Pythonの版・Beamの版・主要ライブラリの版を1つの表に落として合意しておいてください。

Apache Beamを採用する条件と見送るべき場面の切り分け基準

ここまでの内容を採否の判断に落とします。条件を付けて言い切ります。

単一エンジンで完結する処理にBeamを持ち込まない方がよい条件

次の3つに当てはまるなら、Beamを採用しないでください。第1に、処理が1つのエンジンで完結し乗り換えの計画も無い場合。抽象化の層が増える分だけデバッグ経路が長くなります。第2に、ストリーミング要件が無く日次のバッチ集計だけで足りる場合。SQLとワークフローエンジンの組み合わせのほうが軽く済みます。

第3に、State APIとカスタムウィンドウを多用する設計になった場合。この領域はランナーごとの対応差が最も大きく、移植性という採用理由が実質的に消えます。そこまで作り込むなら、対象エンジンのネイティブAPIを直接書いてください。

移植性と実行基盤の乗り換え可能性がBeam採用を正当化する場面

採用が正当化されるのは、実行基盤が動く前提の案件です。オンプレミスのSparkクラスタからマネージド実行へ段階移行する、複数クラウドで同じ集計を回す、受託案件で発注元の基盤方針が確定していない、といった状況が該当します。処理ロジックを基盤から切り離しておけば、移行時に書き直す範囲が入出力とランナーオプションに限定されます。

もう1つの適用場面が、バッチとストリーミングの二重実装を避けたい要件です。同じ集計ロジックを日次バッチとリアルタイム処理の両方で持つと、仕様変更のたびに2箇所を直すことになり、結果の食い違いが起きます。Beamなら入力と窓の指定だけを差し替えて両方へ回せる。この効果は、集計ロジックが複雑で改修頻度が高いほど大きくなります。

受託開発でBeamパイプラインを引き継ぐ際の設計要件と体制の条件

受託でBeamを納める場合、引き継ぎ可能性を設計要件に含めてください。State APIとカスタムウィンドウの使用箇所を一覧化する、ランナー固有オプションを設定ファイルへ外出しする、Beam・Java(またはPython)・主要ライブラリの版を明記する、の3点です。これが揃っていないパイプラインは、保守担当が代わった時点で版を上げられなくなります。

体制面の条件は、発注側にランナーを運用できる人員がいるかどうかです。いないならマネージド実行を前提に設計し、セルフホストのFlinkは選ばない。曖昧なまま納品すると、クラスタの障害対応が誰の担当でもない状態になります。データ収集から変換、機械学習の推論までを含む基盤の設計と運用体制の整理はデータ分析基盤構築・MLOps構築支援で承っており、ランナー選定と保守分担もこの段階で決めておくと後の手戻りが減ります。

よくある質問

Apache Beamの採用検討で、実務からよく挙がる質問をまとめました。

Apache BeamとCloud Dataflowはどう使い分けますか?

役割が異なり、二択の関係にはありません。Beamはパイプラインを記述するプログラミングモデルとSDKで、Cloud DataflowはそのパイプラインをGoogle Cloud上で実行するランナーの1つです。BeamのコードはFlinkやSpark、ローカルのPrismでも動かせます。論点は「Beamを使うか」と「どのランナーで動かすか」の2段階に分けてください。

Apache BeamとApache Flinkは競合する関係ですか?

競合ではなく、層が違います。Flinkはストリーム処理の実行エンジンで、独自のAPIを持つ製品です。BeamはFlinkを含む複数エンジンの上に乗る記述層で、FlinkランナーとしてFlinkを実行基盤に使えます。FlinkのネイティブAPIを直接書けばFlink固有の機能をすべて使える代わりに、他エンジンへは移せません。求めるものがどちらかで決めます。

Beamを使うとランナーは本当に無変更で切り替えられますか?

基本的な変換だけで組んだパイプラインは切り替えられますが、無条件ではありません。ウィンドウ・トリガー・State APIの対応状況はランナーごとに異なり、公式のRunner Capability Matrixで差が公開されています。例えばPrismはカスタムウィンドウやループタイマーが未対応です。移植性を重視するなら、差が出る機能の使用を設計段階で絞る判断が要ります。

Python SDKだけでBeamの機能はひと通り使えますか?

ひと通りとは言えません。新機能はJava SDKから入る傾向があり、コネクタの品揃えもJava側が厚くなっています。2.75.0でもDelta Lakeの読み取り対応はJavaに入りました。Python側で不足するコネクタはクロス言語変換で補えますが、コンテナ構成とネットワークの前提が増えます。Pythonで進めるなら、必要なコネクタの有無を着手前に確認してください。

小規模なバッチ処理でBeamを選ぶ意味はありますか?

処理規模が小さく、実行基盤の乗り換え予定も無いなら選ぶ意味は薄いと考えます。分散処理の抽象化に伴う学習と運用の負担が、得られる並列性に見合いません。分かれ目は規模ではなく、将来ストリーミング要件が加わるか、実行基盤が変わりうるかの2点です。どちらかが見込まれるなら、小規模でもBeamで書いておく価値があります。

関連記事

資料請求

RELATED POSTS 関連記事