Tableauでデータパイプライン用のガントチャートを作る

概要

データの生成時間が分かると何かと便利です。例えばbackfillにかかる時間を見積もりやすくなったり、ボトルネックを突き止められるなどのメリットがあります。

しかしパイプラインが複数のコンポーネントで構成されていると導出は困難になります。また依存関係が複雑になるほど上流が下流に与える影響も大きくなり、見積もりづらくなります。特に2日以上のデータを作成する場合は尚更です。

パイプラインをガントチャートとして可視化することで、全体の見通しが良くなります。 この記事ではコンポーネントの依存関係と実行時間を表す簡易的な情報を元に、パイプラインのガントチャートを作成する方法を紹介します。

前提

以下のデータパイプラインを対象に話を進めます。

矢印は依存関係を表しています。コンポーネント名に深い意味はありません。

また各コンポーネントの生成時間を以下と仮定します。

component duration
src_orders 5
src_payments 10
stg_orders 6
stg_payments 8
fct_orders 10

これらの情報を基にガントチャートを作成していきましょう。

Step1:データの用意

まずはコンポーネントの依存関係と生成時間をまとめます。

component dependency duration
src_orders 5
src_payments 10
stg_orders src_orders 6
stg_payments src_payments 8
fct_orders stg_orders,stg_payments 10

カラムを補足します。

  • component
    • コンポート名
    • テーブル名、Coordinator Job Nameなどが入る想定です
  • dependency
    • 依存している前段のコンポート名
    • 依存がない場合は空欄としてください
    • 複数ある場合はスペースを入れずにカンマ区切りで記載してください
  • duration
    • コンポーネントの生成時間
    • 日によって生成時間が異なる場合は代表値を入力してください

上記のデータをdata/input.tsv に保存してください。

Step2:時系列データの作成

Step1のファイルを元に時系列データを作成します。

import pandas as pd

def read(path):
    return pd.read_csv(path, sep='\t')
    
def preprocess(df):
    """dependencyをリストに分割する"""
    df["dependency"] = df["dependency"].apply(lambda x: x.split(",") if pd.notnull(x) else [])
    return df

def calc_start_time(df, component, dependency):
    """依存関係に基づいてコンポーネントの開始時間を計算する"""
    if  len(dependency) > 0:
        return df.query(f"(component == @component) | (component in @dependency)")["end"].max()
    elif not df.query("component == @component").empty:
        return df.query(f"component == @component")["end"].max()
    else:
        return 0

def gantt_df(df, days):
    """コンポーネントの開始および終了時刻を含むGanttチャート用のDataFrameを生成する"""
    res_df = pd.DataFrame(columns=["component", "day", "start", "end"])
    for day in range(days):
        for _, row in df.iterrows():
            start_time = calc_start_time(res_df, row["component"], row["dependency"])
            res_df.loc[len(res_df)] = [row["component"], day, start_time, start_time + row["duration"]]
    return res_df
    
def format(df, base_date="202404/01 04:00"):
    """開始および終了時間を日時形式にフォーマットする"""
    for c in ["start", "end"]:
        df[c] = df[c].apply(lambda x: pd.to_datetime(base_date) + pd.Timedelta(minutes=x))
    df = df.sort_values(["component", "day"]).reset_index(drop=True)
    return df
    
df = read("data/input.tsv")
df = preprocess(df)
df = gantt_df(df, 3)
df = format(df)
df.to_csv("data/gantt.tsv", sep="\t", index=None)

例として、3日分のデータを作成した場合のアウトプットを以下に示します。

component day start end
fct_orders 0 2024-04-01 4:18:00 2024-04-01 4:28:00
fct_orders 1 2024-04-01 4:28:00 2024-04-01 4:38:00
fct_orders 2 2024-04-01 4:38:00 2024-04-01 4:48:00
src_orders 0 2024-04-01 4:00:00 2024-04-01 4:05:00
src_orders 1 2024-04-01 4:05:00 2024-04-01 4:10:00
src_orders 2 2024-04-01 4:10:00 2024-04-01 4:15:00
src_payments 0 2024-04-01 4:00:00 2024-04-01 4:10:00
src_payments 1 2024-04-01 4:10:00 2024-04-01 4:20:00
src_payments 2 2024-04-01 4:20:00 2024-04-01 4:30:00
stg_orders 0 2024-04-01 4:05:00 2024-04-01 4:11:00
stg_orders 1 2024-04-01 4:11:00 2024-04-01 4:17:00
stg_orders 2 2024-04-01 4:17:00 2024-04-01 4:23:00
stg_payments 0 2024-04-01 4:10:00 2024-04-01 4:18:00
stg_payments 1 2024-04-01 4:20:00 2024-04-01 4:28:00
stg_payments 2 2024-04-01 4:30:00 2024-04-01 4:38:00
  • day
    • 生成対象の日付
  • start
    • 生成開始時刻
  • end
    • 生成完了時刻

Step3:Tableauによる可視化

データが用意できたので後は可視化するだけです。 Step2でTableauに合わせた形にデータを加工したので、比較的簡単に可視化できます。

1. データソースを読み込む

Step2のアウトプットをTableauに読み込みます

2. 計算フィールドを作成する

新たにdurationを作成します。生成時間を表します。 以下の計算式を入力してください。

DATEDIFF('minute', [Start], [End]) / (60 * 24)

最初の関数は時刻の差分を分単位で返します。 このvizでは日単位に直す必要があるので1日分の分数で割っています。

3. フィールドを配置する

以下のようにフィールドを配置します。

あるいはDataPipeline - GanttChart | Tableau Publicからダウンロードしたvizを使ってください。

ポイントをいくつかまとめます

  • durationを「サイズ」に指定することで、生成時間とバーの長さを関連付けています
  • dayを「色」に指定することで生成対象の日付がわかるようになっています
  • コンポーネントの順序は手動で並べ替えています

これで完成です!

さいごに

ガントチャートを使ってデータパイプラインの生成時間を可視化する方法を紹介しました。モダンなオーケストレーションツールにはガントチャートが実装されているので、この記事の内容が役立つタイミングはあまりないかもしれません。 あえてTableauで可視化することで、他のデータと組み合わせることが可能となり可視化の幅も広がります。ぜひ試してみてください。