0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Semantic LinkでMicrosoft FabricのセマンティックモデルをData Agent向けに整備する

0
Posted at

この記事でできること
Microsoft Fabric NotebookからPower BIセマンティックモデルへ接続し、テーブル、列、メジャーの説明(Description)を一覧取得・確認・更新する手順を紹介します。

はじめに

Microsoft Fabric Data Agentを使うと、ユーザーはデータに対して自然言語で質問できます。

たとえば、次のような質問です。

  • 先月の総売上はいくらですか?
  • 売上金額が最も大きい製品はどれですか?
  • 購入実績のある顧客は何人ですか?
  • 地域別の売上を表示してください。

Data AgentにPower BIセマンティックモデルを接続すると、Data Agentはモデル内のテーブル、列、メジャー、リレーションシップ、メタデータなどを参照し、ユーザーの質問をDAXクエリへ変換します。

しかし、テーブルやリレーションシップ、DAXメジャーが正しく作成されていても、AIが業務上の意味まで正しく理解できるとは限りません。

たとえば、モデルには次のような技術的な名前が含まれていることがあります。

factinternetsales
dimcustomer
CustomerKey
SalesAmount

※サンプル画面
image.png

これらは開発者には理解しやすくても、業務上の意味までは十分に表していません。そのため、本記事ではMicrosoft Fabric NotebookとSemantic Link Labsを使い、セマンティックモデルのテーブル、列、メジャーに説明を付与する方法を紹介します。

1. どのような課題を解決するのか

たとえば、セマンティックモデルに次の列があるとします。

factinternetsales[SalesAmount]

image.png

列名から「売上金額」であることは推測できます。しかし、次の内容までは分かりません。

  • 総売上ですか、それとも純売上ですか?
  • 税金は含まれていますか?
  • 返品やキャンセルは除外されていますか?
  • どの通貨を使用していますか?
  • 列を直接集計するべきですか、それともDAXメジャーを使用するべきですか?

Data Agentが正しいDAXクエリを生成するには、このような業務コンテキストが重要です。

業務コンテキストが不足していると、次のような問題が起きる可能性があります。

  • 適切でない列やメジャーを選択する
  • 誤った日付列を使用する
  • 業務用語を正しく解釈できない
  • 意図と異なるDAXクエリを生成する
  • 技術的には成立しているものの、業務定義とは異なる回答を返す

Microsoft Learnでも、Fabric Data Agentの回答品質は、セマンティックモデルのスキーマ、メタデータ、Prep for AIの構成などに大きく左右されると説明されています。

2. 解決方法

セマンティックモデルの主なオブジェクトに、分かりやすい説明を追加します。

テーブルの説明

テーブルにどのような情報が含まれているかを説明します。

例:

顧客別のインターネット売上を分析するための顧客情報を格納します。

列の説明

各フィールドの業務上の意味を説明します。

例:

セマンティックモデル内で顧客を一意に識別するためのキーです。

メジャーの説明

DAXメジャーが何を計算するかを説明します。

例:

現在のレポートフィルター条件に基づいて、インターネット売上の合計を計算します。

この整備により、次の利用者や機能がモデルを理解しやすくなります。

  • Fabric Data Agent
  • Power BI Copilot
  • レポート開発者
  • データアナリスト
  • データサイエンティスト
  • 将来のモデル管理者

3. 処理の流れ

Notebookでは、次の順番で処理します。

セマンティックモデルへ接続
        ↓
テーブル、列、メジャーを取得
        ↓
説明が未設定のオブジェクトを確認
        ↓
追加する説明をマッピングとして準備
        ↓
変更内容をドライランで確認
        ↓
セマンティックモデルへ反映
        ↓
説明が保存されたことを検証

Semantic Linkは、Power BIセマンティックモデルとMicrosoft FabricのNotebook環境を接続する機能です。Pythonからセマンティックモデルのデータやメタデータへアクセスできます。

Semantic Link Labsは、Fabricアイテムを扱うための補助機能を提供するライブラリです。本記事では、Tabular Object Model(TOM)経由でセマンティックモデルのメタデータを更新します。

4. 前提条件

事前に次の環境を用意してください。

  • Microsoft Fabricワークスペース
  • ワークスペース内のPower BIセマンティックモデル
  • Fabric Notebook
  • 対象モデルを変更できる権限
  • XMLAエンドポイントのRead Write設定
  • 対象ワークスペース名とセマンティックモデル名

