AWS Lake Formation + Redshift Spectrum（Glue クローラー使用）でQuickSightデータセットを作る

# はじめに
QuickSightで、Redshift Spectrumを使って接続したいときがあったので、手順をメモします。Lake Formationが絡んでくると、さらにややこしくなるので、結構ハマりました。

やりたいことは、以下の図のようなイメージです（タイトルに出てきたサービスは赤字にしてあります）。この構成だと、S3内のcsvを更新すれば、Glue Data CatalogやRedshiftの更新などせずに、**csvファイルの更新が自動で反映**されてQuickSightから見られます（SPICEを利用している場合は、SPICEの更新が必要）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2949357/1702d069-6bfd-4985-b06e-3c8f1b2b524f.png)

Redshift Spectrumを利用しなくても、QuickSightのデータセット接続の際に「Athena」を選択することで、Glue Data Catalogに直接接続することもできます。
ただ、Redshift Spectrumを経由することで、Redshift内のテーブルとしてSQLで加工処理を実施できます（ビュー作成や、他の内部テーブルとの結合など）。他のテーブルもすべてRedshiftにあるなど、Redshiftを中心に管理したいという場合は今回ようにRedshift Spectrumを使うとデータ保管、加工がRedshiftで統一できます。

:::note warn
（念のため補足）
**SQLで加工処理したい**だけであれば、Athena上でビューを作成することも可能です。他もすべてGlue Data Catalogで統一しているなら、Athena上で全て作成する方が、管理が楽になる可能性もあります。
:::

# 前提条件
- 既に、Lake Formationの設定は実施済み
- Redshift Serverlessの名前空間、ワークグループは作成済み
    - パブリックにアクセス可能、SSL有効
- QuickSight環境も構築済み

# 大まかな流れ
以下のような流れで実施します。
ポイントは「外部スキーマの定義」で、クローラーを実行しただけだと、Redshift Serverlessのクエリエディタでクエリはできますが、QuickSightのデータセットとして読み込むことが出来ません。外部スキーマを定義してあげることで、Redshift Spectrumを利用してQuickSightからよみこむことができます

- クローラーでGlue Tableを作成
    - S3にCSVファイルをアップロード
    - Glue DB作成
    - クローラーで利用するIAMロールにLFで権限付与
    - クローラー作成&実行
- Redshift Spectrumでクエリしてみる
    - 自分自身にLFで権限付与
    - Redshift Serverlessでクエリする
- 外部スキーマの定義 ★ポイント
    - IAMロールの紐づけとLF権限付与
    - 外部スキーマ作成
    - 外部スキーマ内のテーブルにクエリしてみる
- QuickSightのデータセット作成
    - データソース作成
    - データセット作成

# やってみる

## クローラーでGlue Tableを作成
### S3にCSVファイルをアップロード
まずは、使用するテストデータ（CSV）をS3にアップロードします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2949357/019c1d79-9ee2-46f7-ae89-42313a5c5123.png)

ちなみに、テストデータの中身は以下です。LLMに作ってもらいました。

```csvs:sample_product_list.csv
product_name,price,stock,category
デスクライト,2500,45,家具
シンプルノート,380,120,文具
マグカップ,850,67,キッチン
ブラックペン,650,89,文具
収納ボックス,1200,34,家具
キーホルダー,300,156,アクセサリー
トートバッグ,1800,23,バッグ
カラフル付箋,420,95,文具
ティーポット,2200,12,キッチン
スマホケース,980,78,アクセサリー
```

### Glue DB作成
Glue Tableを作る前に、DBを作成します。
Glueコンソールから作成しますが、この時`Location`に先ほどのS3のパスを指定しましょう。
これを指定しておくことで、Lake FormationでData LocationにS3パスとロールを登録しなくても、DBにTableが作成できるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2949357/efb95823-4cf5-4d0e-b80c-898ad7568c19.png)

### クローラーで利用するIAMロールに権限付与
詳細は省きますが、クローラーで利用するIAMロールに、Lake Formationで以下の権限を付与します。
- DBを対象とした、Super権限
- DBの中のALL Tablesを対象とした、Super権限

1つ目の権限でDBにテーブルを作成できるようになり、2つ目の権限でDB内の全てのテーブルを参照できるようになります。

