jaffle_shopでOpenMetadataを実践してみた
はじめに
dbt でデータモデリングをしていると、「このテーブルどこから来てるんだっけ?」「このカラムの意味って何だったっけ?」という疑問が出てきます。モデルが増えてくると特にそう感じます。
そこで今回は OpenMetadata を試してみました。オープンソースのデータカタログ・データリネージツールで、dbt との連携機能が充実しているとのこと。おなじみの jaffle_shop プロジェクトを使って、実際にメタデータを取り込んでリネージを確認するところまでやってみます。
今回の構成は dbt + PostgreSQL です。jaffle_shop を PostgreSQL 上に構築し、OpenMetadata の PostgreSQL コネクタでテーブルを取り込み、さらに dbt 連携でリネージ・説明・テスト結果を重ねていく、という流れで進めます。
OpenMetadata とは?
一言で言うと、データの「地図」を作るためのプラットフォームです。
データカタログ・リネージ・データ品質・チームコラボレーションなどを一元管理できるオープンソースツールで、90 以上のコネクタが用意されています。データベースに接続してスキーマを自動取り込みし、dbt の manifest.json を読み込むことでモデルの説明・テスト結果・依存関係(リネージ)を重ねられます。
DataHub が「dbt の manifest を起点にメタデータを構築する」スタイルなのに対し、OpenMetadata は「まず実データベースにコネクタで接続してスキーマを取り込み、そこに dbt 情報を重ねる」スタイルです。この違いは後で効いてきます。
開発元は Collate(旧 OpenMetadata 社)で、活発に開発が続いています。データカタログ・リネージにとどまらず、データプロファイリング・データ品質テスト・PII 自動分類・ガバナンス・コラボレーションまで、メタデータまわりを「ひとつのナレッジグラフ」に集約しようとしているのが特徴です。今回はその機能群を jaffle_shop で一通り触っていきます。
OpenMetadata のアーキテクチャを理解する
機能を触る前に、内部構成を軽く押さえておきます。ここを知っておくと「なぜプロファイリングやテストがネイティブにできるのか」が腑に落ちます。
主要コンポーネント
docker compose up で立ち上がるコンテナは、ざっくり次の4つです。
-
server(API サーバ): Java 製のメタデータ API。ポート
8585で REST API と UI を提供します。OpenMetadata の中心。 - MySQL: メタデータの本体を保存するプライマリストア(PostgreSQL も選択可)。
- Elasticsearch: 検索インデックス。Explore 画面の全文検索や絞り込みはここが支えます。
- ingestion: Airflow ベースの取り込み実行基盤。UI からスケジュール取り込みを回すときに使います。
DataHub が Kafka を中核に据えたイベント駆動なのに対し、OpenMetadata は MySQL + Elasticsearch というシンプルな2本柱です。構成がコンパクトなぶん、起動に必要なメモリも 6GB 程度と軽めです。
メタデータモデル — JSON Schema と Fully Qualified Name
OpenMetadata のメタデータモデルは JSON Schema で定義されています。テーブル・カラム・ダッシュボード・パイプライン・用語(GlossaryTerm)・チーム(Team)といった Entity がスキーマで厳密に型付けされていて、各エンティティは Fully Qualified Name(FQN) で一意に識別されます。
今回の customers テーブルなら、FQN はこうなります。
jaffle_shop_postgres.analytics.jaffle_shop.customers
サービス名.データベース.スキーマ.テーブル という階層がそのまま名前になっていて、直感的です。後で出てくる API 呼び出しでは、この FQN をキーにメタデータを読み書きします。
環境のセットアップ
前提条件
今回の構成です。
- macOS(Apple Silicon)
- Docker Desktop(メモリ割り当て: 6GB 以上)
- dbt + PostgreSQL(jaffle_shop を構築するため)
- jaffle_shop のデータが PostgreSQL にロード済みであること
jaffle_shop を PostgreSQL に構築する
まず取り込み対象のデータを用意します。jaffle_shop プロジェクトを PostgreSQL に向けて dbt build します(profiles.yml の target を PostgreSQL にしておきます)。
# 生データのロード + モデル構築 + テスト
dbt seed --vars '{"load_source_data": true}'
dbt build
これで PostgreSQL の raw スキーマに生データ、jaffle_shop スキーマに customers・orders などのモデルが構築されます。あとで dbt 連携に使うので、メタデータファイルも生成しておきます。
dbt docs generate # catalog.json も生成される
target/ に manifest.json・run_results.json・catalog.json が揃っていれば準備完了です。
Docker で OpenMetadata を起動する
OpenMetadata は Docker Compose で起動します。公式が配布している docker-compose.yml をダウンロードして立ち上げます。
mkdir openmetadata-local && cd openmetadata-local
curl -sL https://github.com/open-metadata/OpenMetadata/releases/download/1.5.14-release/docker-compose.yml -o docker-compose.yml
docker compose up -d
MySQL・Elasticsearch・server・ingestion などのコンテナが立ち上がります。初回は初期化に数分かかります。
OpenMetadata にログインする
ブラウザで http://localhost:8585 を開くとログイン画面が表示されます。