Data Agentからセマンティックモデルへ質問するだけであれば、モデルに対する読み取り権限で利用できます。一方、説明の更新やPrep for AIの構成など、モデルを変更する操作には書き込み権限が必要です。

推奨
最初は必ず開発用ワークスペースとサンプルのセマンティックモデルで検証してください。本番モデルから始めることは避けてください。

5. Fabric Notebookを作成する

Fabricポータルで次の操作を行います。

  1. 対象のセマンティックモデルがあるワークスペースを開きます。
  2. 新しいアイテムを選択します。
  3. Notebookを選択します。
  4. Notebookに分かりやすい名前を付けます。

例:

Update Semantic Model Descriptions

Notebookは、対象のセマンティックモデルと同じワークスペースに作成すると管理しやすくなります。

6. 必要なライブラリをインストールする

最初のセルで次のコードを実行します。

%pip install -U semantic-link semantic-link-labs

インストール後、別のセルでライブラリを読み込みます。

import pandas as pd
import sempy.fabric as fabric
import sempy_labs as labs

from sempy_labs.tom import connect_semantic_model

pd.set_option("display.max_rows", None)
pd.set_option("display.max_columns", None)
pd.set_option("display.max_colwidth", 150)

print("Libraries loaded successfully.")

Fabric Runtime 1.2以降ではSemantic Linkが標準で利用できますが、上記のコマンドを使用すると最新バージョンへ更新できます。

パッケージのインストール後にPythonセッションの再起動を求められた場合は、セッションを再起動し、インポート用セルをもう一度実行してください。

7. 対象ワークスペースとセマンティックモデルを指定する

環境に合わせて、次の値を変更します。

# 対象のFabricワークスペース
workspace = "Your-Workspace-Name"

# 対象のPower BIセマンティックモデル
# 一部のAPIでは、現在もdatasetという引数名が使用されています
# 製品上の名称はセマンティックモデルです
dataset = "Your-Semantic-Model-Name"

# False: 変更内容の確認のみ
# True : セマンティックモデルへ保存
commit_changes = False

# 非表示のテーブル、列、メジャーを対象に含めるか
include_hidden = False

print(f"Workspace: {workspace}")
print(f"Semantic model: {dataset}")
print(f"Commit changes: {commit_changes}")

例:

workspace = "Fabric-Lab"
dataset = "AdventureWorksSM"

最初の実行では、必ず次の状態にします。

commit_changes = False

これはドライランです。変更内容は表示されますが、モデルには保存されません。

※サンプル
image.png

8. セマンティックモデルへの接続を確認する

更新処理を行う前に、読み取り専用で接続できることを確認します。

with connect_semantic_model(
    dataset=dataset,
    workspace=workspace,
    readonly=True
) as tom:

    model_tables = [
        table.Name
        for table in tom.model.Tables
    ]

print("Connection successful.")
print("Tables found:")

for table_name in model_tables:
    print(f"- {table_name}")

今回は、AdventureWorksのサンプルモデルを使用しているので、次のようなテーブルが表示されます。

dimcustomer
dimdate
dimproduct
factinternetsales

※サンプル画面
image.png

接続に失敗する場合は、次を確認してください。

  • ワークスペース名
  • セマンティックモデル名
  • ワークスペースとモデルの権限
  • Fabric容量の状態
  • XMLAエンドポイントの設定
  • ライブラリのインストール状況

9. テーブル、列、メジャーの情報を取得する

9.1 テーブル一覧を取得する

table_rows = []

with connect_semantic_model(
    dataset=dataset,
    workspace=workspace,
    readonly=True
) as tom:

    for table in tom.model.Tables:

        if not include_hidden and table.IsHidden:
            continue

        table_rows.append({
            "type": "table",
            "table": table.Name,
            "name": table.Name,
            "description": table.Description or "",
            "is_hidden": bool(table.IsHidden)
        })

table_inventory_df = pd.DataFrame(table_rows)

display(table_inventory_df)

9.2 列一覧を取得する

column_rows = []

with connect_semantic_model(
    dataset=dataset,
    workspace=workspace,
    readonly=True
) as tom:

    for table in tom.model.Tables:

        if not include_hidden and table.IsHidden:
            continue

        for column in table.Columns:

            if not include_hidden and column.IsHidden:
                continue

            column_rows.append({
                "type": "column",
                "table": table.Name,
                "name": column.Name,
                "description": column.Description or "",
                "data_type": str(column.DataType),
                "is_hidden": bool(column.IsHidden)
            })

column_inventory_df = pd.DataFrame(column_rows)

