Databricks にて Confluent から JSON 形式の Topic のデータ取得を手動でスキーマを指定して実施する方法

## 概要

Databricks にて Confluent から JSON 形式の Topic のデータ取得を手動でスキーマを指定して実施する方法を紹介します。

本記事は、以下のシリーズの一部です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/27593d44-23cc-bd0a-98d1-bd538793cad4.png)

引用元：[Databricks と Confluent をつなぐ：データ連携の全体像を徹底解説 #Spark - Qiita](https://qiita.com/manabian/items/b79d2ad8a624065c9f57)

## 事前準備

### 1. Confluent にて Topic を作成

```text
{
  "properties": {
    "gender": {
      "connect.index": 3,
      "type": "string"
    },
    "regionid": {
      "connect.index": 2,
      "type": "string"
    },
    "registertime": {
      "connect.index": 0,
      "connect.type": "int64",
      "type": "integer"
    },
    "userid": {
      "connect.index": 1,
      "type": "string"
    }
  },
  "title": "ksql.users",
  "type": "object"
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/e5f43fba-d28b-6d19-7f1e-3fdea489951c.png)


### 2. Confluent にて API キーを主塔

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/134d657f-daeb-f6c6-67aa-99c6da0a2524.png)

## データを取得する手順

### 1. Databricks 上で API キーを変数にセット

```python
# Confluent に対する認証情報をセット
bootstrap_servers = "pkc-921aa.us-east-2.aws.confluent.cloud:9092"
sasl_username = "U4BML4OPRCaaaa"
sasl_password = "zzEjUzyUwYYJneNE240L7jgPVrHAtRBANo6wnnzCgKlGIJ9OxJqaJZWRvaaaaa"
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/6ce615e5-5267-5fdb-5619-44c3dd2cda32.png)

### 2. Topic 名とスキーマを変数にセット

```python
from pyspark.sql.types import StructType, StructField, StringType, LongType

topic_name = "json_user"
schema = StructType(
    [
        StructField("registertime", LongType(), True),
        StructField("userid", StringType(), True),
        StructField("regionid", StringType(), True),
        StructField("gender", StringType(), True),
    ]
)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/0e59bbb8-8a73-c409-b514-1200cce903a2.png)


### 3. Condluent からデータを取得

```python
from pyspark.sql.functions import col, expr, from_json

# Confluent から読み込み
df = (
    spark.readStream.format("kafka")
    .option("kafka.bootstrap.servers", bootstrap_servers)
    .option("kafka.security.protocol", "SASL_SSL")
    .option(
        "kafka.sasl.jaas.config",
        f'kafkashaded.org.apache.kafka.common.security.plain.PlainLoginModule required username="{sasl_username}" password="{sasl_password}";',
    )
    .option("kafka.sasl.mechanism", "PLAIN")
    .option("subscribe", topic_name)
    .option("startingOffsets", "earliest")
    .load()
)

# Key を Deserialize
key_des_df = df.withColumn(
    "key",
    col("Key").cast("string"),
)

# Value から Magic Byte と Schema ID を除去
no_magic_df = key_des_df.withColumn(
    "value",
    expr("substring(value, 6, length(value) - 5)"),
)

# Magic Byte と Schema ID を取り除いた Value を Deserialize
decoded_df = no_magic_df.withColumn(
    "decoded_value",
    from_json(
        col("value").cast("string"),
        schema,
    ),
)

# Deserialize した Value のカラムを展開
tgt_cols = [
    "key",
    "decoded_value.*",
    "topic",
    "partition",
    "offset",
    "timestamp",
    "timestampType",
]
src_df = decoded_df.select(tgt_cols)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/0b650929-7321-e4e1-41ad-d1e168fa1480.png)

### 4. データを表示

```python
src_df.display()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/cb17b95d-6b82-d5ee-9de3-0d0eccf34475.png)

## 事後処理

### Databricks ノートブックの実行を停止

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/7544912e-1a82-a6ad-2dc2-c07d5723b85c.png)