Microsoft PurviewのLineageを外部に出力する（その1）

# この記事でやること
この記事ではMicrosoft PurviewのLineageをREST APIでJSON形式で取得し[Graphviz](https://graphviz.org/)を使って可視化します。
REST APIの実行はPythonを使っています。

* この記事
* [Microsoft PurviewのLineageを外部に出力する（その2）](https://qiita.com/cannoteat/items/b4177ac7f150a6dd0d30)
* [Microsoft PurviewのLineageを外部に出力する（その3）](https://qiita.com/cannoteat/items/ba97cd3d57193a458d76)

## 環境など

* Microsoft Purview REST API
Purviewの[Get Lineage By Unique Attribute](https://learn.microsoft.com/en-us/rest/api/purview/catalogdataplane/lineage/get-lineage-by-unique-attribute)でLineageがJSON形式で返されます。
```
GET {Endpoint}/catalog/api/atlas/v2/lineage/uniqueAttribute/type/{typeName}?direction={direction}
```
* graphviz
JSONで返されたLineageを[GraphvizのPythonインターフェイス](https://graphviz.readthedocs.io/en/stable/manual.html)を使ってSVG表示します。

## サンプルLineage
今回こんな感じのLineageを出力していきます。
　S3->ADF(Copy)->ADLS->ADF(DataFlow)->SQL Databse
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89512/4413ecae-5e6e-9833-de5d-e011a6f3ac3e.png)


このLineageをREST APIで取得するとこんな構造の出力が得られます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89512/e9abe2d8-50e6-66b4-3715-69f9891fd425.png" width=50%>
頭が痛くなりますね。。

# Lineageの取得と表示
ここからは実際にLineageの取得と表示を行っていきます。

## アクセストークンの取得

``` python
import json
import requests
from pprint import pprint

def azure_ad_auth(tenant_id: str, client_id: str, client_secret: str, resource_url: str):
    url = f"https://login.microsoftonline.com/{tenant_id}/oauth2/token"
    payload= f"grant_type=client_credentials&client_id={client_id}&client_secret={client_secret}&resource={resource_url}"
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded'
    }
    response = requests.request("POST", url, headers=headers, data=payload)
    access_token = json.loads(response.text)['access_token']
    
    return access_token

tenant_id = "テナントID"
client_id = "アプリケーションID"
client_secret = "シークレット"
resource_url = "https://purview.azure.net"
data_catalog_name = "Purviewアカウント名"

azure_ad_access_token = azure_ad_auth(tenant_id, client_id, client_secret, resource_url)
```
## Lineageの取得
今回はLineageの終端であるSQL DatabaseのCustomerInfoテーブルを起点にしてLineageを取得します。CustomerInfoテーブルのqualifiedNameとtypeNameを指定して取得します。
[GUIDを指定してLineageを取得する](###-おまけ:-GUIDを指定してLineageを取得する) こともできます。

``` python
def get_lineage_by_atter(typeName: str, qualifiedName: str, direction: str):
    url = f"https://{data_catalog_name}.purview.azure.com/catalog/api/atlas/v2/lineage/uniqueAttribute/type/{typeName}?attr:qualifiedName={qualifiedName}"
    url += f"&direction={direction}"

    headers = {
        "Authorization": "Bearer " + azure_ad_access_token,
        "Content-Type": "application/json"
    }
    response = json.loads(requests.get(url, headers=headers).content)

    return response

direction = "BOTH" # Lineageを取得する方向
type_name = "azure_sql_table" # SQLDBのテーブルなのでazure_sql_tableを指定
qualified_name = "" # 下記参照

response = get_lineage_by_atter(type_name, qualified_name, direction)
```
qualifiedNameは↓から取得します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89512/f571d79b-043a-f302-3e8f-8e5c89f43641.png)

## Lineageの表示（その1）
今回、まずはguidEntityMapに着目します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89512/3c444d91-b14e-4fcf-f02b-c17b40f69dc0.png)

guidEntityMapにはLineageの青い枠で表現されている部分の情報が入っています。（線に当たる部分はありません。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89512/5d67c23a-ef8a-9e6e-802c-0d0b55634cb8.png)


まずは、このノードの部分をGraphvizで表示します。

``` python
from graphviz import Digraph
from IPython.display import SVG

lineage01 = Digraph(format="svg")
lineage01.attr('graph', rankdir="LR", compound="true")
lineage01.attr("node", fontname="Segoe UI")

for guid in response["guidEntityMap"]:
    lineage01.node(
        guid,
        shape="box",
        label=f'''
{guid}
{response["guidEntityMap"][guid]["attributes"]["name"]}
{response["guidEntityMap"][guid]["typeName"]}
        '''
    )

lineage01.render("lineage/01.gv")
SVG("lineage/01.gv.svg")
```

GUID、エンティティ名、タイプ名などが表示できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89512/871bc30e-7aca-c403-069e-c335a01edb5e.png)

## おまけ: GUIDを指定してLineageを取得する
``` python
def get_lineage_by_guid(guid: str, direction: str):
    url = f"https://{data_catalog_name}.purview.azure.com/catalog/api/atlas/v2/lineage/{guid}?direction={direction}"

    headers = {
        "Authorization": "Bearer " + azure_ad_access_token,
        "Content-Type": "application/json"
    }
    response = json.loads(requests.get(url, headers=headers).content)

    return response

guid = "b8ff9bf2-5ee6-4849-b3ad-93f6f6f60000"
direction = "BOTH"
response = get_lineage_by_guid(guid, direction)
```
GUIDはURLから取得します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89512/ce58ef34-ef3e-9251-f0e8-e2fe069dac16.png)

##
次回はノードを繋いでいきます。

* この記事
* [Microsoft PurviewのLineageを外部に出力する（その2）](https://qiita.com/cannoteat/items/b4177ac7f150a6dd0d30)
* [Microsoft PurviewのLineageを外部に出力する（その3）](https://qiita.com/cannoteat/items/ba97cd3d57193a458d76)