display(column_inventory_df)

9.3 メジャー一覧を取得する

measure_rows = []

with connect_semantic_model(
    dataset=dataset,
    workspace=workspace,
    readonly=True
) as tom:

    for table in tom.model.Tables:

        if not include_hidden and table.IsHidden:
            continue

        for measure in table.Measures:

            if not include_hidden and measure.IsHidden:
                continue

            measure_rows.append({
                "type": "measure",
                "table": table.Name,
                "name": measure.Name,
                "description": measure.Description or "",
                "expression": measure.Expression,
                "format_string": measure.FormatString,
                "is_hidden": bool(measure.IsHidden)
            })

measure_inventory_df = pd.DataFrame(measure_rows)

display(measure_inventory_df)

※サンプル画面
image.png

10. 追加する説明をマッピングとして定義する

次のマッピングはAdventureWorksモデルを想定した例です。実際のモデルに合わせて、テーブル名、列名、メジャー名、説明文を変更してください。

mapping = [
    {
        "type": "table",
        "table": "dimcustomer",
        "name": "dimcustomer",
        "description": (
            "顧客別のインターネット売上を分析するための顧客情報を格納します。"
        )
    },
    {
        "type": "table",
        "table": "dimdate",
        "name": "dimdate",
        "description": (
            "日、月、四半期、年の単位で売上を分析するためのカレンダー日付を格納します。"
        )
    },
    {
        "type": "table",
        "table": "dimproduct",
        "name": "dimproduct",
        "description": (
            "製品別のインターネット売上を分析するための製品情報を格納します。"
        )
    },
    {
        "type": "table",
        "table": "factinternetsales",
        "name": "factinternetsales",
        "description": (
            "顧客、製品、日付、数量、売上金額を含むインターネット販売トランザクションを格納します。"
        )
    },
    {
        "type": "column",
        "table": "dimcustomer",
        "name": "CustomerKey",
        "description": (
            "セマンティックモデル内で顧客を一意に識別するためのキーです。"
        )
    },
    {
        "type": "column",
        "table": "dimdate",
        "name": "DateKey",
        "description": (
            "インターネット販売トランザクションを日付テーブルへ関連付けるためのキーです。"
        )
    },
    {
        "type": "column",
        "table": "dimproduct",
        "name": "ProductKey",
        "description": (
            "セマンティックモデル内で製品を一意に識別するためのキーです。"
        )
    },
    {
        "type": "column",
        "table": "factinternetsales",
        "name": "SalesAmount",
        "description": (
            "インターネット販売トランザクションに記録された売上金額です。"
        )
    },
    {
        "type": "measure",
        "table": "factinternetsales",
        "name": "Total Internet Sales",
        "description": (
            "現在のレポートフィルター条件に基づいて、インターネット売上の合計を計算します。"
        )
    },
    {
        "type": "measure",
        "table": "factinternetsales",
        "name": "Total Orders",
        "description": (
            "現在のレポートフィルター条件に基づいて、インターネット販売の注文数を重複なしで集計します。"
        )
    },
    {
        "type": "measure",
        "table": "factinternetsales",
        "name": "Internet Sales Profit",
        "description": (
            "現在のレポートフィルター条件に基づいて、インターネット売上から製品原価を差し引いた利益を計算します。"
        )
    }
]

mapping_df = pd.DataFrame(mapping)

display(mapping_df)

注意
説明文はサンプルです。売上、利益、顧客、注文などの正式な定義は、業務部門、データオーナー、KPI定義書、データ辞書などを確認して決定してください。

※サンプル実行結果画面
image.png

11. オブジェクト名を検証する

テーブル、列、メジャーの一覧を1つにまとめ、マッピングで指定したオブジェクトが実際に存在するか確認します。

inventory_df = pd.concat(
    [
        table_inventory_df,
        column_inventory_df,
        measure_inventory_df
    ],
    ignore_index=True,
    sort=False
)

proposal_df = mapping_df.merge(
    inventory_df[
        ["type", "table", "name", "description"]
    ],
    on=["type", "table", "name"],
    how="left",
    suffixes=("_proposed", "_current")
)

proposal_df["object_found"] = (
    proposal_df["description_current"].notna()
)

proposal_df["change_required"] = (
    proposal_df["description_current"].fillna("")
    != proposal_df["description_proposed"].fillna("")
)

display(
    proposal_df[
        [
            "type",
            "table",
            "name",
            "object_found",
            "description_current",
            "description_proposed",
            "change_required"
        ]
    ]
)