デフォルトの認証情報でログインします。
-
Username:
admin@open-metadata.org -
Password:
admin

ダッシュボードが表示されました。上部メニューの「Explore」「Settings」「Govern」などから各機能に移動できます。さっそく PostgreSQL のメタデータを取り込んでいきましょう。
PostgreSQL サービスを登録する
OpenMetadata では、データを取り込む前に「どのデータソースから取り込むか」を サービス として登録します。Settings → Services → Databases から「Add New Service」を開くと、コネクタの選択画面が出ます。

Athena、BigQuery、Databricks、MySQL、Oracle、Redshift…と、データベース系のコネクタがずらりと並んでいます。今回使う Postgres(象のアイコン)もちゃんと用意されています。OpenMetadata は主要なデータベースを一通りカバーしているので、PostgreSQL のような定番 DB はこうして公式コネクタで素直に接続できます。
Postgres を選んで、サービス名(今回は jaffle_shop_postgres)と接続情報を設定します。
メタデータを取り込む
サービスの取り込み(ingestion)には2つの方法があります。
- UI から実行: OpenMetadata の画面でスケジュールを設定して実行する。裏で Airflow が取り込みパイプラインを回す。
-
metadataCLI から実行: 取り込み設定を YAML で書き、metadata ingestコマンドで直接実行する。
UI 方式は Airflow の連携が前提になるので、今回は手軽な metadata CLI を使います。Python パッケージとしてインストールできます。
pip install "openmetadata-ingestion[postgres]==1.5.14"
取り込み設定(レシピ)を書く
PostgreSQL からメタデータを取り込む YAML を用意します。serviceName は先ほど登録したサービス名に合わせ、schemaFilterPattern で対象スキーマ(raw と jaffle_shop)を絞ります。
source:
type: postgres
serviceName: jaffle_shop_postgres
serviceConnection:
config:
type: Postgres
username: postgres
authType:
password: password
hostPort: localhost:5432
database: analytics
sourceConfig:
config:
type: DatabaseMetadata
schemaFilterPattern:
includes:
- "^raw$"
- "^jaffle_shop$"
sink:
type: metadata-rest
config: {}
workflowConfig:
openMetadataServerConfig:
hostPort: http://localhost:8585/api
authProvider: openmetadata
securityConfig:
jwtToken: "<ingestion-bot の JWT トークン>"
JWT トークンは OpenMetadata の Settings → Bots → ingestion-bot から取得できます。
取り込みを実行する
metadata ingest -c postgres_ingest.yaml
実行すると、こんな感じの出力が表示されます。
Workflow Postgres Summary:
Processed records: 23
Updated records: 0
Errors: 0
Success %: 100.0
Workflow finished in time: 6.71s
PostgreSQL の raw と jaffle_shop スキーマのテーブルが、エラーなく 100% 取り込まれました。コネクタが実 DB に接続してスキーマを introspect してくれるので、テーブル名・カラム名・データ型まで自動で入ります。
Settings → Services → Databases から jaffle_shop_postgres サービスを開くと、取り込まれた analytics データベースが確認できます。