### クローラー作成&実行
先ほどのテストデータを格納したS3パスをクローリング先に指定して、Glueのクローラーを作成します。
その際、利用するIAMロールは先ほどLake Formationで権限付与したIAMロールにします。

その後、クローラーを実行すると、権限付与などがうまくいっていれば、以下のようにStatusがCompletedになるはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2949357/3d2193f9-e2ba-435c-aa29-f0eb6c577bf9.png)

## Redshift Spectrumでクエリしてみる
### 自分自身にLake Formationで権限付与
今コンソールログインしているIAMユーザーやIAMロールに対して、Lake Formationで以下の権限付与します。

- DBの中のALL Tablesを対象とした、Super権限

### Redshift Serverlessでクエリする
クエリエディタv2を使って、Redshift ServerlessのワークグループにFederated userでログインします（ユーザー名、パスワード認証だと、クエリができません）。

その後、`external databases`の中の`awsdatacatalog`の中に、先ほど作成したDBと、クローリングした結果作成されたテーブルがあるはずです。
それに対して、クエリすると、データが取得できます。

:::note info
今時点では、Glue Tableに対して、Redshift Serverlessで接続しているFederated userがクエリをしています。そのため、1つ前の「自分自身にLF権限付与」をしないとエラーでクエリできなくなります。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2949357/fb0a1299-1ff5-4e79-bfdc-83e8bdca36a2.png)

一般的には、外部スキーマを作成して、外部テーブルを作成するはずですが、今回はGlueクローラーを使って外部テーブルを先に作成しました。

https://docs.aws.amazon.com/ja_jp/redshift/latest/dg/c-spectrum-external-tables.html

## 外部スキーマの定義
### IAMロールの紐づけと権限付与
Redshift Spectrumでは、Redshift Serverlessの名前空間に紐づいたIAMロールを使ってクエリします。
そのため、以下のようにIAMロールを作成して紐づけておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2949357/95e085a6-8063-49a1-befd-55cefc3641bd.png)

その後、そのIAMロールに、Lake Formationで以下の権限を付与します。

- DBの中のALL Tablesを対象とした、Super権限

### 外部スキーマ作成
今回はGlueクローラーで外部テーブルを先に作成したので、外部スキーマが存在していません。これがないとQuickSightからテストデータのテーブルに接続できないため作成していきます。

クエリエディタで、以下を実行します（DBはdevにいる事を前提にしてます）。

```sql
create external schema spectrum_test_schema from data catalog 
database 'spectrum_test_db' 
iam_role DEFAULT;
```

:::note warn
もし上記のSQL文を実行してエラーとなったら、管理者ユーザーでログインし直して、以下を実行してデータベースdevに対してのALL権限を付与してみてください。自身のロール名やユーザー名は`select current_user;`を実行して確認してください。

```sql
GRANT ALL ON DATABASE dev to "IAMR:<Role-name>"
```
:::

### 外部スキーマ内のテーブルにクエリしてみる
先ほど作成した外部スキーマ内に、テーブルが存在して、クエリが実行できるはずです。

:::note info
ここでは、自分自身ではなく、名前空間に紐づいたIAMロールがクエリします。そのため、そのIAMロールにLake Formationでの権限が付与されていないと、Tablesが0件と表示されます。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2949357/87015f54-6910-4d66-bd6b-96c8cdef5529.png)


## QuickSightのデータセット作成
### データソース作成
QuickSightのデータソースを作成します。Redshift(手動接続)から、以下のように接続して作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2949357/51154324-f532-4021-8f8a-ae9089a9abd7.png)

### データセット作成
今作成したデータソースから、外部スキーマの中のテーブルを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2949357/503458b4-0d47-42c0-a781-b14e6b34ffb4.png)

以下のように中身が見れて、データセットが作成できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2949357/fe2a5c30-0005-4577-ae43-89834144e7a1.png)

# おわりに
ポイントは、Glueクローラーでテーブルを作成したとしても、外部スキーマをRedshiftクエリエディタで作成しないといけないことでした。
そうしないと、QuickSight側でデータセットを作成しようとしても、見えないか、見えてもエラーとなります。
今回検証した環境では、そもそもスキーマが見えませんでしたが、別の環境ではテーブル自体は見えますが、データセットの編集をすると以下のようなエラーが出ました。

```
No columns are found in the source.
```

ここら辺はなかなかややこしいところですが、しっかり理解していきたいですね。