Realtime Compute for Apache Flink は、グループウィンドウ集計とウィンドウテーブル値関数 (TVF) 集計の 2 種類のウィンドウ集計をサポートしています。このトピックでは、それぞれの構文、ウィンドウ TVF 集計が非 TVF モードにフォールバックする場合、およびウィンドウタイプ別の更新ストリームサポートについて説明します。
2つの構文の選択
| グループウィンドウ集計 | ウィンドウ TVF 集計 | |
|---|---|---|
| 演算子 | GroupWindowAggregation |
WindowAggregate |
| ウィンドウ関数 | TUMBLE、HOP、SESSION | TUMBLE、HOP、CUMULATE、SESSION |
| ステータス | 非推奨 | 推奨 |
| パフォーマンス最適化 | なし | あり |
| GROUPING SETS サポート | なし | あり |
| 集計後のウィンドウ Top-N | なし | あり |
| 更新ストリームサポート | あり (VVR) | あり (VVR、すべてのウィンドウタイプ) |
ウィンドウ TVF 集計の使用を推奨します。グループウィンドウ集計のすべてのウィンドウタイプに加えて CUMULATE をサポートし、パフォーマンス最適化と GROUPING SETS を追加し、集計結果にウィンドウ Top-N を適用できます。
グループウィンドウ集計 (非推奨)
グループウィンドウ集計は、GROUP BY 句でウィンドウを定義します。GroupWindowAggregation 演算子に対応し、TUMBLE、HOP、SESSION ウィンドウ関数をサポートします。
構文、例、および機能の詳細については、「グループウィンドウ集計」をご参照ください。
VVR 11.x におけるグループウィンドウ集計の動作変更
VVR 11.x (Flink 1.20) 以降、システムはグループウィンドウ集計 (非推奨の構文) をウィンドウ TVF 集計の実行計画に自動的に書き換えなくなりました。
VVR 8.x では、システムは非推奨の構文を新しい構文の実行計画に自動的に書き換え、Local-Global 2 段階集計最適化を有効にしていました。VVR 11.x 以降、この自動書き換えはデフォルトの動作ではなくなり、非推奨の構文は元の物理実行計画を保持します。
影響:非推奨の構文を使用しているジョブは、2 段階集計最適化の恩恵を自動的に受けられなくなります。大量のデータやデータスキューが発生するシナリオでは、パフォーマンスが低下する可能性があります。
グループウィンドウ集計をウィンドウ TVF 集計 (新しい構文) に移行します。2フェーズ集計最適化を有効にする条件については、「ウィンドウ集計のローカル-グローバル最適化」をご参照ください。
以前の動作との互換性
すぐに移行できない場合は、次のパラメーターを有効にして VVR 8.x の動作を復元できます。
| パラメーター | 説明 | デフォルト |
|---|---|---|
table.optimizer.window-rewrite-enabled |
非推奨の構文から新しい構文への自動書き換えを有効にし、2 段階集計最適化を有効にします。 | false (VVR 11.x 以降) |
設定例 (ジョブパラメーターに追加):
table.optimizer.window-rewrite-enabled: true
このパラメーターは、アップグレード時の移行互換性対策としてのみ機能します。非推奨の構文は、将来のリリースで書き換えサポートを失う可能性があります。できるだけ早く新しい構文に移行することを推奨します。
ウィンドウ TVF 集計
ウィンドウ TVF 集計では、ウィンドウ TVF によって生成される window_start および window_end 列を含む GROUP BY 句を使用してウィンドウを定義します。これは WindowAggregate 演算子に対応し、TUMBLE、HOP、CUMULATE、および SESSION ウィンドウ関数をサポートします。
連続テーブルでの集計とは異なり、ウィンドウ TVF 集計は中間結果を生成せず、各ウィンドウの終了時に最終結果のみを生成します。中間状態データは自動的にクリーンアップされます。
構文、例、および機能の詳細については、「ウィンドウ TVF 集計」をご参照ください。
SESSION ウィンドウ TVF 構文:VVR 11.x と VVR 8.x の比較
SESSION ウィンドウ TVF 構文は VVR バージョンによって異なります。完全な機能の構文を使用するには、VVR 11.1 以降にアップグレードしてください。
VVR 11.x (Flink 1.20)
SESSION(TABLE data [PARTITION BY(keycols, ...)], DESCRIPTOR(timecol), gap)
| パラメーター | 説明 |
|---|---|
data |
時間属性列を持つテーブル |
keycols |
(オプション) セッションウィンドウの処理の前にデータをパーティション分割するために使用される列 |
timecol |
セッションウィンドウにマッピングされる時間属性列 |
gap |
同じセッション内の 2 つのイベント間の最大時間間隔 |
VVR 8.x (Flink 1.17)
SESSION(TABLE data, DESCRIPTOR(timecol), gap)
| パラメーター | 説明 |
|---|---|
data |
時間属性列を持つテーブル |
timecol |
セッションウィンドウにマッピングされる時間属性列 |
gap |
同じセッション内の 2 つのイベント間の最大時間間隔 |
VVR 8.x はPARTITION BYをサポートしていません。パーティションフィールドはGROUP BY句から暗黙的に推測されます。
SESSION 構文の比較:VVR 11.x と VVR 8.x
| VVR 11.x | VVR 8.x | |
|---|---|---|
| 構文 | SESSION(TABLE data [PARTITION BY(keycols, ...)], DESCRIPTOR(timecol), gap) |
SESSION(TABLE data, DESCRIPTOR(timecol), gap) |
| パーティションフィールドの指定 | 明示的 — PARTITION BY(keycols) を使用 |
暗黙的 — GROUP BY 句を使用 |
| パーティションフィールドの制限 | なし | GROUP BY に含まれている必要があり、window_start、window_end、または window_time は使用できません |
| スタンドアロンの SESSION() の使用 | サポート | GROUP BY と併用する必要があります |
| ウィンドウ関数と集計のマージ | サポート | サポートされていません — 集計はパーティションフィールドと一致する必要があります |
次の例は同等です。どちらも item をパーティションフィールドとして使用しています。
-- Bid テーブルスキーマ (以下のすべての例で使用)
> desc Bid;
+-------------+------------------------+------+-----+--------+---------------------------------+
| name | type | null | key | extras | watermark |
+-------------+------------------------+------+-----+--------+---------------------------------+
| bidtime | TIMESTAMP(3) *ROWTIME* | true | | | `bidtime` - INTERVAL '1' SECOND |
| price | DECIMAL(10, 2) | true | | | |
| item | STRING | true | | | |
+-------------+------------------------+------+-----+--------+---------------------------------+
-- VVR 11.x:パーティションフィールドを SESSION() で明示的に宣言
> SELECT window_start, window_end, item, SUM(price) AS total_price
FROM TABLE(
SESSION(TABLE Bid PARTITION BY item, DESCRIPTOR(bidtime), INTERVAL '5' MINUTES))
GROUP BY item, window_start, window_end;
-- VVR 8.x:パーティションフィールドを GROUP BY から推測
> SELECT window_start, window_end, item, SUM(price) AS total_price
FROM TABLE(
SESSION(TABLE Bid, DESCRIPTOR(bidtime), INTERVAL '5' MINUTES))
GROUP BY item, window_start, window_end;
| VVR 11.x | VVR 8.x | |
|---|---|---|
| SESSION ウィンドウのパーティション分割 | SESSION(TABLE Bid PARTITION BY item, DESCRIPTOR(bidtime), INTERVAL '5' MINUTES) |
SESSION(TABLE Bid, DESCRIPTOR(bidtime), INTERVAL '5' MINUTES) |
| 集計とウィンドウのマージ | 直接マージをサポート (例:ウィンドウ内で SUM(price)) |
集計フィールドはウィンドウパーティションフィールドと一致する必要があります (例:GROUP BY item) |
ウィンドウ TVF 集計が非 TVF モードにフォールバックする場合
クエリにウィンドウ TVF が含まれているが、TVF と集計をマージする条件を満たしていない場合、システムは非 TVF の実行計画にフォールバックします。
マージできないクエリが処理時間を時間属性として使用している場合、処理時間列がマテリアライズされて、作成されたウィンドウの時間属性として使用されます。これにより、ソーステーブルのウォーターマークが集計結果に影響を与え、ウィンドウが予想より早く閉じる可能性があり、遅延データが破棄される可能性があります。これはイベント時間ウィンドウの場合と同様です。これを防ぐために、以下のパターンを避けてください。
次のいずれかの条件を満たす場合、ウィンドウ TVF と集計ステートメントをマージできません。
-
ウィンドウ時間フィールドに対するフィルタリングまたは計算:
window_start、window_end、またはwindow_timeが集計前にフィルタリングまたは変更されている場合。-- window_start に対するフィルタリング > SELECT window_start, window_end, item, SUM(price) AS total_price FROM (SELECT item, price, window_start, window_end FROM TABLE( SESSION(TABLE Bid, DESCRIPTOR(bidtime), INTERVAL '5' MINUTES)) WHERE window_start >= TIMESTAMP '2020-04-15 08:06:00.000') GROUP BY item, window_start, window_end; -- window_start に対する算術演算 > SELECT window_start, window_end, item, SUM(price) AS total_price FROM (SELECT item, price, window_start + (INTERVAL '1' SECOND) AS window_start, window_end FROM TABLE( SESSION(TABLE Bid, DESCRIPTOR(bidtime), INTERVAL '5' MINUTES))) GROUP BY item, window_start, window_end; -- window_start に対する型変換 > SELECT window_start, window_end, item, SUM(price) AS total_price FROM (SELECT item, price, CAST(window_start AS varchar) AS window_start, window_end FROM TABLE( SESSION(TABLE Bid, DESCRIPTOR(bidtime), INTERVAL '5' MINUTES))) GROUP BY item, window_start, window_end; -
ウィンドウ TVF がユーザー定義テーブル関数 (UDTF) と併用されている場合。
> SELECT window_start, window_end, category, SUM(price) AS total_price FROM (SELECT category, price, window_start, window_end FROM TABLE( SESSION(TABLE Bid, DESCRIPTOR(bidtime), INTERVAL '5' MINUTES)), LATERAL TABLE(category_udtf(item)) AS T(category)) GROUP BY category, window_start, window_end; -
GROUP BY 句に window_start または window_end が含まれていない場合。
> SELECT window_start, item, SUM(price) AS total_price FROM TABLE( SESSION(TABLE Bid, DESCRIPTOR(bidtime), INTERVAL '5' MINUTES)) GROUP BY item, window_start; -
Python のユーザー定義集計関数 (UDAF) が使用されている場合。
-
GROUPING SETS、CUBE、または ROLLUP が window_start または window_end で個別にグループ化している場合。
> SELECT item, SUM(price) AS total_price FROM TABLE( SESSION(TABLE Bid, DESCRIPTOR(bidtime), INTERVAL '5' MINUTES)) GROUP BY GROUPING SETS((item), (window_start), (window_end)); > SELECT item, SUM(price) AS total_price FROM TABLE( SESSION(TABLE Bid, DESCRIPTOR(bidtime), INTERVAL '5' MINUTES)) GROUP BY CUBE (item, window_start, window_end); > SELECT item, SUM(price) AS total_price FROM TABLE( SESSION(TABLE Bid, DESCRIPTOR(bidtime), INTERVAL '5' MINUTES)) GROUP BY ROLLUP (item, window_start, window_end); -
集計関数が
window_start、window_end、またはwindow_timeに適用されている場合。> SELECT window_start, window_end, item, SUM(price) AS total_price, MAX(window_end) AS max_end FROM TABLE( SESSION(TABLE Bid, DESCRIPTOR(bidtime), INTERVAL '5' MINUTES)) GROUP BY item, window_start, window_end;
更新ストリームサポート
次の表は、ウィンドウ関数と構文別の更新ストリームサポートを示しています。
| ウィンドウ関数 | 旧構文 (GroupWindowAggregation) - VVR | 旧構文 (GroupWindowAggregation) - Apache Flink | 新構文 (WindowAggregate) - VVR | 新構文 (WindowAggregate) - Apache Flink |
|---|---|---|---|---|
| TUMBLE | あり | あり | あり | なし |
| HOP | あり | あり | あり | なし |
| SESSION | あり | あり | あり | あり (Apache Flink 1.19 以降) |
| CUMULATE | 該当なし | 該当なし | あり (VVR 8.0.6 以降) | なし |
旧構文では、VVR と Apache Flink のどちらを使用しても、更新ストリームのサポートは同じです。新構文では、VVR の WindowAggregate 演算子のみが、すべてのウィンドウ関数で更新ストリームをサポートします。VVR は、入力ストリームに基づいて GroupWindowAggregation 演算子と WindowAggregate 演算子を自動的に選択します。
VVR と Apache Flink の SESSION ウィンドウ関数の違いについては、「クエリ」をご参照ください。
ウィンドウ集計の Local-Global 最適化
ウィンドウ集計は Local-Global 2 段階集計最適化をサポートしています。有効にすると、オプティマイザは単一段階のウィンドウ集計を次のように分割します。
-
Local Aggregate:データシャッフルの前に部分的な事前集計を実行し、ネットワーク経由で転送されるデータ量を削減します。
-
Global Aggregate:シャッフルの後に最終集計を実行し、結果を生成します。
この最適化が有効になるには、次の 6 つの条件をすべて満たす必要があります。
条件1:集計段階の戦略が 2 段階を許可
table.optimizer.agg-phase-strategy が AUTO (デフォルト) または TWO_PHASE に設定されている必要があります。ONE_PHASE に設定すると、2 段階最適化が無効になります。
条件2:ウィンドウがイベント時間を使用
ウィンドウはイベント時間 (rowtime) を使用する必要があります。処理時間ウィンドウはサポートされていません。
条件3:ウィンドウタイプが SESSION でない
TUMBLE、HOP、CUMULATE ウィンドウタイプがサポートされています。SESSION ウィンドウは 2 段階最適化をサポートしていません。
条件4:すべての集計関数が部分マージをサポート
すべての集計関数がマージ操作をサポートしている必要があります。SUM、COUNT、MIN、MAX、AVG などの組み込み関数がサポートされています。カスタム UDAF は merge() メソッドを実装する必要があります。
条件5:入力ストリームが挿入のみで、ウィンドウが TVF 形式に変換可能
次の条件をすべて満たす必要があります。
-
入力ストリームが挿入のみであること。
-
table.exec.emit.early-fire.enabledがfalse(デフォルト) に設定されていること。 -
table.exec.emit.late-fire.enabledがfalse(デフォルト) に設定されていること。 -
HOP ウィンドウの場合、ウィンドウが整列していること (ウィンドウサイズがスライド間隔で割り切れる)。
条件6:データ分散がパーティション要件を事前に満たしていない
入力データの分散が集計のパーティション要件をまだ満たしていない必要があります。データが既にパーティションキーで分散されている場合、オプティマイザは追加の事前集計が不要であると判断し、Local Aggregate ノードを生成しません。
パラメーターリファレンス
| パラメーター | タイプ | デフォルト | 要件 |
|---|---|---|---|
table.optimizer.agg-phase-strategy |
Enum | AUTO | ONE_PHASE 以外である必要があります |
table.exec.emit.early-fire.enabled |
Boolean | false | false である必要があります |
table.exec.emit.late-fire.enabled |
Boolean | false | false である必要があります |