dbt 連携でリネージ・説明・テストを取り込む
コネクタだけだとテーブルとカラムは揃いますが、リネージ(依存関係)やモデルの説明、dbt test の結果は入りません。ここで dbt 連携の出番です。先ほど生成した manifest.json・run_results.json・catalog.json を OpenMetadata に取り込みます。
dbt 連携用のプラグインを追加して、
pip install "openmetadata-ingestion[dbt]==1.5.14"
dbt 取り込み用の YAML を書きます。serviceName は PostgreSQL サービスと同じ にするのがポイントです(同じサービスのテーブルに dbt 情報を重ねるため)。
source:
type: dbt
serviceName: jaffle_shop_postgres
sourceConfig:
config:
type: DBT
dbtConfigSource:
dbtConfigType: local
dbtManifestFilePath: ./target/manifest.json
dbtRunResultsFilePath: ./target/run_results.json
dbtCatalogFilePath: ./target/catalog.json
sink:
type: metadata-rest
config: {}
workflowConfig:
openMetadataServerConfig:
hostPort: http://localhost:8585/api
authProvider: openmetadata
securityConfig:
jwtToken: "<ingestion-bot の JWT トークン>"
metadata ingest -c dbt_ingest.yaml
Workflow dbt Summary:
Processed records: 93
Errors: 0
Success %: 100.0
93 レコードが処理され、テーブルに dbt のメタデータが重なりました。
OpenMetadata で確認してみる
取り込んだメタデータを見ていきましょう。
検索とディスカバリ
上部の「Explore」を開くと、取り込んだデータ資産を横断的に探索できます。

左サイドバーには Databases・Dashboards・Pipelines・ML Models・APIs… とアセットの種類が並び、jaffle_shop_postgres サービスの analytics データベース配下に raw スキーマ(生データ)と jaffle_shop スキーマ(モデル)のテーブルが見えます。すべて PostgreSQL(象のアイコン)から取り込まれたものです。
この検索は Elasticsearch が支えていて、テーブル名だけでなく説明文・カラム名・タグ・用語集まで含めた全文検索ができます。画面上部の Domain / Owner / Tag / Tier / Service / Service Type といったフィルタで絞り込めるほか、Advanced から条件を組み合わせた高度な検索も可能です。たとえば「Tier1 かつ PII タグの付いたテーブル」のように、ガバナンス情報を使った横断検索ができます。
カラム定義の確認
customers テーブルを開いて Schema タブを見てみます。

customer_id(text)、customer_name(text)、count_lifetime_orders(bigint)、first_ordered_at(timestamp)…と、各カラムの型がコネクタ経由で正確に入っています。さらに「Customers' full name.」「Total number of orders a customer has ever placed.」といった説明文は、dbt の schema.yml から重ねられたものです。テーブル全体の説明「Customer overview data mart, offering key details for each unique customer.」も dbt 由来です。
タブには Schema のほかに「Profiler & Data Quality」「Lineage」「dbt」などが並んでいます。順番に見ていきましょう。
dbt モデルの定義
「dbt」タブを開くと、そのテーブルの元になった dbt モデルの SQL がそのまま表示されます。

models/marts/customers.sql の中身が確認できます。{{ ref('stg_customers') }} のような dbt の記法もそのまま見えるので、「このテーブルって結局どういう SQL で作られてるの?」がカタログから直接たどれます。
データリネージの確認
一番の目的だったリネージです。customers の Lineage タブを開いてみると…

raw_customers → stg_customers、orders・order_items → customers という変換の流れがグラフで表示されました。このリネージは dbt の ref() から自動生成されたもので、コネクタで取り込んだ物理テーブル同士がきちんとつながっています。
orders テーブルのリネージも見てみましょう。

