powerbi-to-sl について
powerbi-to-slは、既存のPower BIアーティファクトをKeboola Semantic Layer用のJSONペイロードに移行するスキルです。既存モデルを移行するチーム向けで、構造を機械的に対応付け、DAXをレビュー用に保持し、確認後のプッシュに対応します。
主な機能
- 01TMDLとテーブル別JSONの入力を判定
- 02テーブル、メジャー、リレーションを対応付け
- 03DAX式を保持し警告を提示
- 04JSON Schemaで出力を検証
- 05確認後のプッシュまたはsl-toolkitへの引き継ぎ
活用シーン
- 01Power BIモデルをKeboola SLへ移行
- 02SQL書き換え前にDAXメジャーを確認
- 03セマンティックレイヤーのペイロードを作成・検証
MCP 対応
必要に応じてMicrosoft Power BI Modeling MCPの読み取り専用モードでTMDLを生成できます。公開処理をsl-toolkitに引き継ぐこともできます。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ keboola/ ai-kit --skill powerbi-to-slインストール後、Claude Code で/powerbi-to-slを入力して読み込まれたか確認します。
詳細
powerbi-to-sl — Power BI → Keboola Semantic Layer の移行
既存の PowerBI アーティファクトを読み込み → Keboola SL のペイロードにマッピング → JSON ファイルに書き込み → ユーザーが確認 → sl-toolkit または直接 REST 経由でプッシュします。sl-toolkit(グリーンフィールド)の補完ツールであり、こちらはブラウンフィールド向けの方法です。
ステップ 0 — 入力を特定する
PowerBI アーティファクトの場所をユーザーに尋ねてから、形式を自動検出します。
INPUT_DIR="$(read -p 'Path to PowerBI artifacts: ' x; echo "$x")"
python3 -c "
import os, sys
p = sys.argv[1]
tmdl = [f for f in os.listdir(p) if f.endswith('.tmdl')] if os.path.isdir(p) else []
jsons = [f for f in os.listdir(p) if f.endswith('_semantic_layer.json')] if os.path.isdir(p) else []
if tmdl: print('tmdl')
elif jsons: print('per-table-json')
else: print('unknown')
" "$INPUT_DIR"
unknown の場合は、ユーザーに確認を求めるか、Microsoft の Power BI Modeling MCP を --readonly でデータセットに対して実行し、まず TMDL を生成してもらいます。
ステップ 1 — ビジネス上の質問(マッピングの前に確認)
「簡単な質問が 3 つあります。
- これらのテーブルに使用する Keboola バケットのプレフィックスは何ですか?(例:
in.c-pbi-migration— 各 semantic-dataset のtableIdの構築に使用します)- セマンティックモデル名と表示名は何ですか?(例:
acme-pbi-migration/ "Acme Power BI Migration")- Snowflake と BigQuery のどちらの方言を使用しますか?(デフォルト:Snowflake)」
回答を BUCKET_PREFIX、MODEL_NAME、MODEL_DISPLAY、DIALECT として保存します。
ステップ 2 — マイグレーターを実行する
python3 scripts/migrate.py \
--input "$INPUT_DIR" \
--input-format "$FORMAT" \
--bucket-prefix "$BUCKET_PREFIX" \
--model-name "$MODEL_NAME" \
--model-display "$MODEL_DISPLAY" \
--dialect "$DIALECT" \
--output ./out/
出力レイアウト:
out/
semantic-model.json
semantic-dataset/
<bucket-prefix>.<table>.json # one per PowerBI table
semantic-metric/
<measure-slug>.json # one per PowerBI measure
semantic-relationship/
<from>__<to>.json # one per PowerBI relationship
WARNINGS.md # DAX-not-translated, unmapped types, etc.
ステップ 3 — ユーザーと WARNINGS.md を確認する
マイグレーターは DAX メジャー式を semantic-metric.sql にそのまま保持します。ユーザーに WARNINGS.md を見せ、次のどれにするか尋ねます。
- 後回しにする — DAX はそのままにし、後続の Kai(または人間)が必要に応じて SQL に書き換えます。
- 簡単なケースを自動翻訳する —
SUM('Table'[Col])→SUM("Table"."Col")、COUNT、DISTINCTCOUNT、AVERAGE。CALCULATE、フィルターコンテキスト、RELATED、時間インテリジェンス、または変数を含むものには引き続きフラグを付けます。 - 人手で対応する — WARNINGS のリストを開き、1 行ずつ書き換えます。
デフォルト:後回しにしてリストを表示します。簡単なケースの翻訳はオプトインです。
ステップ 4 — Keboola SL スキーマに対して検証する(jsonschema)
python3 -c "
import json, jsonschema, glob, sys, os
schemas_dir = os.environ['SCHEMAS_DIR']
schemas = {
name: json.load(open(f'{schemas_dir}/semantic-{name}_schema_1.0.0.json'))
for name in ['model','dataset','metric','relationship']
}
errs = 0
for kind, schema in schemas.items():
pattern = './out/semantic-model.json' if kind == 'model' else f'./out/semantic-{kind}/*.json'
for f in glob.glob(pattern):
try:
jsonschema.validate(json.load(open(f)), schema)
except jsonschema.ValidationError as e:
errs += 1
print(f'❌ {f}: {e.message}')
print(f'{errs} validation errors' if errs else '✅ all valid')
"
同じ検証は tests/test_smoke.py の pytest アサーションとしても実行されます。Keboola metastore の semantic-* JSON スキーマを含むディレクトリを SCHEMAS_DIR に設定してください。
ステップ 5 — プッシュする(任意、ユーザーの確認後に実行)
書き込みを行う前に、必ずユーザーに確認します。方法は 2 つあります。
方法 A — sl-toolkit 経由(そのプラグインがインストールされている場合に推奨。標準的な生成–検証–プッシュのパイプラインを担います):
「
sl-toolkitに引き継ぎますか? SL モデルの標準的なプッシュパイプラインを担います。それとも、メタストアの REST API に直接プッシュしますか?」
sl-toolkit が選択された場合は、--source ./out/ を指定して、そのプッシュステップを実行します。
方法 B — 直接 REST(sl-toolkit が利用できない場合):
import json, os, urllib.request, glob
from concurrent.futures import ThreadPoolExecutor
TOKEN = os.environ['KBC_STORAGE_TOKEN']
METASTORE = os.environ['KBC_METASTORE_URL'] # e.g. https://metastore.us-east4.gcp.keboola.com
def post(kind, payload):
req = urllib.request.Request(
f'{METASTORE}/api/v1/repository/semantic-{kind}',
data=json.dumps(payload).encode(),
headers={'X-StorageAPI-Token': TOKEN, 'Content-Type': 'application/json'},
method='POST')
return urllib.request.urlopen(req, timeout=30).read()
# Model first — get the UUID, propagate to children
model_uuid = json.loads(post('model', json.load(open('./out/semantic-model.json'))))['data']['id']
for kind in ['dataset','metric','relationship']:
payloads = []
for f in glob.glob(f'./out/semantic-{kind}/*.json'):
p = json.load(open(f))
p['modelUUID'] = model_uuid
payloads.append(p)
with ThreadPoolExecutor(max_workers=10) as ex:
list(ex.map(lambda p: post(kind, p), payloads))
マッピングの参照
| Power BI | Keboola SL |
|---|---|
tables[].name | semantic-dataset.name + tableId |
tables[].description | semantic-dataset.description |
tables[].columns[].name | semantic-dataset.fields[].name |
tables[].columns[].dataType | semantic-dataset.fields[].type * |
tables[].columns[].description | semantic-dataset.fields[].description |
| 主キー列のヒント | semantic-dataset.primaryKey |
tables[].measures[].expression (DAX) | semantic-metric.sql(そのまま) |
tables[].measures[].description | semantic-metric.description |
relationships[] | semantic-relationship |
型のマッピング: string→string、int64/integer→integer、
double/decimal/currency→decimal、dateTime/date→datetime/date、
boolean→boolean。不明な型は string にフォールバックし、ログに記録されます。
既知の注意点
- テーブルごとの JSON では Power Query M のステップが失われます。 以前の
get_semantic_modelの出力では M 式を取得できません。完全な 忠実性が必要な場合は、Microsoft の Power BI Modeling MCP を--readonlyフラグ付きで再実行して TMDL を生成してください。TMDL では DAX と M がネイティブに取得されます。 - DAX ≠ SQL です。 デフォルトではそのまま保持し、後続の Kai または
人間が変換します。
CALCULATE、RELATED、時系列分析、変数は 単純な変換では維持できません。 - PowerBI のテーブル名には空白や非 ASCII 文字が含まれます。 ファイル名にはスラッグ化した名前を使い、
name/displayNameには元の名前を保持してください。UTF-8 のパスは macOS/Linux では問題ありませんが、ファイルシステムに癖のある環境では注意してください。 - PK の検出はベストエフォートです。 Power BI では PK が明示的にマークされていないことがあります。マイグレーターは、(a)TMDL の明示的な
isKeyマーカー、(b)ヒューリスティックとしてのリレーションシップのto列、(c)空の primaryKey とユーザーに選択を求める WARNINGS エントリへのフォールバック、を使用します。 - リレーションシップのカーディナリティ。
manyToOneとoneToOne→inner、oneToMany→ 「多」側からのleftです。manyToManyの場合は WARNINGS エントリが生成されます。SL モデルはスター・スキーマとの親和性を想定しています。
2 つのスキルが存在する理由(powerbi-to-sl と sl-toolkit)
| 観点 | sl-toolkit | powerbi-to-sl(このスキル) |
|---|---|---|
| 方向 | 新規構築(Keboola のテーブル → SL) | 既存環境(Power BI → SL) |
| 入力 | Keboola ストレージ + SQL 変換 | TMDL フォルダーまたはテーブルごとの JSON |
| 生成 | スキーマ + KPI に基づく LLM 主導 | 構造を機械的に変換 |
| 検証 | 自動修正 + LLM による批評 | jsonschema による検証 + WARNINGS |
| プッシュ | プッシュパイプラインを管理 | プッシュを sl-toolkit に引き継ぐ |
両方がインストールされている場合、このスキルは SL ペイロードを生成し、プッシュを
sl-toolkit に委任します。重複ではなく、再利用です。