Databricks 上で Hadoop Catalog により Apache Iceberg を実行する際の Multiple sources found for ICEBERG

## 概要

Databricks 上で Hadoop Catalog により Apache Iceberg を実行する際に発生した下記エラーの対応方法を紹介します。推測でありますが、 Databricks Runtime 13.3 以降で  Apache Iceberg 関連の機能実装が原因の可能性があります。 Databricks Runtime 12.2 にすることでエラーの解消ができました。

> AnalysisException: Multiple sources found for ICEBERG (com.databricks.sql.transaction.tahoe.uniform.sources.IcebergBrowseOnlyDataSource, org.apache.iceberg.spark.source.IcebergSource), please specify the fully qualified class name.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/b41e8c81-4815-4ddf-986d-ffb899943eb7.png)

Databricks 上で Hadoop Catalog により Apache Iceberg を利用するには、下記の設定が必要です。

- Databricks Runtime のバージョンを 12.2LTS 以前にすること
- アクセスモードを分離なし共有（Uniyt Catalog 利用不可のモード」）にすること
- Java 8 に対応したライブラリ（Iceberg 1.6.1 以前のライブラリ）を利用すること
- Spark 構成に Iceberg 関連の設定を実施

## 事前準備

### ベースとなるクラスターを作成

#### Databricks Runtime にて`12.2`を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/4324f0d6-d98e-4397-9650-1f02ded050fd.png)

#### アクセスモードを 分離なし共有に設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/3791dd9b-c781-48f0-b17c-4441f70589dc.png)

#### Spark 構成に Iceberg 関連の設定を実施

`spark.sql.catalog.spark_catalog.warehouse`にて指定してディレクトリにテーブルのデータが書きこまれる。

```text
spark.sql.catalog.spark_catalog = org.apache.iceberg.spark.SparkCatalog
spark.sql.catalog.spark_catalog.type = hadoop
spark.sql.catalog.spark_catalog.warehouse = dbfs:/Iceberg
spark.sql.extensions = org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/905acb2d-8cd8-4d12-bcb1-78165e4139ed.png)

### Iceberg 関連ライブラリである`org.apache.iceberg:iceberg-spark-runtime-3.3_2.13:1.6.1`をインストール

クラスターのライブラリタブにて、`新規インストール`を選択し、`ライブラリをインストール`ウィドウにて`Mave`をチェック後に、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/5f496302-c98d-4289-a5fe-281c20951883.png)

`org.apache.iceberg iceberg-spark-runtime`と入力すると下記のようにバージョンごとのライブラリを表示し、`org.apache.iceberg:iceberg-spark-runtime-3.3_2.13`の`1.6.1`リリースを選択後に`選択`を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/224f7b07-876d-4396-b416-255a2d0679cd.png)

`org.apache.iceberg:iceberg-spark-runtime-3.3_2.13:1.6.1`と入力されたことを確認後に、`インストール`を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/d73020ea-2005-4692-9d6e-70f0bdf478e5.png)

## エラーの再現方法

### Databricks Runtime 13.3 に変更

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/8fbe272c-c7f1-4e12-9002-654d06baf77f.png)

### Databricks Runtime の Spark バージョン合わせた Iceberg のライブラリ（`org.apache.iceberg:iceberg-spark-runtime-3.4_2.12:1.6.1`）を変更

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/e0bcef4b-8022-45b8-9f76-1a6ddb8afeff.png)

### クラスターを再起動

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/6d7fe51d-acf4-4e6c-9ab7-3709bc9416a4.png)


### エラーとなることを確認

```sql
%sql
CREATE TABLE ICEBERG_TBL_2(ID INT,NAME STRING) USING ICEBERG;
INSERT INTO ICEBERG_TBL_2 VALUES(1,"Shraddha");
SELECT * FROM ICEBERG_TBL_2;
```

> AnalysisException: Multiple sources found for ICEBERG (com.databricks.sql.transaction.tahoe.uniform.sources.IcebergBrowseOnlyDataSource, org.apache.iceberg.spark.source.IcebergSource), please specify the fully qualified class name.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/b41e8c81-4815-4ddf-986d-ffb899943eb7.png)

## エラーへの対応方法

### Databricks Runtime を`12.2`に変更

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/bf35d332-ad3b-490c-97f3-cefe79c2ce5c.png)

### Databricks Runtime の Spark バージョン合わせた Iceberg のライブラリ（`org.apache.iceberg:iceberg-spark-runtime-3.3_2.13:1.6.1`）を変更

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/2c4c3b91-a695-4674-a5a5-f93188cf0298.png)

### エラーとなったコードが正常終了することを確認

```sql
%sql
CREATE TABLE ICEBERG_TBL_2(ID INT,NAME STRING) USING ICEBERG;
INSERT INTO ICEBERG_TBL_2 VALUES(1,"Shraddha");
SELECT * FROM ICEBERG_TBL_2;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/6263f66d-51eb-4565-b764-e59ed6370f7e.png)