raw_orders から stg_orders・stg_order_items・stg_products・stg_supplies を経て order_items、そして orders、最終的に customers へ——という多段の依存関係が一目でわかります。ノードをクリックすると、そのテーブルの詳細ページにジャンプできます。「このテーブルどこから来てるんだっけ?」がすぐ解消されますね。
リネージ画面の上部には Domain / Owner / Tag / Column といった絞り込みもあり、OpenMetadata は カラムレベルのリネージ(「このカラムは大元をたどるとどのソースカラムか」)にも対応しています。テーブル単位だけでなく、カラム単位で影響範囲を追えるのは、impact analysis の精度を上げてくれます。
データプロファイリング
ここからは OpenMetadata の真骨頂、ネイティブのデータプロファイラです。DataHub OSS では外部ツール頼みだった「データの中身の統計」を、OpenMetadata は標準機能で取得できます。
プロファイラは専用のワークフローで実行します。
source:
type: postgres
serviceName: jaffle_shop_postgres
serviceConnection:
config:
type: Postgres
username: postgres
authType:
password: password
hostPort: localhost:5432
database: analytics
sourceConfig:
config:
type: Profiler
generateSampleData: true
schemaFilterPattern:
includes:
- "^jaffle_shop$"
processor:
type: orm-profiler
config: {}
sink:
type: metadata-rest
workflowConfig:
openMetadataServerConfig:
hostPort: http://localhost:8585/api
authProvider: openmetadata
securityConfig:
jwtToken: "<JWT トークン>"
metadata profile -c profiler.yaml
テーブルプロファイル
customers の「Profiler & Data Quality」→「Table Profile」を開くと、テーブル全体の統計が表示されます。

Row Count 935、Column Count 9、Profile Sample 100%。下には「Data Volume(行数の推移)」のグラフもあります。プロファイラを定期実行すれば、行数の増減やデータ量の変化を時系列で追えるようになります。
カラムプロファイル
「Column Profile」では、カラムごとの統計が一覧で見られます。

customer_id は NULL 0%・ユニーク 100%(主キーらしい)、customer_name はユニーク 99%、count_lifetime_orders は distinct 20%…と、NULL 率・ユニーク率・distinct 率がバー付きで一目でわかります。「このカラム、欠損どれくらいあるんだっけ?」「実質何種類の値が入ってる?」が、SQL を書かずに把握できます。
実 DB に接続するコネクタ方式だからこそできる芸当で、ここは OpenMetadata がはっきり強い領域です。
データ品質テスト
OpenMetadata はデータ品質テストもネイティブに持っています。約30種類の組み込みテスト(NULL チェック・ユニーク・値域・行数・正規表現・カスタム SQL など)が用意されていて、UI や CLI、API からテストを定義・実行できます。
OpenMetadata でテストを定義する
dbt test とは別に、OpenMetadata 側でテストを定義してみます。テストワークフローで「customer_id はユニーク」「行数は 900〜1000 の範囲」といったテストを作って実行します。
source:
type: postgres
serviceName: jaffle_shop_postgres
serviceConnection:
config:
type: Postgres
username: postgres
authType:
password: password
hostPort: localhost:5432
database: analytics
sourceConfig:
config:
type: TestSuite
entityFullyQualifiedName: jaffle_shop_postgres.analytics.jaffle_shop.customers
processor:
type: orm-test-runner
config:
testCases:
- name: customer_id_should_be_unique
testDefinitionName: columnValuesToBeUnique
columnName: customer_id
- name: customer_count_in_expected_range
testDefinitionName: tableRowCountToBeBetween
parameterValues:
- name: minValue
value: "900"
- name: maxValue
value: "1000"
sink:
type: metadata-rest
workflowConfig:
openMetadataServerConfig:
hostPort: http://localhost:8585/api
authProvider: openmetadata
securityConfig:
jwtToken: "<JWT トークン>"
metadata test -c test.yaml
dbt test と OpenMetadata テストが同居する
customers の「Data Quality」を開くと、こうなります。

Total Tests 7・Success 100%。中身を見ると、
-
customer_id_should_be_unique、customer_count_in_expected_range… OpenMetadata で定義したテスト -
not_null_customers_customer_id、unique_customers_customer_id、dbt_utils_expression_is_true_...、accepted_values_...… dbt から取り込んだテスト
が1つの画面に同居しています。dbt で書いたテストはそのまま活かしつつ、dbt にないチェック(行数の範囲監視など)は OpenMetadata 側で足す、という運用ができます。
テストの失敗を Incident(インシデント) として管理したり、複数テストをまとめて Data Contract(データ契約) にする機能(1.8 以降)もあります。「テストの実行も定義も結果管理も1つのツールで完結させたい」というニーズには、OpenMetadata がよく応えてくれます。
ガバナンス機能
メタデータを「整理・統制」するためのガバナンス機能も一通り揃っています。
ビジネス用語集(Glossary)
業務用語を定義する Glossary です。jaffle_shop 向けに用語集を作ってみました。

