Microsoft Purviewでスキャン済みのAzureサービスやDatabricksテーブルのGUIDを一覧で取得したいなら、Type定義(ビルトイン)ではなく「Data Mapの検索(Discovery)API」でエンティティ(=実アセット)を列挙するのが最短ルートです。本記事ではREST APIの使い方と、DatabricksでDeltaテーブルに保存して分析へつなげる実装手順をまとめます。
「ビルトインのGUIDしか返らない」原因は、参照している対象が違う
まず押さえたいのは、Microsoft Purview(Data Map)が内部的にApache Atlasのモデルを持っていて、APIが大きく「型(Type)」と「実体(Entity)」に分かれている点です。ここを取り違えると、あなたがスキャンしたテーブルやファイルのGUIDではなく、システムが持つビルトイン定義(分類や型定義)のGUIDばかりが返ってきます。
| 区分 | 意味 | 返ってくるGUIDの正体 | 典型的なエンドポイント例 | 今回ほしいものか? |
|---|---|---|---|---|
| Type(型定義) | 「テーブル」「カラム」などのテンプレート。属性構造・制約を定義 | 型定義のGUID(ビルトインが多い) | /catalog/api/atlas/v2/types/...、/datamap/api/atlas/v2/types/... | いいえ |
| Classification(分類) | PIIなどの分類ラベル。適用ルールやメタ情報 | 分類定義のGUID(ビルトインが多い) | /.../types/classificationdef など | いいえ |
| Entity(エンティティ) | スキャンされた「実際のアセット」(テーブル、ファイル、ダッシュボード等) | アセットのGUID(あなたが欲しいGUID) | /datamap/api/search/query、/catalog/api/search/query、/.../atlas/v2/entity/guid/... | はい |
結論として、GUID一覧が欲しい場合は「検索APIでEntityを列挙」→「レスポンスの id を回収」という流れが王道です。
スキャン済みアセットのGUID一覧を取得できるAPI
Microsoft PurviewのData Mapには、検索でアセットを引けるAPIがあります。公式のREST APIリファレンス上では、代表的に以下が「アセット一覧(検索結果)を返す」エンドポイントです。
推奨:Discovery – Query(Data Map Search)
アセットを検索し、結果の配列にGUID(id)を含めて返します。キーワード検索に加え、objectType(Tables/Filesなど)やcollectionIdで絞り込みでき、最大1000件/リクエストでページングできます。
リクエスト例(基本形)
POST {endpoint}/datamap/api/search/query?api-version=2023-09-01
Authorization: Bearer {access_token}
Content-Type: application/json
{
"keywords": "*",
"limit": 1000
}
レスポンス例(重要フィールド)
{
"continuationToken": "<token>",
"@search.count": 5155,
"@search.count.approximate": true,
"value": [
{
"id": "24c16e53-1bfd-4d6c-b4ce-b1f6f6f60000",
"qualifiedName": "mssql://.../dbo/exampledata1",
"name": "exampledata1",
"entityType": "azure_sql_mi_table",
"objectType": "Tables",
"assetType": ["Azure SQL Managed Instance"],
"classification": [],
"label": []
}
]
}
この value[].id が、スキャン済みアセット(Entity)のGUIDです。continuationToken が返ってきた場合は、次ページがある合図なので、同じAPIに continuationToken を付けて繰り返します。
endpoint の決め方(クラシック / 新ポータル)
Purviewは「どのポータル(クラシック or 新Microsoft Purview)を使っているか」でベースURLが変わります。加えて、スキャン管理(登録・スキャン実行)とカタログ/データマップ(検索・取得)でサブドメインが違う点も混同しやすいので、ここは明確に分けます。
| 用途 | クラシック(例) | 新Microsoft Purviewポータル(例) | この用途でGUID一覧は取れる? |
|---|---|---|---|
| データマップ/カタログ(検索・Entity取得) | https://{accountName}.purview.azure.com | https://api.purview-service.microsoft.com | はい |
| スキャン(データソース登録/スキャン実行など) | https://{accountName}.scan.purview.azure.com | https://api.scan.purview-service.microsoft.com | 基本的にいいえ(管理系) |
GUID一覧の取得は「データマップ/カタログ側」のAPIを使う、というのがポイントです。
Discovery – Query APIの主要パラメータを押さえる
Discovery – Queryは柔軟に絞り込みできます。まずは「全件(keywords=*)を安全にページングで回収」できる状態を作り、その後に運用上の要件に合わせてフィルタを足すのが、失敗しにくい手順です。
| 項目 | 役割 | 実務での使いどころ | 注意点 |
|---|---|---|---|
keywords | 全文検索キーワード(検索可能フィールドに適用) | まずは * で全件、特定ソース名やテーブル名で部分抽出 | * は全件ヒットしやすく重い。limitとページング前提 |
limit | 1回で返す件数 | 一括エクスポートなら 1000 | 最大 1000。それ以上は continuationToken で回す |
continuationToken | 次ページ取得用トークン | 全件回収・定期同期で必須 | トークンが返らない=終端 |
filter | 絞り込み条件(and/or/not、属性条件など) | objectType=Tables、collectionId、entityTypeでの限定 | 条件を強くしすぎると「取得漏れ」が起きる |
orderby | ソート条件 | 更新日時で追いかけたいとき | 増分設計は「更新時刻の単独依存」に注意(遅延・再処理があり得る) |
facets | 集計用のファセット(assetType/classification等) | 「どのソースが多いか」をAPIだけで概観 | まずは取得→Databricks集計でも十分 |
実装の流れ:DatabricksでGUID一覧を取得してDeltaテーブルに保存する
ここからは「現場でそのまま動かせる」ことを意識して、Databricks前提の実装例をまとめます。Microsoft Tech Communityの記事ではPython SDK(azure-purview-catalog)でのエクスポート例が紹介されていますが、Databricksでは依存関係やネットワーク制約があることも多いので、まずは requests だけで呼べるREST直叩き版を中心に紹介します。
事前準備:サービスプリンシパルと権限
最低限、以下を揃えます。
- Microsoft Entra IDでアプリ登録(クライアントID / クライアントシークレット / テナントID)
- Purview側で、対象コレクションにサービスプリンシパルを付与(Data Reader もしくは Data Curator)
- Databricks Secret Scope(またはKey Vault連携)に機密情報を格納
コレクション権限は「付与したコレクション配下だけが見える」設計なので、想定より件数が少ない場合は、まずここを疑うのが近道です。
ステップ:アクセストークンを取得する
Purview Data MapのデータプレーンAPIは、Microsoft Entra IDのトークン(リソース/スコープが https://purview.azure.net)をBearerとして渡します。
Databricks(Python)例:トークン取得
import requests
tenant_id = dbutils.secrets.get("my_scope", "TENANT_ID")
client_id = dbutils.secrets.get("my_scope", "CLIENT_ID")
client_secret = dbutils.secrets.get("my_scope", "CLIENT_SECRET")
token_url = f"[https://login.microsoftonline.com/{tenant_id}/oauth2/token](https://login.microsoftonline.com/{tenant_id}/oauth2/token)"
payload = {
"grant_type": "client_credentials",
"client_id": client_id,
"client_secret": client_secret,
"resource": "[https://purview.azure.net](https://purview.azure.net)"
}
token_resp = requests.post(token_url, data=payload, timeout=30)
token_resp.raise_for_status()
access_token = token_resp.json()["access_token"]
もし社内標準でv2.0エンドポイントを使う場合は、/oauth2/v2.0/token と scope=https://purview.azure.net/.default で同等に取得できます(環境のポリシーに合わせてください)。
ステップ:Discovery – Queryでアセットをページング取得する
最大1000件/回なので、全件取得では必ず continuationToken でループします。途中で失敗しても再実行しやすいよう、レスポンスを正規化してから蓄積します。
Databricks(Python)例:GUID一覧を全件回収
import time
import requests
# Purviewのエンドポイント(クラシック or 新ポータルに合わせて切り替え)
purview_endpoint = dbutils.secrets.get("my_scope", "PURVIEW_ENDPOINT")
# 例: "https://{accountName}.purview.azure.com" または "[https://api.purview-service.microsoft.com](https://api.purview-service.microsoft.com)"
api_url = f"{purview_endpoint}/datamap/api/search/query?api-version=2023-09-01"
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
def fetch_all_assets(object_type=None, limit=1000, sleep_sec=0.2, max_retry=5):
results = []
token = None
while True:
body = {
"keywords": "*",
"limit": limit
}
# 任意:Tablesだけに限定(最初はNoneで全件→後から絞るのがおすすめ)
if object_type:
body["filter"] = {"and": [{"objectType": object_type}]}
if token:
body["continuationToken"] = token
# 簡易リトライ(429/5xx対策)
for attempt in range(max_retry):
resp = requests.post(api_url, headers=headers, json=body, timeout=60)
if resp.status_code in (429, 500, 502, 503, 504):
backoff = (2 ** attempt) * 1.0
time.sleep(backoff)
continue
resp.raise_for_status()
data = resp.json()
break
else:
raise RuntimeError("Purview API request failed after retries")
values = data.get("value", [])
results.extend(values)
token = data.get("continuationToken")
if not token:
break
time.sleep(sleep_sec)
return results
# 例1:全部取る(FilesやDashboardsも含む)
all_assets = fetch_all_assets(object_type=None)
# 例2:テーブルだけに限定して取り直す
table_assets = fetch_all_assets(object_type="Tables")
print(f"all_assets: {len(all_assets)}, table_assets: {len(table_assets)}")
ここで回収できる id がGUIDです。あとはDatabricksに保存し、資産量・ソース別の件数・更新頻度などを可視化できます。
ステップ:Spark DataFrameに変換してDeltaテーブルへ保存
Purviewの検索レスポンスはネストを含むことがあるため、まずは「分析に必要な列だけをフラット化」してから保存すると扱いやすくなります。特に、assetType・objectType・entityType・collectionId・updateTime(あれば)を残すと、後工程が楽になります。
Databricks(Python)例:フラット化してDeltaへ保存
from pyspark.sql import functions as F
# Pythonのdict配列をSpark DataFrameへ
raw_df = spark.createDataFrame(all_assets)
# よく使う列だけ整形(存在しない列があっても落ちにくいようにcoalesce)
assets_df = (
raw_df
.withColumnRenamed("id", "guid")
.withColumn("assetType0", F.expr("assetType[0]"))
.withColumn("classification_count", F.size(F.col("classification")))
.withColumn("label_count", F.size(F.col("label")))
.select(
"guid",
"name",
"qualifiedName",
"objectType",
"entityType",
"assetType0",
"collectionId",
"updateTime",
"createTime",
"owner",
"classification_count",
"label_count"
)
.withColumn("snapshot_date", F.current_date())
)
target_table = "governance.purview_assets_inventory"
(
assets_df
.write
.format("delta")
.mode("append")
.saveAsTable(target_table)
)
この形にしておくと、例えば次のような分析がすぐできます。
- assetType別の件数(どのソースが多いか)
- objectType=Tablesだけ抽出して、テーブル資産の規模把握
- collectionId別の資産量(運用単位・責任境界の見える化)
- classification_countが0でない資産の比率(ラベリング進捗)
おすすめのテーブル設計:スナップショット型と最新参照型を分ける
コスト管理や資産推移を見たい場合、「毎日/毎週のスナップショット(append)」と「最新状態(upsert)」を分けると運用が安定します。
| テーブル | 保存方式 | 主な用途 | ポイント |
|---|---|---|---|
purview_assets_inventory | append(snapshot_date付き) | 資産増減、スキャン対象量の推移、コスト/負荷の見立て | 日次/週次でジョブ化しやすい |
purview_assets_latest | MERGE(guidでupsert) | 常に最新のGUID一覧を参照して他データとJOIN | 分析側のJOINが軽くなる |
MERGE例(最新状態を維持)
from delta.tables import DeltaTable
latest_table = "governance.purview_assets_latest"
# 初回は作成
assets_df.write.format("delta").mode("overwrite").saveAsTable(latest_table)
# 2回目以降はMERGE
t = DeltaTable.forName(spark, latest_table)
(
t.alias("t")
.merge(
assets_df.alias("s"),
"t.guid = s.guid"
)
.whenMatchedUpdateAll()
.whenNotMatchedInsertAll()
.execute()
)
削除の扱いは要注意です。Purview側のコネクタやスキャンの仕様によっては「元データで削除されてもPurview内のアセットが即時に消えない」ケースがあります。削除も含めて厳密に追いたい場合は、スナップショットの差分(当日存在しないguid)を「削除候補」として別テーブルに出す運用が現実的です。
「ビルトインしか返らない」問題を解くためのチェックリスト
症状と対処を、現場でよくあるパターンに絞って整理します。
| 症状 | よくある原因 | 対処 |
|---|---|---|
| Type定義っぽいGUIDしか取れない | Type系のAPI(typedefs等)を叩いている | Entity検索(/datamap/api/search/query)で value[].id を回収する |
| 件数が1000で止まる | APIの上限(limit最大1000)でページングしていない | continuationToken が無くなるまでループする |
| 403/権限エラーになる | Purviewのコレクション権限が不足 | 対象コレクションにData Reader/Data Curatorを付与。サブコレクションのみ付与の場合、見える範囲が限定される |
| データは取れるが欲しいソースが含まれない | collectionIdフィルタや権限範囲のミスマッチ | まずフィルタ無しで取得→assetType/collectionIdを確認→必要な絞り込みを追加 |
| 新ポータルのつもりがクラシックに見える/挙動が違う | endpointの使い分け・ネットワーク(Firewall/Private Endpoint/DNS)の影響 | クラシック:{accountName}.purview.azure.com、新:api.purview-service.microsoft.com を明確に切り替え。許可リストやDNSも確認 |
| 429(Too Many Requests)が出る | 短時間に大量リクエスト | 指数バックオフでリトライ、limitを大きくして回数を減らす、ジョブ時間帯を分散 |
フィルタ設計のコツ:最初は「広く取って、後から絞る」
「Databricksのテーブルだけ」「Azure SQLだけ」など、最初から狙い撃ちしたくなりますが、運用設計としては段階を踏む方が安全です。特にPurviewはコネクタやバージョンで entityType/assetType の表記が変わることがあるため、まずは全件を取り、実データを見てから確実な条件を採用するのが失敗しにくいです。
よく使う絞り込みパターン(Discovery – Query)
以下は実務で出番が多い絞り込み例です。
| 目的 | 例(リクエストbodyのイメージ) | コメント |
|---|---|---|
| テーブルだけ欲しい | {"keywords":"*","limit":1000,"filter":{"and":[{"objectType":"Tables"}]}} | まずはこれが一番シンプル |
| 特定コレクション配下だけ | {"keywords":"*","limit":1000,"filter":{"and":[{"collectionId":"<collection-guid>"}]}} | 運用単位(部門/プロジェクト)で棚卸したいとき |
| 特定のassetTypeだけ | {"keywords":"*","limit":1000,"filter":{"and":[{"assetType":"Azure Databricks"}]}} | assetType表記は環境で揺れることがあるので、最初に全件から確認推奨 |
| qualifiedNameに文字列を含むもの | {"keywords":null,"limit":1000,"filter":{"and":[{"attributeName":"qualifiedName","operator":"contains","attributeValue":"databricks"}]}} | 「URIのパターン」が安定しているなら強い |
Databricks由来のアセットだけを厳密に取りたい場合でも、まずは objectType=Tables でテーブル一覧を作り、そこから entityType と assetType0 の実値を見て条件を確定させる方が、取得漏れを減らせます。
Python SDKで実装したい場合(Tech Communityサンプルをベースにする)
社内標準でAzure SDKを使う方針なら、Tech Communityで紹介されているように azure-purview-catalog を使う方法もあります。検索(Discovery)を呼び出す形は同じで、戻ってくるデータに id(GUID)や entityType が含まれます。
インストール例(必要に応じて)
pip install azure-identity
pip install azure-purview-catalog
pip install pandas
SDK例(概念)
from azure.identity import ClientSecretCredential
from azure.purview.catalog import PurviewCatalogClient
credential = ClientSecretCredential(tenant_id=tenant_id, client_id=client_id, client_secret=client_secret)
client = PurviewCatalogClient(endpoint=purview_endpoint, credential=credential)
response = client.discovery.query(search_request={"keywords": "*"})
# response["value"] の各要素に id が入る(=GUID)
ただし、SDK経由でも「最大1000件」問題は残るため、全件抽出するならページング(continuationToken)を意識した実装が必要です。大量データをエクスポートする運用では、REST直叩き+リトライ制御の方が挙動を掴みやすい場面もあります。
運用に乗せるための実践ポイント
GUIDを取れるようになったら、次は「継続的に、壊れずに回る」状態を作るのが価値になります。最後に、実務で効くポイントをまとめます。
- ジョブはスナップショット型で始める:まずは日次で全件をappendし、増減の傾向を掴む。後から増分最適化しても遅くない。
- 列は欲張らない:最初は
guid / qualifiedName / name / objectType / entityType / assetType / collectionId / updateTimeがあれば分析は十分進む。 - フィルタは後置き:最初から狙い撃ちすると取得漏れの原因になる。全件→観察→条件確定が安全。
- 429・ネットワーク要因を織り込む:指数バックオフ、タイムアウト、ジョブの再実行性(冪等)を最初から入れる。
- Purview側の仕様差を前提にする:コネクタ・ポータル・ネットワーク(Private Endpoint/Firewall)で見え方が変わることがあるので、endpointと権限範囲の記録を残す。
まとめ
Microsoft Purviewでスキャン済みアセットのGUID一覧を取得するには、ビルトイン定義(Type/Classification)ではなく「Entity(実アセット)を検索で列挙するAPI」を使うのが正攻法です。Discovery – Query(/datamap/api/search/query)で全件をページング取得し、レスポンスの value[].id を回収してDatabricksのDeltaテーブルへ保存すれば、資産量・ソース別分布・分類進捗などの分析がすぐに始められます。
参考(公式・一次情報)
https://learn.microsoft.com/en-us/rest/api/purview/datamapdataplane/discovery/query?view=rest-purview-datamapdataplane-2023-09-01https://learn.microsoft.com/en-us/purview/data-gov-api-create-assetshttps://techcommunity.microsoft.com/discussions/azurepurview/exporting-microsoft-purview-data-assets-using-the-rest-api/3948965https://techcommunity.microsoft.com/blog/azurearchitectureblog/exploring-purview%E2%80%99s-rest-api-with-python/2208058

コメント