「データレイク (data lake)」は構造化・半構造化・非構造化データを生のまま (スキーマオンリード) 大量に保管するストレージ層。 S3・Azure Data Lake Storage・Google Cloud Storage が代表的基盤。 本ページでは DWH との対比・Parquet/ORC 等の列指向フォーマット・Delta Lake / Iceberg / Hudi のテーブルフォーマット・データスワンプ化の防止・レイクハウス (Lakehouse) への進化を整理する。
これらのキーワードは「生データを安価に保管 → 列指向で高速分析 → テーブルフォーマットで ACID → メダリオンで品質階層化」というデータレイク運用のフローを構成する。
🍰 まずはやさしく
あらゆるデータを貯める巨大な池のような場所です。
後で分析するために、生のデータをそのまま保存します。
スマホの写真や動画を全部保存するフォルダのようなものです。
この章では、データレイクの結論を短くまとめます。
構造化・非構造化を生のまま保存する大規模ストレージ
データレイク ── 構造化・半構造化・非構造化を問わず生のまま低コストに蓄積する大規模ストレージ。 ETL 後に整える DWH と対照的に 「貯めてから考える」 思想。
🍰 まずはやさしく
データが集まる流れの中にある、蓄積の場所です。
集めたデータを整理して、分析に使いやすくします。
部活の記録をノートや写真など色々な形で残すことに似ています。
この章では、データがどう流れて保存されるかを読みます。
データレイクは データエンジニアリング の蓄積層の中核です。 上流は データ収集 ・ センサー ・ SNS ・ 行動ログ、 下流は DataFrame ・ BI ・ ML パイプライン。
対比概念は データウェアハウス(DWH、 整形済み・スキーマ厳格)とRDB(行指向・トランザクション)。 「型が決まっていない / 後で型を決めたい」生データはレイクへ、 「定型集計が走る」整形済みは DWH へ、と使い分けます。
Databricks が広めた Bronze / Silver / Gold 3 層構造が定石。 段階的にデータを精錬していくモデルです:
| 層 | 役割 | 形式 | 利用者 |
|---|---|---|---|
| Bronze(生) | 取り込みそのまま、 監査用 | JSON, CSV, ログ原文 | 基盤エンジニア |
| Silver(整形済) | クレンジング、 名寄せ済 | Parquet/Delta、 型定義あり | データサイエンティスト |
| Gold(業務向け) | 事業 KPI に集計 | 星型・スター スキーマ | アナリスト・BI |
この階層化が、 「データを失わず、 用途別に最適化する」レイクの核心。 Bronze には全てを残し、 Silver / Gold は再生成できる前提で設計します。
| フォーマット | 指向 | 圧縮率 | 向く用途 |
|---|---|---|---|
| CSV | 行 | 低(圧縮しない場合) | 交換、 簡易共有 |
| JSON | 行 | 中 | 半構造化、 ログ |
| Avro | 行 | 高 | Kafka 連携、 ストリーミング |
| Parquet | 列 | 高(10倍) | 分析、 OLAP の定番 |
| ORC | 列 | 高 | Hive エコシステム |
| Delta Lake | 列+ログ | 高 | ACID、 Time Travel |
| Iceberg | 列+メタ | 高 | ベンダ中立、 スキーマ進化 |
| Hudi | 列+ログ | 高 | 更新が多いストリーム |
2025 年現在、 列指向(Parquet)+テーブルフォーマット(Iceberg/Delta)の組合せが事実上の標準。 CSV は人間用、 内部処理は Parquet が無難です。
🍰 まずはやさしく
とりあえず全部置いておく、大きな倉庫のようなものです。
形を変えずに保存して、使う時にだけ加工します。
買い物メモやレシートを、とりあえず箱に全部入れる感覚です。
この章では、使い方の考え方や注意点を直感的に学びます。
データレイクは「とりあえず原型のまま全部置いておく巨大ストレージ」。 SSDSE-B-2026 のような CSV、 IoT ログの JSON、 画像、 動画を、 形式変換せず S3 / GCS / Azure Blob などに一括蓄積する。 「先にスキーマを決めず、 必要になったら読み出して加工する (schema on read)」という思想で、 事前整形が必須のデータウェアハウス (schema on write) と対比される。
以下では、 S3 / GCS / Azure Blob 上のオブジェクトストレージに SSDSE CSV・IoT JSON・画像・動画を原型のまま並べて蓄える設計から始め、 schema on read の思想、 Parquet / Delta Lake / Iceberg などのテーブル形式、 そして「データウェアハウス (DWH) との使い分け」「データレイクハウス (Databricks 提唱) への発展」を整理します。 「カタログを作らず誰が何を入れたか不明になる Data Swamp 化」「ACID 不在で同時書込が壊れる」など、 統制を欠いた運用が招く典型的事故も順に辿ります。
「データレイク」という言葉そのものが比喩です。 川(データソース)から流れ込んだ水(データ)が、 形を整えずにそのまま大きな湖に溜まるイメージ。 利用者は釣り糸を垂らすように、 必要な時に必要な形でデータを取り出します。
対照的に、 データウェアハウス(DWH)は ペットボトル飲料 のような存在。 工場で品質管理され、 規格化されて店頭に並んでいる。 そのまま飲める一方、 「もう作り直せない」「色付き水(型変更)が欲しくても無理」という制約があります。
この自由度こそ「貯めてから考える(schema-on-read)」哲学の本質で、 IoT や SNS のように「将来どう使うか未知の」データを扱う現代において、 DWH より柔軟性が高い基盤として選好されるようになりました。
典型的なデータレイクの処理フローを順に追います。 各段階で使うツールも例示:
| 段階 | 入力 | 処理 | 出力 | ツール例 |
|---|---|---|---|---|
| 1. 取得 | DB / API / IoT | バッチ/ストリーム取得 | 生 JSON, CSV | Fivetran, Kafka |
| 2. 着地 (Bronze) | 生データ | そのまま蓄積 | Bronze テーブル | S3 + Iceberg |
| 3. 整形 (Silver) | Bronze | クレンジング、 型統一 | Silver テーブル | Spark, dbt |
| 4. 集計 (Gold) | Silver | 業務 KPI 集計 | Gold テーブル | dbt, Spark SQL |
| 5. 提供 | Gold | BI/ML/API | レポート, 予測 | Tableau, MLFlow |
| 6. 監視 | 全層 | 品質・SLA | アラート | Monte Carlo, Soda |
| 機能 | AWS | Google Cloud | Azure | Databricks |
|---|---|---|---|---|
| ストレージ | S3 | GCS | Blob/ADLS Gen2 | 下層は各社 |
| クエリエンジン | Athena, Redshift Spectrum | BigQuery (Omni) | Synapse, Fabric | Photon |
| テーブル | Iceberg, Hudi, Delta | Iceberg, BQ | Delta, Iceberg | Delta(主) |
| カタログ | Glue Catalog | Dataplex | Purview | Unity Catalog |
| ETL | Glue, EMR | Dataproc, Dataflow | Synapse, DF | Workflows |
| 価格モデル | 従量 | 従量+予約 | 従量+予約 | DBU 課金 |
既存のクラウド契約に合わせるのが王道。 マルチクラウドなら Iceberg + Trino のオープン構成を検討。
環境/層/ドメイン/テーブル/パーティション の階層Q1. DWH と何が違うの?
DWH は 事前に スキーマ・前処理を厳格に行ってから格納するのに対し、 レイクは生のまま放り込んでクエリ時に解釈。 「先に整える vs 後で整える」が本質的な違い。 近年は両者の中間「レイクハウス」が主流。
Q2. オンプレ HDFS は今でも有効?
大企業のレガシーは現役ですが、 新規はクラウドのオブジェクトストレージ(S3/GCS/Blob)が主流。 オンプレ存続なら MinIO 等の S3 API 互換 OSS が選択肢。
Q3. 小規模なら DuckDB で十分?
数 TB までならローカル PC+DuckDB が最速・最安。 「ビッグデータ」と称しても実際は数十 GB 級、 ということが多く、 過剰スペック化への警鐘もあります。
Q4. Delta vs Iceberg、どちらを選ぶ?
Databricks 中心なら Delta、 AWS/オープン環境なら Iceberg が無難。 Iceberg は Snowflake, BigQuery, Trino など複数エンジン対応で、 ベンダ ロックイン回避の観点で支持を集めています。
Q5. 個人情報はレイクに入れていい?
入れてよいが、 ① 暗号化保管(KMS)、 ② IAM/RBAC でアクセス制御、 ③ マスキングビューでの参照、 ④ データガバナンス 規程の整備、 が必要。 「個人情報専用ゾーン」を分離して別バケットにする設計が多い。
🍰 まずはやさしく
色々な形式のデータをそのまま保存する仕組みです。
大量のデータを低コストで蓄えるために使います。
学校のアンケート結果や、SNSの投稿をまとめて保存する例です。
この章では、データレイクの正確な定義を詳しく読みます。
構造化・非構造化を生のまま保存する大規模ストレージ
英語名 Data Lake。
この用語を理解・使用するときは、 次のような前提を意識してください:
クラウドデータレイクの月額コストは大きく次の和で表せます:
$$ C_{\text{月}} = C_s + C_r + C_w + C_q $$
$C_s$=ストレージ容量料、 $C_r$=API リクエスト料、 $C_w$=ネットワーク転送料、 $C_q$=クエリ料(Athena/BigQuery 等)。 ストレージは安いが、 「クエリで全件スキャン」を繰り返すと $C_q$ が急増。 列指向+パーティション分割で対策します。
| 項目 | 単価(参考) | 節約策 |
|---|---|---|
| S3 Standard | 0.023 USD / GB / 月 | 古いデータは IA / Glacier へ |
| S3 リクエスト | 0.005 USD / 1000 PUT | 小ファイルを結合(compaction) |
| Athena | 5 USD / TB スキャン | パーティション・列指向・LIMIT |
| BigQuery | 6.25 USD / TB | 同上、 予約計算枠 |
| 転送 (外向き) | 0.09 USD / GB | 同リージョン内で完結 |
データレイク (Data Lake) は「構造化・半構造化・非構造化のデータを生のまま大量に格納し、 後で読むときにスキーマを当てる (schema-on-read)」アーキテクチャです。 ここでは SSDSE-B-2026 という比較的小さい (約 360KB) CSV を題材に、 実際にデータレイクへ格納する手順をシミュレートし、 ファイル形式・パーティション設計・クエリ性能・コストの観点を順に検証します。 数式を言葉で読み解いて、 「なぜ CSV のまま置きっぱなしにすべきでないか」を腹落ちさせるのが本節の狙い。
行数 $N$、 列数 $M$、 平均値 1 つあたりのバイト数 $b$、 圧縮率 $\rho$ のとき、 ストレージサイズ $S$ は次のように近似できます。
$$ S \approx \rho \cdot N \cdot M \cdot b \cdot (1 + \alpha_{\text{meta}}) $$
$\alpha_{\text{meta}}$ はメタデータ (カラム名・統計・索引) のオーバーヘッド比 (Parquet で約 5-15%)。 月額コスト $C$ は
$$ C = S \cdot p_{\text{storage}} + Q \cdot p_{\text{query}} $$
$p_{\text{storage}}$ は GB あたり月額単価、 $Q$ はクエリでスキャンするバイト数、 $p_{\text{query}}$ はスキャンバイト単価です。 列指向 (Parquet) は不要列をスキップできるため $Q$ を 1/10 以下に下げられる。
SSDSE-B-2026.csv は実測で 359,821 バイト (564 行 × 112 列)。 これを Parquet にフォーマット変換すると、 圧縮アルゴリズムごとに次のサイズになります。
この規模 (560 行) では Snappy 圧縮は CSV と大差ない (むしろメタデータで微増)。 しかし行数が 100 倍以上になると、 Parquet の差は決定的になります。 Snappy は解凍が高速なため、 クエリ時の総コストでは Parquet+Snappy が最有力。
🎯 このコードでやること: SSDSE-B-2026.csv を読み込み、 pandas + pyarrow で Parquet 化し、 圧縮形式ごとのファイルサイズを比較する。 Parquet 化はデータレイクの「Raw → Bronze 層」の標準パターン。
📥 入力データ: data/raw/SSDSE-B-2026.csv (564 行 × 112 列、 約 360KB)。 cp932 エンコーディング、 ヘッダー 2 行構成。
1 2 3 4 5 6 7 8 9 10 11 12 13 | import pandas as pd import pyarrow as pa import pyarrow.parquet as pq import os df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df.rename(columns={'SSDSE-B-2026':'year'}) os.makedirs('data/lake/bronze/ssdse', exist_ok=True) for codec in ['snappy', 'gzip', 'zstd']: p = f'data/lake/bronze/ssdse/ssdse_{codec}.parquet' df.to_parquet(p, engine='pyarrow', compression=codec) print(f'{codec:6}: {os.path.getsize(p):,} bytes') |
📤 実行すると次の出力が得られる:
💬 結果の読み方: 564 行という小さいデータでも、 zstd は CSV の 70% に縮む。 これが数千万行になると差は数 GB のオーダーに膨らみ、 S3 ストレージ料金とスキャンコストに直接効いてくる。 「とりあえず Parquet + zstd」がデータレイクの初期設定として無難。
🎯 このコードでやること: SSDSE-B-2026 を year カラムでパーティショニングして保存。 これにより「2023 年だけ読む」クエリでパーティションプルーニングが効き、 スキャンバイトを激減できる。
📥 入力データ: 同じ SSDSE-B-2026 (564 行 × 112 列)。 year 列は 2012-2023 の 12 種類。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | import pandas as pd import pyarrow as pa import pyarrow.parquet as pq df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df.rename(columns={'SSDSE-B-2026':'year'}) table = pa.Table.from_pandas(df) # write_to_dataset は既存ディレクトリに *追記* する。 # 消さずに再実行すると同じ行が何重にも積み上がるので、毎回作り直す。 import shutil, os shutil.rmtree('data/lake/bronze/ssdse_partitioned', ignore_errors=True) pq.write_to_dataset( table, root_path='data/lake/bronze/ssdse_partitioned', partition_cols=['year'], compression='snappy', ) # 部分読み込み: 2023 年のみ subset = pq.read_table( 'data/lake/bronze/ssdse_partitioned', filters=[('year', '=', 2023)] ).to_pandas() print(f'2023 年のみ: {len(subset)} 行 (期待 47 行)') print(subset[['Prefecture','A1101']].head()) |
📤 実行すると次の出力が得られる:
💬 結果の読み方: filters を指定するだけで該当パーティションだけ読み込まれる。 Athena/Spark/Trino でも同じ仕組み。 「2023 年だけ取りたいクエリで全 564 行を読まずに済む」のがパーティショニングの本質。 スキャンバイトが減れば、 クラウドの従量課金も減る。
🎯 このコードでやること: Databricks 社が提唱する「メダリオン階層」を SSDSE で実装。 Bronze=生データ、 Silver=クレンジング、 Gold=ビジネス指標。 同じソースから役割の違う 3 層が生成される。
📥 入力データ: data/raw/SSDSE-B-2026.csv (Bronze)。 Silver では年・県・主要指標のみ抽出、 Gold では「年あたり人口増加率」を計算。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | import os os.makedirs('data', exist_ok=True) # 書き出し先を先に作る os.makedirs('data/lake/bronze', exist_ok=True) # 保存先のフォルダを作っておく os.makedirs('data/lake/silver', exist_ok=True) # 保存先のフォルダを作っておく os.makedirs('data/lake/gold', exist_ok=True) # 保存先のフォルダを作っておく import os import pandas as pd import pyarrow # Parquet の読み書きに必要(ブラウザ版 Python には入っていない) # ── この抜粋で使うデータを用意します(英字の項目コードで読み込み)── # 年度をまたいだ集計をするので、ここでは年度で絞らない df_raw = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=0) df_raw = df_raw[df_raw['Code'].astype(str).str.match(r'^R\d{5}$', na=False)].copy() for _c in df_raw.columns[3:]: df_raw[_c] = pd.to_numeric(df_raw[_c], errors='coerce') # 保存先が無いと to_parquet は失敗する for _p in ('data/lake/bronze', 'data/lake/silver', 'data/lake/gold'): os.makedirs(_p, exist_ok=True) # Bronze: 生 CSV をそのまま Parquet 化 df_raw.to_parquet('data/lake/bronze/ssdse_raw.parquet', compression='snappy') # Silver: 必要列のみ、 型整理、 欠損処理 df_silver = df_raw[['SSDSE-B-2026', 'Code', 'Prefecture', 'A1101']].copy() df_silver.columns = ['year', 'pref_code', 'pref_name', 'population'] df_silver = df_silver.dropna().astype({'population': 'int64'}) df_silver.to_parquet('data/lake/silver/pop_clean.parquet', compression='snappy') # Gold: 年あたり人口増加率の集計 df_silver = df_silver.sort_values(['pref_name','year']) df_silver['pop_growth'] = df_silver.groupby('pref_name')['population'].pct_change() df_gold = df_silver.groupby('pref_name').agg( avg_pop=('population','mean'), avg_growth=('pop_growth','mean'), ).round(4) df_gold.to_parquet('data/lake/gold/pref_summary.parquet', compression='snappy') print(df_gold.sort_values('avg_growth', ascending=False).head()) |
📤 実行すると次の出力が得られる (概略):
💬 結果の読み方: Bronze は再現性のため絶対消さない。 Silver は分析担当が使える品質、 Gold はビジネスダッシュボードに直結する事前集計。 「Gold だけ見れば良い」アナリストと「Bronze から戻れる」エンジニアの役割分担がデータレイク運用の鍵。
🎯 このコードでやること: データレイク上の Parquet ファイルを Athena/Trino を使わずローカル DuckDB で SQL クエリし、 「ファイルをロードせずに集計できる」体験を再現。
📥 入力データ: data/lake/silver/pop_clean.parquet (564 行)。
1 2 3 4 5 6 7 8 9 10 11 12 13 | import duckdb con = duckdb.connect() df = con.execute(""" SELECT pref_name, AVG(population) AS avg_pop, MAX(population) - MIN(population) AS range_pop FROM read_parquet('data/lake/silver/pop_clean.parquet') GROUP BY pref_name ORDER BY avg_pop DESC LIMIT 5 """).df() print(df) |
📤 実行すると次の出力が得られる:
💬 結果の読み方: DuckDB はParquet を直接 SQL する。 これがデータレイクの強み。 「ファイルを開く・読む・整形する」のコードが不要になり、 SQL 一本で集計まで完結する。 クラウドでは Athena (S3 + Glue Data Catalog)、 オンプレでは Trino/Spark/DuckDB を選ぶ。
| 観点 | データレイク | DWH | レイクハウス |
|---|---|---|---|
| データ型 | 構造化〜非構造化すべて | 構造化中心 | 構造化〜半構造化 |
| スキーマ | on-read | on-write | on-write + on-read |
| トランザクション | 基本無し | ACID | Delta/Iceberg で ACID |
| クエリ性能 | 中 | 高 (索引・統計) | 中〜高 |
| コスト | 最安 | 高 (専用ハード) | レイクに近い |
| 代表サービス | S3 + Athena + Glue | Snowflake / Redshift / BigQuery | Databricks / Iceberg + Trino |
| ML 親和性 | 高 (生データ容易) | 低 (SQL 中心) | 高 (Spark ML) |
Bronze→Silver の変換が増えてくると、 「ある日突然 NULL が増えた」「集計値が前月比 30% 違う」といった異常検知が必要になります。 Great Expectations や dbt tests の標準テストカテゴリは以下のとおり。
| カテゴリ | テスト例 | 失敗時の挙動 |
|---|---|---|
| スキーマ | 列名・型・順序が期待通りか | パイプライン即時停止 |
| NULL 率 | 指定列の NULL 率 < 1% | 警告 + Slack 通知 |
| 値域 | population > 0、 year ∈ [2000, 2030] | 行を quarantine フォルダへ |
| 一意性 | (pref_code, year) ペアが一意 | パイプライン停止 |
| 参照整合性 | pref_code が master テーブルに存在 | 未参照値をログ |
| 分布 | 前月比 ±20% 以内 | 手動確認をリクエスト |
これらをパイプライン側で自動実行し、 「Gold 層に届くデータは品質保証済み」と宣言できる体制を目指す。
SSDSE-B-2026 のような小規模公的データ (約 360KB の CSV、 47 都道府県 × 複数年) はそのまま Bronze 層に置けば月額数セント以下に収まる。 しかし実務では SSDSE 系列を出発点に派生集計や関連データ (人口動態・経済センサス・気象観測など) を結合した Silver/Gold 層が積み上がり、 容量は数 TB〜数十 TB に達する。 ここでは典型的な階層別単価 (Hot/Warm/Cold) とアクセス頻度から月額コストを概算する。
| 階層 | 容量 [TB] | 単価 [USD/GB] | 月額 |
|---|---|---|---|
| Hot | 5 | 0.023 | 117.76 USD |
| Warm | 20 | 0.013 | 266.24 USD |
| Cold | 100 | 0.004 | 409.60 USD |
※ 1 TB = 1024 GB
1 2 3 4 5 6 | import numpy as np cap_tb = np.array([5, 20, 100]) rate = np.array([0.023, 0.013, 0.004]) cost = cap_tb * 1024 * rate print(f"階層別: {cost}") print(f"合計: {cost.sum():.2f} USD") |
💬 手計算 (Step 2) 793.60 USD と Python 出力が完全一致。
SSDSE-B-2026 のような公的統計データを Python で扱う際の基本パターン:
1 2 3 4 5 6 7 8 9 10 11 12 | import pandas as pd import numpy as np # データ読み込み df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=1) print(df.shape) print(df.dtypes) print(df.describe()) # 「データレイク」の文脈で扱う場合の例: # 分野: データエンジニアリング # 関連手法は同カテゴリの他用語を参照してください。 |
具体的なコードは データエンジニアリング を参照してください。
分析結果を報告するときに含めるべき情報:
(1) SSDSE-B のような CSV を S3 へ Parquet で投入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import os os.makedirs('data', exist_ok=True) # 書き出し先を先に作る import os os.makedirs('data/lake/bronze', exist_ok=True) # 保存先のフォルダを作っておく import pyarrow # parquet の読み書きに必要(ブラウザには無い) import pandas as pd import boto3 df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=1) # 年でパーティション分割した Parquet 出力 df.to_parquet('data/lake/bronze/ssdse_b.parquet', partition_cols=['年度'], compression='snappy') # S3 にアップロード boto3.client('s3').upload_file( 'data/lake/bronze/ssdse_b.parquet', 'my-data-lake', 'bronze/ssdse/year=2026/data.parquet') |
(2) DuckDB で S3 上の Parquet をローカル PC から直接クエリ(最近の定番):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import duckdb con = duckdb.connect() con.execute("INSTALL httpfs; LOAD httpfs;") # S3 上の Parquet 全体に SQL(必要列のみ列指向で読み込み) q = """ SELECT 都道府県, AVG(高齢化率) AS avg_aging FROM read_parquet('s3://my-data-lake/silver/ssdse/*.parquet') GROUP BY 都道府県 ORDER BY avg_aging DESC LIMIT 10; """ print(con.execute(q).fetch_df()) |
(3) Delta Lake で ACID トランザクション:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | from deltalake import write_deltalake, DeltaTable # 初回書き込み write_deltalake('data/lake/silver/ssdse', df, mode='overwrite') # 更新(UPSERT 風) dt = DeltaTable('data/lake/silver/ssdse') dt.merge( source=df, predicate='source.都道府県 = target.都道府県 AND source.年度 = target.年度', source_alias='source', target_alias='target', ).when_matched_update_all().when_not_matched_insert_all().execute() # Time Travel:1 バージョン前の状態を取得 old = DeltaTable('data/lake/silver/ssdse', version=0).to_pandas() print(old.head()) |
同じ生データ(CSV / JSON / ログ / 画像メタ)を、 左のデータレイクと右のDWH に同時に流し込む実験です。 レイクはそのまま沈む(投入 1 pt)が、 DWH は投入前にスキーマ検証・変換のゲートを通る(投入 5〜8 pt)。 逆に読み出しは、 レイクが schema-on-read のため 1 件 4 pt、 DWH は整形済みなので 1 件 1 pt。 「投入時の手間 vs 読み出し時の手間」のトレードオフを合計コストで確かめてください。 さらに「ガバナンス無し」トグルを ON にすると、 メタデータ未登録のままレイクに沈んだデータが検索不能になり、 湖が濁ってデータスワンプ化する様子も体感できます。
※ コスト(pt)は「作業の手間」を表す架空のモデル値です(実測値ではありません)。 レイク投入 1 pt/件、 DWH 投入 5 pt/件(非構造化のログ・画像メタは構造化変換 +3 pt で 8 pt)、 レイク読み出し 4 pt/件・回(スキーマ適用 3 + 品質処理 1)、 DWH 読み出し 1 pt/件・回。
| 件数 | 投入コスト | 読み出しコスト(×回数) | 合計 | |
|---|---|---|---|---|
| 🌊 レイク | 0 | 0 pt | 0 pt | 0 pt |
| 🏭 DWH | 0 | 0 pt | 0 pt | 0 pt |
🔎 レイクの検索可能率: 100% / 🥬 スワンプ度: 0%
まずデータを投入してみましょう。 SVG の湖・倉庫をタップしても投入できます。
上の実験で数値が示す通り、 レイクは「書くのが速く、 読むのが重い」、 DWH は「書くのが重く、 読むのが速い」。 読み出し回数のスライダーを 0〜1 回にするとレイクが安く、 回数を増やすほど DWH(や、 レイク内で Silver/Gold 層に整形しておく Medallion 設計)が有利になります。 このモデルでは構造化データ 1 件あたり「1 + 4r」対「5 + r」(r = 読み出し回数)なので、 r ≧ 2 で DWH 側が逆転する計算です(r = 2 で 9 pt 対 7 pt)。 つまり「何度も同じ形で読むデータは先に整える」「使うか分からない生データはまず湖へ」が合理的な使い分けです。
ガバナンス無しトグルを ON にした後の湖を見てください。 「?」のラベルが増え、 検索可能率が下がり、 湖が濁っていきます。 これがデータスワンプです。 データ自体は消えていないのに、 メタデータ(誰が・いつ・何の目的で・どんなスキーマで入れたか)が無いために見つけられず使えない。 投入が速いというレイクの利点は、 カタログ整備・命名規約・データガバナンスとセットで初めて成立します。 「後で整理しよう」は、 湖では実質「二度と整理されない」と同義です。
現代の実務では、 レイクの柔軟性と DWH の信頼性を統合したレイクハウス(Delta Lake / Apache Iceberg / Apache Hudi)が主流化しています。 オブジェクトストレージ上の Parquet(列指向・高圧縮)にトランザクションログとスキーマ情報を重ねることで、 ACID・Time Travel・スキーマ進化を実現し、 「湖なのに倉庫並みに読める」状態を作ります。 そしてどの構成でも要となるのがデータカタログ(AWS Glue / Unity Catalog / DataHub など)。 上の実験の「メタデータ登録」に相当する仕組みを最初から組み込むことが、 スワンプ化を防ぐ唯一の恒久策です。 前処理の詳細は ETL・データクレンジング も参照してください。
| 層 | AWS | GCP | Azure | OSS |
|---|---|---|---|---|
| ストレージ | S3 | GCS | ADLS Gen2 | MinIO |
| カタログ | Glue Data Catalog | Dataplex | Purview | Hive / Iceberg REST |
| SQL クエリ | Athena | BigQuery (external) | Synapse Serverless | Trino / DuckDB |
| 変換 (ETL) | Glue / EMR | Dataflow / Dataproc | Synapse / HDInsight | Spark / dbt |
| テーブル形式 | Iceberg / Delta | Iceberg / BigLake | Delta | Apache Iceberg / Hudi |
| 統合プラットフォーム | Lake Formation | Dataplex | Fabric | Databricks (商用 OSS) |
SSDSE は 564 行と小規模ですが、 仮に同じ列構造で 1 億行 (47 都道府県 × 365 日 × 約 5800 年相当、 もしくは細粒度ログ) になったときの保存・クエリコストを試算します。
| 形式 | サイズ | S3 月額 (Standard) | 全件 Athena クエリ | 3 列クエリ |
|---|---|---|---|---|
| CSV | ~64 GB | 1.60 USD | 0.32 USD | 0.32 USD (列指向不可) |
| Parquet+Snappy | ~64 GB | 1.60 USD | 0.32 USD | 0.009 USD (≒1/35) |
| Parquet+Zstd | ~44 GB | 1.10 USD | 0.22 USD | 0.006 USD |
| Parquet+Year パーティション | ~44 GB | 1.10 USD | 0.22 USD | 0.0005 USD (≒1/640) |
小さなクエリでも回数が多ければコストは加算される。 「フォーマット選定」「パーティション設計」「圧縮選択」の 3 点だけで、 同じデータでも 100 倍以上のコスト差が出る。
| 用語 | 意味 |
|---|---|
| schema-on-read | 読み込み時にスキーマを当てる方式 |
| data swamp | メタデータ整備を怠ったレイクが沼化した状態 |
| medallion architecture | Bronze/Silver/Gold の 3 階層 ETL パターン |
| columnar format | 列単位で連続配置 (Parquet/ORC) |
| partition pruning | パーティション条件で読み込み対象を絞り込む最適化 |
| predicate pushdown | WHERE 条件をファイル側で評価する最適化 |
| ACID on lake | Iceberg/Delta によるトランザクション保証 |
| time travel | 過去スナップショットを SQL で参照 |
| vacuum | 古いスナップショットを物理削除しサイズ縮小 |
| data catalog | テーブル定義・系譜・統計の中央集約 |
「データレイク = Parquet + ディレクトリ構造」だけだと、 同時書き込み・スキーマ進化・トランザクションで困ります。 これを解決するのが Iceberg/Delta/Hudi といったテーブル形式。 Parquet ファイル群の上にメタデータ層を被せて、 ACID・time travel・schema evolution を提供します。
Iceberg テーブルは以下の 3 階層メタデータで構成されます。
クエリ時はまず manifest を読んで「どの Parquet を読めば良いか」を絞り込む。 この仕組みにより、 数百万 Parquet があっても WHERE 条件で必要なファイルだけに絞れる。
Delta は _delta_log/ に 00000000000000000000.json 形式の追記型ログを置きます。 各書き込みが 1 JSON ファイル = 1 トランザクションに対応し、 過去任意のバージョンに戻る (time travel) ことができる。 10 トランザクションごとに .checkpoint.parquet が自動生成され、 メタ読み込みを高速化。
| 観点 | Iceberg | Delta Lake | Hudi |
|---|---|---|---|
| 主要パトロン | Netflix → Apache | Databricks → Linux Foundation | Uber → Apache |
| エンジン互換 | 広い (Trino/Snowflake/Athena) | Spark 強い | Spark/Flink 強い |
| スキーマ進化 | 列追加・順序変更可 | add only | add only |
| CDC (差分取り込み) | v3 で改善中 | 標準サポート | 最大の強み |
マルチエンジン (Snowflake + Trino + Spark) なら Iceberg、 Databricks 中心なら Delta、 ストリーミング CDC なら Hudi が定番。
レイクの中身が増えるほど「誰がアクセスできるか」「個人情報は混入していないか」「監査ログは残っているか」が経営イシューになります。 押さえるべき 7 つの観点を整理します。
データレイクを中心に、 隣接する データウェアハウス (DWH)・データレイクハウス・データマート・ETL/ELT・データカタログ・メタデータ管理との関係を整理した。 SSDSE-B-2026 の原本 CSV・整形済み parquet・結合キー・利用条件メタデータ・派生図表を「再利用できる状態で残す」ためにどの構成要素が必要かの俯瞰図として使える。
概念マップは「データレイク」を 3 つの隣接技術と接続する。 上方の Apache Hudi / Iceberg / Delta Lake は、 純粋なオブジェクトストレージ (S3, GCS) に ACID トランザクションと time-travel を載せる「テーブルフォーマット」で、 データレイクをデータウェアハウスに近づける現代の主流技術。 左方の CDC (Change Data Capture) は基幹 DB の変更を準リアルタイムでレイクに反映する仕組みで、 デバジウム (Debezium) などが代表実装。 右下の レイクハウスフェデレーション は複数レイク横断クエリを実現する Databricks 提案概念。
SSDSE-B-2026 のような確定済み公開データであれば素の CSV/Parquet をオブジェクトストレージに置くだけで十分機能するが、 業務システムから流入する更新頻度の高いデータでは Iceberg + CDC の組み合わせが事実上の標準となりつつある。 データレイクの「スキーマオンリード」思想は柔軟性が高い反面、 ガバナンスが弱いとデータスワンプ (沼) 化する常識的なリスクがあるため、 上記テーブルフォーマットによるスキーマ管理が必須となる。
データレイクは収集とウェアハウス、 分散処理の中継基盤。 3 視点 (接続・統合・比較) で隣接蓄積基盤との関係を整理する。
取り込み → 生データ層 (raw) → クレンジング層 (cleansed) → 集計層 (curated) → 配信の流れで、 メタデータカタログとスキーマオンリード (read 時にスキーマ解釈) が運用効率を決める。 SSDSE のような小規模データなら lake は過剰だが、 学校・自治体データを横断的に蓄えるならレイク + ガバナンスの組合せが有効。
| 基盤 | 蓄積対象 | スキーマ | 典型用途 |
|---|---|---|---|
| データレイク | 構造化 + 非構造化 | スキーマオンリード | 多様データ蓄積 |
| データウェアハウス (DWH) | 構造化のみ | スキーマオンライト | BI・集計分析 |
| レイクハウス | 構造化 + 非構造化 | 両方 | レイク + DWH 統合 |
| OLTP DB | 構造化トランザクション | スキーマオンライト | 業務システム |
4 基盤は用途が異なる。 レイクは多様性、 DWH は集計性能、 レイクハウスは両立、 OLTP は業務処理を担う。 SSDSE は CSV 数 MB なので lake は不要だが、 公的データを多数取り込む研究機関なら lake + ガバナンスの組合せが現実解。
データレイクは構造化 / 非構造化を区別せず生データを蓄積し、 ガバナンスで秩序化する。
生データ蓄積なら data lake、 構造化集計なら DWH、 両者統合なら lakehouse、 と「データ性質と利用パターン」で選ぶ。
本ページ前半でも触れた schema on read の核心を、 別角度から言い直す。 データレイクの本質は「データを捨てない・型を急いで決めない」という一点に尽きる。 CSV・JSON・ログ・画像・音声を、 変換せずそのままの形で置く。 型 (スキーマ) を当てるのは読み出すその瞬間であって、 蓄える時ではない。 これが データウェアハウス (DWH) の schema on write (入れる前に整形・型固定) と正反対の思想だ。
レイクが受け入れる形式は大きく 3 種類。 レイクの「多様性」はこの混在を許すことで生まれる。
| 分類 | 例 | スキーマ | レイクでの扱い |
|---|---|---|---|
| 構造化 | SSDSE-B-2026.csv、 RDB エクスポート | 行×列が明確 | そのまま置く / 後で Parquet 化 |
| 半構造化 | JSON ログ、 XML、 API レスポンス | タグ・キーはあるが不定形 | 読む時に展開 (flatten) |
| 非構造化 | 画像、 音声、 PDF、 自由記述 | なし | バイナリのまま格納、 メタで管理 |
DWH は「質問が先に決まっている」データに強い ── 定型の月次売上集計、 KPI ダッシュボードのように「何を集計するか」が既知なら、 入れる時に整形しておけば読み出しが速い。 レイクは「質問がまだ決まっていない」データに強い ── 将来どう使うか未知の IoT ログや SNS を、 とりあえず失わずに貯めておける。 ETL (整形してから入れる) が DWH 型、 ELT (入れてから整形する) がレイク型の処理順序に対応する点も押さえておきたい。
レイクの「何でも入れられる」は諸刃の剣だ。 本ページ前半の落とし穴群を、 「なぜ起きるか」の因果でまとめ直す。 最重要はデータスワンプ (沼) 化 ── これはメタデータ・カタログ・命名規約という「秩序装置」を後回しにした結果として、 ほぼ必然的に起きる。
| 落とし穴 | 根本原因 | 対策の勘所 |
|---|---|---|
| データスワンプ化 | 「入れる自由」に「探せる仕組み」が伴わない | メタデータカタログを初日から必須化 |
| 発見可能性の欠如 | 誰が何を入れたか記録されない | 出典・取得日・粒度をファイル名とカタログに |
| データ品質の担保不足 | schema on read で検証が読む側に転嫁 | Silver 層で型・欠損・重複を検査 |
| 権限・セキュリティの穴 | 「全部入り」バケットに機密が混入 | 個人情報ゾーン分離+ガバナンス規程 |
| コスト膨張 | 「捨てない」思想が蓄積量を青天井に | ライフサイクル (IA→Glacier→削除) 設定 |
| スキーマオンリードの負担 | 読むたびに型変換・整形が走る | よく使う切り口は Gold 層に事前集計 |
要するに、 レイクは「蓄積は安いが、 秩序は高い」。 ストレージ単価が下がっても、 発見可能性・品質・権限・コスト管理という運用コストは自動では下がらない。 「入れるのが簡単」であることと「使えること」は別問題だ、 という一点を常に思い出すこと。
レイクの現在地を、 隣接概念の座標系で整理する。 いずれも本ページ各所で触れているが、 ここで一枚の見取り図にまとめる。 なお レイクハウス・データメッシュ・オブジェクトストレージの単独解説ページは本用語集には未整備のため、 以下では用語として説明する。
| 概念 | 一言で | レイクとの関係 |
|---|---|---|
| DWH | 整形済み構造化データの分析専用倉庫 | 対比軸 (schema on write) |
| レイクハウス | レイクにテーブル形式で ACID を載せた統合形 | レイクの進化形 (両者の中間) |
| メダリオン | Bronze/Silver/Gold の品質階層 | レイク内の精錬パターン |
| スキーマオンリード | 読む時に型を当てる方式 | レイクの根本思想 |
| データカタログ | メタデータ・系譜の中央集約 | 沼化を防ぐ秩序装置 |
| データメッシュ | ドメイン主導でデータを分散所有 | 組織論的な発展形 |
| オブジェクトストレージ | S3/GCS/Blob、 レイクの物理基盤 | レイクの土台 (実体) |
| Delta / Iceberg | Parquet 上に載せるテーブル形式 | レイクを DWH に近づける |
処理の流れとしては、 データエンジニアリングの ELT パイプライン (しばしば ETL/ELT ツールで自動化) がレイクへの投入を担い、 DataFrame や BI がレイクからの読み出しを担う。 業務 RDB の変更を CDC でレイクへ反映する構成も定番だ。
レイクの「原型のまま蓄積」を、 実データの規模感で確認する。 SSDSE-B-2026.csv (cp932、 単位行 skiprows=[1] を除外) は以下の実測値をもつ。 これをそのまま Bronze 層に置くのがレイク的な第一歩だ。
| 項目 | 実測値 | 備考 |
|---|---|---|
| ファイルサイズ | 約 351.4 KB (359,821 bytes) | CSV そのまま |
| データ行数 | 564 行 | ヘッダ + 単位行を除く |
| 列数 | 112 列 | Code・Prefecture + 統計指標 |
| 構成 | 47 都道府県 × 12 年 | 2012〜2023 年 |
この 351.4 KB という規模感が要点だ。 レイクの本領は「多源・大規模・時系列」が揃ってこそ発揮される。 SSDSE-B-2026 単体 (数百 KB) なら、 本ページ前半でも述べたとおり単純なファイル管理で十分であり、 レイクは過剰。 一方で「原本 CSV を Bronze に固定し、 Parquet を Silver、 都道府県×年の集計を Gold に置く」という層の分け方そのものは、 数百 KB でも再現性向上に効く ── これが「小さく始めて大きく育てる」レイク思想の学習用の入口となる。 なお 564 行 × 112 列という実際の形状以外の集計値 (仮に PB 級へ拡張した場合のコスト等) は本文中でも架空の試算として明示している点に留意。