すべての行で次の値になっていることを確認します。

object_found = True

Falseがある場合は、そのオブジェクト名がモデル内に存在しません。インベントリの出力から正確な名前を確認し、マッピングを修正してください。

※サンプル実行結果画面
image.png

12. ドライランを実行する

最初は次の設定のまま実行します。

commit_changes = False

続いて、次のセルを実行します。

results = []

with connect_semantic_model(
    dataset=dataset,
    workspace=workspace,
    readonly=not commit_changes
) as tom:

    for item in mapping:

        result = {
            "type": item["type"],
            "table": item["table"],
            "name": item["name"],
            "old_description": None,
            "new_description": item["description"],
            "status": None,
            "error": None
        }

        try:
            table = tom.model.Tables[item["table"]]

            if item["type"] == "table":
                target = table

            elif item["type"] == "column":
                target = table.Columns[item["name"]]

            elif item["type"] == "measure":
                target = table.Measures[item["name"]]

            else:
                result["status"] = "INVALID TYPE"
                results.append(result)
                continue

            result["old_description"] = (
                target.Description or ""
            )

            if commit_changes:
                target.Description = item["description"]
                result["status"] = "UPDATED"
            else:
                result["status"] = "DRY RUN"

        except Exception as ex:
            result["status"] = "FAILED"
            result["error"] = str(ex)

        results.append(result)

results_df = pd.DataFrame(results)

display(results_df)

正常に処理された行には、次のステータスが表示されます。

DRY RUN

FAILEDがある場合は、モデルへ反映せず、エラー内容とオブジェクト名を確認してください。

※サンプル実行結果画面
image.png

13. 説明をセマンティックモデルへ保存する

ドライランの結果に問題がなければ、次の値を変更します。

commit_changes = True

その後、前の更新セルをもう一度実行します。

正常に更新された行には、次のステータスが表示されます。

UPDATED

作業完了後は、誤操作を防ぐため、設定を再びFalseへ戻しておくことを推奨します。

commit_changes = False

※サンプル実行結果画面
image.png

14. 更新結果を検証する

セマンティックモデルへ再接続し、保存された説明が期待値と一致するか確認します。

verification_rows = []

with connect_semantic_model(
    dataset=dataset,
    workspace=workspace,
    readonly=True
) as tom:

    for item in mapping:

        try:
            table = tom.model.Tables[item["table"]]

            if item["type"] == "table":
                target = table

            elif item["type"] == "column":
                target = table.Columns[item["name"]]

            elif item["type"] == "measure":
                target = table.Measures[item["name"]]

            else:
                continue

            actual_description = (
                target.Description or ""
            )

            verification_rows.append({
                "type": item["type"],
                "table": item["table"],
                "name": item["name"],
                "expected_description": item["description"],
                "actual_description": actual_description,
                "verified": (
                    actual_description
                    == item["description"]
                )
            })

        except Exception as ex:
            verification_rows.append({
                "type": item["type"],
                "table": item["table"],
                "name": item["name"],
                "expected_description": item["description"],
                "actual_description": None,
                "verified": False,
                "error": str(ex)
            })

verification_df = pd.DataFrame(
    verification_rows
)

display(verification_df)

すべての行で次の値になっていることを確認します。

verified = True

※サンプル実行結果画面
image.png

さらにFabricのWebモデリング画面でセマンティックモデルを開き、次のオブジェクトの説明(Description)プロパティを確認します。

  • dimcustomer
  • dimcustomer[CustomerKey]
  • factinternetsales[SalesAmount]
  • [Total Internet Sales]

※サンプル画面
image.png

image.png

15. 任意:Fabric Data Agentで動作を確認する

Fabric Data Agentがテナントで有効になっている場合は、更新後のセマンティックモデルを接続して確認できます。

  1. ワークスペースで新しいアイテムを選択します。
  2. Fabric Data Agentを選択します。
  3. 任意の名前を付けます。
  4. 更新したセマンティックモデルをデータソースとして追加します。
  5. 使用するテーブルを選択します。
  6. 自然言語で質問します。

例:

インターネット売上の合計はいくらですか?
年別のインターネット売上を表示してください。
売上金額が最も大きい製品はどれですか?
購入実績のある顧客は何人ですか?

※サンプル実行結果画面
image.png

image.png

