とある研究者の方から分析環境構築について相談を受けた。 アーキテクチャ設計 & データパイプライン構築を支援したのでメモしておく。
要求
受けた相談としては下記の通り
- サイズの大きいデータセットを解析したい
- データセットがフォルダ・ファイルに分かれていて圧倒されている
- 解析には R を使いたい
ヒアリングしてみたところ、アーキテクチャの決定に関わる重要な情報が得られた。
- データ形式: 特定区切り文字の ASCII ファイル
- データベースから抽出されたプレーンテキストファイルで、区切り文字は “
#
”
- データベースから抽出されたプレーンテキストファイルで、区切り文字は “
- データサイズ: 1 年あたり 1.6 GB のデータが 20 年分
- Web サービスが生成するビジネスデータのサイズに比べると特別大きくはないものの、研究データとしてはかなり充実している部類
- R で直接解析するのは厳しいと判断した(贅沢な悩みですね)
- この時点で、まず DWH が必要であることがわかった
- 解析には R を使いたい」の must 感: must ではない
- メイン解析前の探索的解析において R から透過的に DWH を操作するにしても、可視化時にはデータをメモリに載せる必要がある
- それもちょっと厳しそうなので、探索解析における可視化には何らかの BI ツールを使うことにした
- メイン解析前の探索的解析において R から透過的に DWH を操作するにしても、可視化時にはデータをメモリに載せる必要がある
- データ更新の有無: あり
- 既存のデータが修正されることがあるとのこと。ただし更新履歴を記録する必要はなく、上書きでよい。これはかなり助かる
- オンラインサービス・有料サービスの利用可否: どちらも利用不可
- となると、定番スタックからはやや離れたツール選定が必要になる可能性が想定された。
- 裏を返せばそもそもの選択肢が狭まってある意味では楽かもしれない、、、?
- 参照できる既往知見がだいぶ減るのはキツいが致し方なし
- ちなみにオンライン不可というのはインターネットへのアクセス自体が不可という意味ではなかった
- となると、定番スタックからはやや離れたツール選定が必要になる可能性が想定された。
要件
ということで、ヒアリングの結果見えた要件は下記の通り:
- オフラインで動く OSS の DWH を使うこと
- ファイルに更新があるたび DWH に load できること
- オフラインで動く OSS の BI ツールを使うこと
- BI ツール用にデータマートを準備できること
アーキテクチャ設計・ツール選定
(E)LT 形式とする
- load: DLT
- DWH: DuckDB
- transform: dbt (core)
- BI: Superset (Docker container)
- はじめ Rill Data で試したのだがデータ量が多すぎたようでとても操作できなかった
flowchart LR subgraph dataset datasets@{ shape: docs, label: "dataset.txt"} end DLT[DLT] -.-> |read| dataset DLT ---> |load| duckdb[(dataset.duckdb)] dbt -.-> |read| duckdb dbt --> |transform| duckdb Superset -.-> |read| duckdb
各ツールを利用した実装のポイント
Prerequisits:
DLT
- source:
filesystem
タイプ - target: DuckDB
ポイント
- 実行にそれなりの時間がかかるので、ユースケースを通せるまでターゲットディレクトリは絞っておく
- 全カラムをいったん string でロードしておく
- ゴミデータが入っているとパースエラーになったりするので、始めからデータ仕様書通りの型に合わせに行かない
.duckdb
の生成先をsuperset-duckdb/data
配下にしておく
[destination.filesystem] # in ./dlt/secrets.toml
bucket_url="file://path/to/superset-duckdb/data"
DuckDB
特に問題なし
Superset
- この記事を参考に、
jorritsandbrink/superset-duckdb
相当のイメージをビルドして使った。 - https://github.com/jorritsandbrink/superset-duckdb を clone しておく
ポイント
- DLT によるロードで生成される
.duckdb
がsuperset-duckdb/data
配下に置かれるようにしておくdocker run
時にマウントしてくれるので dbt による transform 結果を都度確認するのが楽
dbt
データ仕様書を参考に、各テーブルから利用したいカラムを型変換しつつ DuckDB にリロードする
Makefile
データの更新頻度はそれほど高くないので(年に数回程度)、パイプライン実行は手動でやっている。
.PHONY: load
load:
uv run load.py # DLT による load 処理を書いたファイル
.PHONY: superset
superset:
cd superset-duckdb && \
docker build -t YOURNAME/superset-duckdb docker && \
docker run -d -p 8080:8088 \
-e "SUPERSET_SECRET_KEY=your_secret_key" \
--mount type=bind,source=$$(pwd)/data,target=/data \
--name superset-duckdb \
YOURNAME/superset-duckdb && \
./docker/setup.sh
.PHONY: transform
transform:
uv run dbt run --profiles-dir .dbt --project-dir PROJECT_DIR