日記BOTにクイズ機能をつけてみる①　テーブル作成

お疲れさまです、みやもとです。

先日作成したLINEBOTでは[日記を小説風にして英訳と和訳を返す](https://qiita.com/Mymt_aggw2208/items/4f098fd9423bf95662ba)ようにしていました。

せっかく英訳と和訳を付けたので、「英訳→文章に関するクイズ→和訳」という感じで機能を追加してみることにしました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477580/5dd96de8-4c31-0933-60fc-692c28ce9b98.png" width=50%>

出題時は問題文と選択肢がテキストで返信され、クイックリプライから答えを選ぶようにしました。
答えを選んでいくとこんな感じになります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477580/71dcd431-0933-ab76-2cab-4789d9f5d920.jpeg" width="50%">


長くなりそうなので記事を分けます。
今回は文章と問題・選択肢を保存するテーブルを準備します。

## BigQueryを使ってみる
BOTの動作として必要なのは
①日記を生成する
②英訳文のみ返信する
③ユーザー側からのアクションを受けて問題を出題・採点する
④全問題を採点し終わったら正解数と和訳文を返す
という処理になります。
ユーザー側からのアクションをはさむため、ユーザーに紐づいた日記データと問題をどこかに保持しておくことが必要です。

なのでBigQueryにテーブルを作成して、そこでデータを管理することにしました。
まずはGoogle Cloud Platformのメニューから「BigQuery - BigQuery Studio」を開きます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477580/cdde93ec-d024-6797-73cb-632416263801.png" width="50%">

プロジェクトのメニューから「データセットを作成」を選択します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477580/acc4522e-cab1-2541-6ef0-c8ff889d3868.png" width="50%">

そこからデータセットに関する設定を入力。
データセットIDとリージョンぐらいしかいじらなかったです。

そして作ったデータセットのメニューから「テーブル作成」を選択。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477580/f3dce465-65be-536a-aa21-9709119c472d.png" width="50%">

テーブルIDやカラム等を定義して作成していきます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477580/b90b85ab-7331-1571-63de-d0de3a8f4af4.png" width="80%">

今回は以下のテーブルを作成しました。

### diary：日記テーブル
日記の内容を保持するテーブルです。

| フィールド名 | 種類 | モード |
|:-:|:-:|:-:|
| id | INTEGER | REQUIRED |
| user_id | STRING(100) | REQUIRED |
| diary_date | DATE | REQUIRED |
| original_text | STRING(300) | NULLABLE |
| english_text | STRING(2000) | NULLABLE |
| japanese_text | STRING(2000) | NULLABLE |
| number_of_correct_answers | INTEGER | REQUIRED |

### question：問題テーブル
日記の英文に関連する問題を保持するテーブルです。
日記1レコードに対して3レコードが関連付けられます。

| フィールド名 | 種類 | モード |
|:-:|:-:|:-:|
| id | INTEGER | REQUIRED |
| diary_id | INTEGER | REQUIRED |
| question_no | INTEGER | REQUIRED |
| question_text | STRING(200) | REQUIRED |
| explanation_text | STRING(300) | REQUIRED |
| mistake_flag | boolean | NULLABLE |

### options：選択肢テーブル
問題の回答に使う選択肢と正解かどうかを保持するテーブルです。
問題1レコードに対して3レコードが関連付けられます。

| フィールド名 | 種類 | モード |
|:-:|:-:|:-:|
| id | INTEGER | REQUIRED |
| question_id | INTEGER | REQUIRED |
| option_no | INTEGER | REQUIRED |
| option_text | STRING(200) | REQUIRED |
| correct_flag | boolean | REQUIRED |

### user_status：ユーザーステータステーブル
ユーザーの現在の状態や処理中の日記・問題データを保持するテーブルです。
私しか使わないので1レコードしか発生しませんが、ここに入力日数分の日記レコードが関連付けられます。

| フィールド名 | 種類 | モード |
|:-:|:-:|:-:|
| user_id | STRING(100) | REQUIRED |
| status | STRING(1) | NULLABLE |
| current_diary_id | INTEGER | NULLABLE |
| current_question_no | INTEGER | NULLABLE |
| latest_diary_date | DATE | REQUIRED |

とりあえず今日はテーブル定義が終わったところで終了。

## 余談：Cloud SQL
Cloud Runの処理作成時、Cloud SQLとの接続について設定する項目があるのを見かけました。
デフォルトの想定はCloud SQLなのか？と思い、BigQueryとどちらが良いかをAIに質問。
GeminiとClaudeの両方に聞いてみたところ「レスポンス早いしデータ量も多くならないならCloud SQLが良いよ」という回答でした。
念のためBigQueryの無料枠考慮した？と重ねて聞くと、GeminiとClaudeで若干の温度差。
Geminiは「データの増加量とかクエリの発行回数とかによってはやっぱりCloud SQLがいいよ」という感じ。
Claudeは「気を付けるべき点はあるけどBigQueryの無料枠がおすすめ」と、最初の提案を覆す内容になりました。

まぁ１回試してみようということでいったんはCloud SQLを試そうと思ったのですが、課金レポートがこんな感じになって途中でやめました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477580/fff1b3b5-28de-4135-e424-e0e9262acacc.png" width="60%">

金額としては何百円程度なのですが、これ実際にSQL発行したのはグラフのうちの2,3日なんですよね。
少額とはいえ何も触ってない日でも金額変わらないのがちょっと嫌かな、となったので、レスポンスを引き換えにBigQueryに変えました。