説明を追加した後も回答が期待どおりでない場合は、次も確認してください。

  • テーブル、列、メジャーの名前が業務用語として分かりやすいか
  • 不要なオブジェクトがAIデータスキーマに含まれていないか
  • 類似するメジャーが複数存在し、意味が曖昧になっていないか
  • Prep for AIのAIデータスキーマ、AI指示、検証済み回答が適切か
  • Data Agent側で選択したテーブルが、Prep for AIのスコープと一致しているか

16. よくある問題と対処方法

TOM接続が読み取り専用になる

次を確認してください。

  • XMLAエンドポイントがRead Writeに設定されている
  • 対象ワークスペースでモデルを変更できるロールを持っている
  • 保存時にreadonly=False相当の接続になっている
  • commit_changes=Trueを設定している

テーブル、列、メジャーが見つからない

インベントリ取得用セルを再実行し、表示された正確なオブジェクト名をマッピングへコピーしてください。スペル、空白、大文字・小文字を含め、実際のモデル名と一致させます。

FAILEDが表示される

error列の内容を確認してください。対象オブジェクトが存在しない、権限が不足している、XMLAが読み取り専用であるなどの原因が考えられます。

説明を更新したがData Agentの回答が改善しない

説明だけでなく、Prep for AIの構成、使用するメジャー、日付列、リレーションシップ、検証済み回答、AI指示も確認してください。Data Agentの精度は、複数のモデル設定に影響されます。

自動生成した説明をそのまま使ってよいか

自動生成された説明は下書きとして扱うことを推奨します。特に次の内容は、技術情報だけで判断せず、業務部門やデータオーナーへ確認してください。

  • 売上と利益の正式な定義
  • 税の扱い
  • 返品やキャンセルの扱い
  • 使用通貨
  • 会計年度
  • 顧客や注文の有効条件

17. 運用時の推奨事項

  • commit_changes=Falseを既定値にする
  • 開発、テスト、本番のワークスペースを分ける
  • 既存の説明を無条件に上書きしない
  • 変更前と変更後の説明を記録する
  • 業務用語集やKPI定義書を説明の基準にする
  • AI生成の説明にはレビュー工程を設ける
  • 本番反映前にドライラン結果を承認する
  • 更新後に必ず再取得して検証する

まとめ

セマンティックモデルが技術的に正しく作られていても、それだけでAIが業務上の意味を正しく理解できるとは限りません。

テーブル、列、メジャーに分かりやすい説明を追加することで、Fabric Data AgentやPower BI Copilotがモデルの意味を解釈しやすくなります。

本記事では、次の流れを実装しました。

  1. Semantic Link LabsをNotebookへインストール
  2. セマンティックモデルへ読み取り専用で接続
  3. テーブル、列、メジャーの情報を取得
  4. 説明のマッピングを作成
  5. オブジェクト名と変更内容を検証
  6. ドライランを実行
  7. 承認後に説明を保存
  8. 再接続して更新結果を検証
  9. 必要に応じてData Agentから質問して確認

自動化は作業負荷を下げるために有効ですが、説明の最終的な品質は、業務コンテキストが正しく反映されているかどうかで決まります。Notebookによる一括更新と、業務部門による定義確認を組み合わせることが重要です。

参考資料

補足

本記事のコードは検証用のサンプルです。利用するライブラリやAPIの仕様は更新される可能性があります。実際の環境へ適用する前に、対象のFabric Runtime、Semantic Link Labsのバージョン、権限、XMLAの設定を確認してください。

AI利用に関する注記(Disclaimer)
本記事は、筆者が実施した検証内容、Microsoftの公開ドキュメント、および技術セッションの内容をもとに作成しています。記事の構成整理、文章表現の推敲、コード例の整形には生成AIを一部利用していますが、掲載内容は筆者が確認・編集しています。
ただし、本記事のコードおよび手順は検証・学習を目的としたサンプルであり、すべての環境での動作を保証するものではありません。Microsoft Fabric、Power BI、Semantic Link、Semantic Link Labs、Fabric Data Agentなどの機能やAPI、画面、権限要件は、今後変更される可能性があります。実際の環境、特に本番環境へ適用する場合は、最新のMicrosoft公式ドキュメント、利用中のRuntimeおよびライブラリのバージョン、組織のセキュリティ・ガバナンス方針を確認したうえで、利用者自身の責任で十分に検証してください。
また、AIが生成または補助した説明文は下書きとして扱い、売上、利益、顧客、注文、会計年度などの業務定義については、必ず業務部門、データオーナー、または正式なデータ辞書・KPI定義書と照合してください。本記事の内容は筆者個人の見解であり、所属組織を代表するものではありません。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?