Databricks Lakeflow Connect で SharePoint Online ドキュメントライブラリのファイル取込みを行う

## はじめに

Databricks Lakeflow Connect で SharePoint Online サイト上のファイルを取り込みを試してみます。
2025/06/13 現在、[Beta 版](https://learn.microsoft.com/en-us/azure/databricks/release-notes/release-types)機能であるためか、いくつかつまづいた点があるのでこの対処を含めてキャプチャなどを共有します。


### Lakeflow Connect

>Lakeflow Connect には、一般的なエンタープライズ アプリケーション、データベース、クラウド ストレージ、ローカル ファイル、メッセージ バスなどのデータを取り込むためのシンプルで効率的なコネクタが用意されています。 このページでは、Lakeflow Connect で ETL のパフォーマンスを向上させるいくつかの方法について説明します。 また、フル マネージド コネクタから完全にカスタマイズ可能なフレームワークまで、一般的なユース ケースとサポートされているインジェスト ツールの範囲についても説明します。

出典：https://learn.microsoft.com/en-us/azure/databricks/ingestion/overview

## セットアップ（管理者側の作業）

[Microsoft SharePoint インジェストのための OAuth U2M の構成](https://learn.microsoft.com/en-us/azure/databricks/ingestion/lakeflow-connect/sharepoint-source-setup) に従って進めます。

### 機能の有効化

ワークスペース設定から本機能を有効化します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/2399f463-ccd0-423f-9b9f-5f47cebf160e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/0d4f3b5f-ed0b-4149-a219-423133f778a3.png)

### 1. Sharepoint サイト ID の取得

対象のサイトはこちらです。（Fabric のデモ用に用意したものを流用しました）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/86d7ced2-40bb-4fab-a4c0-5432998a10a2.png)

サイト ID は URLの中になく、システム内で利用されている ID を取得する必要があります。

1. サイトのホームの URL 末尾に **`/\_api/site/id`**　を追加してアクセスします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/16ce288a-ec5b-424e-b49f-0006dc1200cf.png)
1. このような画面が表示されるので、ID をメモします
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/e42579a9-97b3-4ab2-98d1-caf042db6310.png)

### 2. サービスプリンシパルの作成（管理者側の作業）


1. Databriks instanec url を取得

    Databricks ワークスペースの URL を取得します。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/cf0340f7-a14c-4854-bac0-15b0079439c8.png)
    
1. Entra ID 上でアプリを作成する際、リダイレクトURLを設定します。<databricks-instance-url>/login/oauth/sharepoint.html の形式となります。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/82d95978-834e-4ca7-8d3a-0a4de722bde3.png)
    
    参考：設定後の値
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/bd6264d1-13c9-4c2b-aa31-1e80566ff36a.png)


:::note info

U2M認証を採用したため、サービスプリンシパルには権限を付与する必要はありません。ただし、後続手順で認証を行うユーザーアカウントの離任などに備える場合にはもう少し手順を変える必要があると思います。

あらかじめ Sharepoint にアクセスできる専用の Entra ID ユーザーを払い出しておくのが簡単だと思います。

:::


## UnityCatalog 上での接続オブジェクト作成（管理者側の作業）

[マネージド インジェスト ソースに接続する](https://learn.microsoft.com/ja-jp/azure/databricks/connect/managed-ingestion#sharepoint)に従って進めます。

ここに関してはあまり難しいところはないので参考のキャプチャのみを記載します。

1. 名前などの設定

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/fed7daf7-9422-4eb1-aa5d-d820af952bb5.png)
1. セットアップで作成したサービスプリンシパル情報と接続先の Sharepoint ドメイン。冒頭に確認したサイトの URL 先頭ですね。

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/5bc2a25c-51dc-43f8-bc35-3d9e2cd72d72.png)

1. サインインすると、サービスプリンシパル（アプリケーション）に 自分の 認可情報に基づいて API を使用する許可に関する確認が発生します。委任により動作させるので組織管理者による同意は不要です。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/83d0a19d-9bc5-494c-91f1-8322871cc566.png)

次の画面に進んだら接続の作成が完了します。

## Ingest Pipeline の作成と実行

[Microsoft SharePoint インジェスト パイプラインを作成する](https://learn.microsoft.com/en-us/azure/databricks/ingestion/lakeflow-connect/sharepoint-pipeline) のノートブックをインポートする形で進めます。

### 1. ライブラリを指定して取込むパイプラインの作成と実行

cell 3 の定義により作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/4fcca4a3-abbc-4253-8698-4c20880126f4.png)