「Jaffle Shop 用語集」の中に、顧客生涯価値(customers の lifetime_spend に対応)、アクティブ顧客 を定義しています。用語には承認フロー(Draft → Approved)があり、レビュアーを立てて運用することもできます。定義した用語は、関連するテーブルやカラムに紐付けてビジネス的な意味を与えられます。
分類(Classification)・Tier・ドメイン
OpenMetadata には、用途別のガバナンス用メタデータが揃っています。customers テーブルに一通り付けてみました。

-
Classification(分類タグ):
customer_nameカラムにSensitive(PII)を付与。個人情報を含むカラムが明示されます。 -
Tier: テーブルに
Tier1を設定。データの重要度を表し、「まず Tier1 から整備する」といった優先順位づけに使います。 -
Domain:
Marketingドメインに割り当て。業務領域でデータを束ねる、データメッシュ的な概念です。 -
Glossary Term: 右パネルに
顧客生涯価値が紐付いています。
ヘッダーに Marketing・Tier1 が並び、customer_name に Sensitive タグが付いた状態が一目でわかります。「このテーブルはマーケ領域の最重要データで、PII を含む」という文脈が、カタログを見るだけで伝わるようになりました。
PII の自動分類(Auto-Classification)
今回 PII タグは手で付けましたが、OpenMetadata には PII を自動検出してタグ付けする機能 もあります。プロファイラ実行時に processPiiSensitive: true を有効にすると、カラム名やサンプルデータを NLP で解析して「これは個人情報っぽい」というカラムに PII.Sensitive を自動で付けてくれます。
sourceConfig:
config:
type: Profiler
processPiiSensitive: true # PII を自動検出してタグ付け
コラボレーションと API
コラボレーション機能
OpenMetadata は「チームで使う」ことを強く意識した作りになっています。各テーブルには Activity Feed(アクティビティフィード) があり、説明の変更やタグの付与といった操作が時系列で流れます。さらに、
- Conversation: 特定のカラムや説明に対してコメントで会話できる
- Task: 「この説明を書いて」「このタグを確認して」といった依頼をタスクとして起票できる
- Announcement: テーブルに告知(メンテ予定など)を出せる
といった、Slack や GitHub のような協調作業の仕組みがカタログに組み込まれています。データに関する議論を、データのすぐ隣でできるわけです。
API と SDK
OpenMetadata の操作はすべて REST API で行えます。UI も裏ではこの API を叩いています。たとえば customers テーブルのメタデータを取得するなら、
curl "http://localhost:8585/api/v1/tables/name/jaffle_shop_postgres.analytics.jaffle_shop.customers" \
-H "Authorization: Bearer <JWT トークン>"
タグやドメインの付与も API(JSON Patch)でできます。実際、この記事の用語集・ドメイン・Tier・PII タグは API でまとめて付与しました。Python SDK も提供されていて、テストケースの定義やメタデータの一括更新をプログラムから行えます。120 以上のコネクタ、REST API、Python SDK に加えて、最近は AI 連携のための MCP サーバも用意されています。
アクセス制御(RBAC)
本番運用では、Roles & Policies によるアクセス制御が効いてきます。OpenMetadata は ロールベース(RBAC)+属性ベースのポリシー を組み合わせていて、「このチームはこのドメインのタグだけ編集できる」といった細かい権限設計ができます。ロールはユーザーだけでなく Team に割り当てられるので、組織構造に沿った権限管理がしやすいです。
OpenMetadata と DataHub の違い
姉妹編の DataHub 記事と合わせて、両者の違いを表で整理します。あくまで dbt + PostgreSQL を題材に触ってみた個人の感想です。
| 観点 | OpenMetadata | DataHub |
|---|---|---|
| アーキテクチャ | MySQL + Elasticsearch(シンプル・軽量) | + Kafka のイベント駆動(リッチ) |
| メタデータモデル | JSON Schema ベース | PDL ベース・拡張性が高い |
| 取り込みの起点 | 実 DB にコネクタ接続 → dbt を重ねる | dbt の manifest 起点 |
| カラムの型 | コネクタが introspect して正確に取得 | catalog.json があれば取得 |
| データプロファイラ | ネイティブ内蔵(行数・NULL率・分布) | OSS は外部頼み |
| データ品質テスト | ネイティブ内蔵(約30種)+ dbt 連携 | dbt / GE 連携で集約 |
| PII 自動分類 | NLP でネイティブ対応 | (限定的) |
| リネージ | テーブル・カラムレベル | テーブル・カラムレベル+Impact Analysis |
| ガバナンス | Glossary / 分類 / Tier / ドメイン / Team | Glossary / タグ / ドメイン / Data Product |
| コラボレーション | 会話・タスク・告知が充実 | Actions による自動化が強い |
| API | REST / Python SDK | REST / GraphQL / Kafka |
| 必要メモリ(ローカル) | 6GB | 8GB |
ざっくり言うと、
- OpenMetadata が向くケース: 実 DB にコネクタで素直につなぎたい。プロファイリングやデータ品質テストをツール1つで完結させたい。PII 自動分類やチームコラボレーションを重視する。
- DataHub が向くケース: dbt の manifest を中心に据えたい。GraphQL / Kafka でメタデータをプログラムから扱いたい。メタデータモデルを拡張したい。リアルタイム連携や自動化を組みたい。
まとめ
今回は jaffle_shop を PostgreSQL に構築し、OpenMetadata で一通りの機能を試しました。
PostgreSQL の公式コネクタで実 DB に接続してスキーマ(テーブル・カラム・型)を自動取り込みし、そこに dbt 連携でリネージ・説明・テスト結果を重ね、さらにプロファイラで統計を取り、OpenMetadata 側のテストやガバナンス(用語集・分類・Tier・ドメイン)を足していく——という流れで、データカタログ/データ品質/ガバナンスのプラットフォームとして一通り使える状態になりました。metadata CLI を使えば Airflow を別途構成しなくても各ワークフローを実行できるので、ローカル検証の敷居も低かったです。
特に良かったのは、
- コネクタが型まで正確に取り込み、プロファイラで中身の統計まで取れる(実 DB を introspect するため)
- データ品質テストを定義・実行・管理まで1つのツールで完結できる(dbt test も同居)
- 用語集・分類・Tier・ドメイン・PII 自動分類と、ガバナンス機能が厚い
という点です。dbt + ウェアハウス(PostgreSQL や Snowflake、BigQuery など、OpenMetadata がコネクタを持つ DB)という構成なら、素直かつ高機能に導入できると感じました。
姉妹編の DataHub 記事と読み比べると、「実 DB にコネクタで接続してから dbt を重ねる OpenMetadata」と「dbt の manifest を起点に構築する DataHub」という思想の違いが見えてきて面白いです。どちらも良いツールなので、自分たちのデータ基盤に合うほうを選んでみてください。
今回は jaffle_shop を使って OpenMetadata を実践しました。
PostgreSQL の公式コネクタで実 DB に接続してスキーマ(テーブル・カラム・型)を自動取り込みし、そこに dbt 連携でリネージ・モデルの説明・dbt test の結果を重ねる——という流れで、データカタログとして一通り使える状態になりました。metadata CLI を使えば Airflow を別途構成しなくても取り込みを実行できるので、ローカル検証の敷居も低かったです。
特に良かったのは、
- コネクタが型まで正確に取り込んでくれる(実 DB を introspect するため)
- dbt の説明・テスト・リネージがそのまま重なる(dbt にメタデータを集約しているほど効く)
- データ品質(テスト結果)をカタログと同じ場所で見られる
という3点です。dbt + ウェアハウス(PostgreSQL や Snowflake、BigQuery など、OpenMetadata がコネクタを持つ DB)という構成なら、素直に導入できると感じました。
姉妹編の DataHub 記事と読み比べると、「実 DB にコネクタで接続してから dbt を重ねる OpenMetadata」と「dbt の manifest を起点に構築する DataHub」という思想の違いが見えてきて面白いです。どちらも良いツールなので、自分たちのデータ基盤に合うほうを選んでみてください。
Discussion