1. ノートブックのインポートにて URL を入力してインポートします。

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/33751731-8802-4fdd-a4dc-c6607a2a3d6e.png)


1. ノートブックの修正
    
    インポートしたノートブックをあらかじめ一部修正しておきます。
    
    ```diff_python:python
      def create_pipeline(pipeline_definition: str):
    - response = requests.post(url=api_url, headers=headers, data=pipeline_definition)
    + response = requests.post(
    +       url=api_url,
    +       headers=headers,
    +       data=pipeline_definition.encode('utf-8')
    +   )
        check_response(response)
    
    ```

    また、json の崩れを補正します。


    ```diff_python:python
    pipeline_spec = """
    {
     "name": "<YOUR_PIPELINE_NAME>",
     "ingestion_definition": {
         "connection_name": "<YOUR_CONNECTON_NAME>",
         "objects": [
            {
              "table": {
                "source_schema": "<YOUR_SHAREPOINT_SITE_ID>", 
                "source_table": "<YOUR_SHAREPOINT_DRIVE_NAME>",
                "destination_catalog": "<YOUR_DATABRICKS_CATALOG>",
                "destination_schema": "<YOUR_DATABRICKS_SCHEMA>",
                "destination_table": "<NAME"> # e.g., "my_drive",
                "table_configuration": {
                  "scd_type": "SCD_TYPE_1"
    +           }   
              }
            }
          ]
     },
     "channel": "PREVIEW"
    }
    """
    
:::note warn

既存のサンプルノートブックのままだとエラーとなります。
1. 日本語文字列のエンコーディング漏れ
    日本語環境では ライブラリの名前は "ドキュメント" など日本語になるので、前処理が必要です。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/5c12d20e-131e-4e44-a845-7161bdb1be39.png)

2. json のフォーマット崩れ
    
    table_configrationのプロパティが閉じてません
    
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/163078d6-4796-4ec9-9ae4-e41e64a32704.png)



:::

3.定義を設定します。ここでサイトIDを使用します。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/6f2ada15-acea-4ce6-950e-637b6fec553b.png)


### 2. 取り込み結果の確認

1. パイプラインを実行します。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/9d2575d6-4496-49f4-adcd-3c02ef731056.png)

2. 取込結果は以下のようになりました。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/a0bf5305-0791-4c5f-afe7-5640d0d258a1.png)

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/fdf0b4ff-f70f-451e-82b1-69d52d10395d.png)   
    
    ファイルパスは、soure_metadata.file_folder_path に [Sharepoint API (Get driveItem)](https://learn.microsoft.com/ja-jp/graph/api/driveitem-get?view=graph-rest-1.0&tabs=http) で利用される ` /drives/{drive-id}/root:/{item-path}` の形式のスキームとなり、
    ファイルの内容は、バイナリの値がcontent.inline_content に格納されるようです。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/e31b361a-e168-46d2-bcaa-3c08afafdf4c.png)
    
ファイルの内容については、[ダウンストリームRAGの使用例](https://learn.microsoft.com/en-us/azure/databricks/ingestion/lakeflow-connect/sharepoint-rag) のように UDF 経由でアクセスすることが推奨されます。ここについてはまた次回。
    
### (日本語環境では不可)サイト全体を取込むパイプライン
    
ライブラリ名を指定しない cell 2 の定義を使用する場合、日本語環境では以下のようなエラーとなります。
ライブラリ名に基づいてテーブル名を作成しようとして、バッククォートなしで日本語を入力していると思われます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/9af36a97-492b-4da3-ae33-a1f49b6eda9a.png)

## 所感

圧倒的に簡単で、なによりサービスプリンシパルに対してあらかじめ権限を与えるのではなく、ユーザーの権限で委任する仕組みが推奨として採用されているのが非常に扱いやすいと感じました。

Sharepoint ライブラリの連携は、[Fabric/ADF データパイプラインでの取得](https://qiita.com/ryoma-nagata/items/e836885a785ac97e6734)などありますが、現在Graph API によるセットアップに関する情報公開が追い付いていないため、Lakeflow Connect が第一におすすめできるソリューションだと思いました。

日本語環境での対応と、そうした細かい取り回しについて内部実装を確認できないことは少し気になりますが、 GA の際には改善されることを期待しています。

## 参考情報

- 取込結果のスキーマ：https://learn.microsoft.com/en-us/azure/databricks/ingestion/lakeflow-connect/sharepoint-reference