Upgrade to Pro — share decks privately, control downloads, hide ads and more …

攻めのデータ活用のためのメタデータ整備:生成 AI を用いた構造化メタデータからの SQL...

攻めのデータ活用のためのメタデータ整備:生成 AI を用いた構造化メタデータからの SQL クエリ生成

8/3木開催のビットバンク様とのクローズド勉強会における、開発本部角田の登壇資料です。

MIXI ENGINEERS

August 04, 2023
Tweet

More Decks by MIXI ENGINEERS

Other Decks in Technology

Transcript

  1. ©MIXI 2 Speaker Deck (など) でご覧の⽅へ ご覧いただきありがとうございます。 ⽣成 AI が隆盛を極める中、⾃社のデータを取り込んで⽣成

    AI を活⽤する動きも 広がり始めています。 ⽣成 AI に⾃社データをうまく扱ってもらう(今回取り上げた SQL ⽣成も含む)ためには 細かいプロンプトエンジニアリングに加えて、あるいはそれ以上に メタデータを含めたデータの品質 が重要となってきます。 現状、確実な SQL の⽣成はまだ難しい印象ですが、今後⽣成 AI モデルや周辺環境のアップデート、 ベンダー側での実装が進むことで実⽤化が進む可能性があります。 そのような状況になっても、データ品質の整備は有意義な取り組みになってくるはずです。 本資料が、メタデータの整備などデータ品質を考えるきっかけとなれば幸いです! ★ LLM 出⼒例は ChatGPT API (gpt-4-0613, temperature=0.1) によるものです。何度か試⾏したうちの例を掲載してます
  2. ©MIXI ⾃⼰紹介 開発本部 > CTO 室 > データグループ ⾓⽥ 孝昭(つのだ

    たかあき) l MIXI でのおしごと • データ利活⽤に関する知⾒を全社的に布教 特にデータマネジメントの重要性を知ってもらうために奔⾛中 • ⼩規模プロダクト‧バックオフィスなど、専任のデータ系エンジニアがいない組織への技術的⽀援 (データ基盤構築‧データ分析‧ダッシュボード整備などデータ周りをフルスタックでやっています) l 前職では… • データ分析によるレコメンド改善⼿法の提案、機械学習を⽤いた不正利⽤対策など 3 猫を飼っています
  3. ©MIXI 4 本発表で⽤いるサンプルテーブル群の説明 スマホゲームのログデータを蓄積するデータウェアハウスを想定 l users(ユーザー情報) l friendships_snapshot (ともだち関係の⽇次スナップショット) 名前

    型 説明 id INTEGER ユーザー ID birthday DATE 誕⽣⽇(年齢計算⽤) l events(⾏動ログ) 名前 型 説明 id INTEGER 関係 ID snapshot _date DATE スナップショットの ⽇付 user_id INTEGER ユーザー ID friend_ user_id INTEGER ともだちのユーザー ID 名前 型 説明 id INTEGER ログ ID event_ timestamp TIME STAMP ログの発⽣時刻 user_id INTEGER ユーザー ID event_name STRING ログの種類 • complete_tutorial • start_stage • end_stage parameters STRING (JSON) ログのパラメータ • start_stage: {"stage_id": "STRING"} • end_stage {"stage_id": "STRING", "result": "STRING"}
  4. ©MIXI 5 プロンプト(⽇本語訳) SQLite3 クエリ⽣成器として振る舞って下さい。 以下に⽰すテーブルスキーマに従って、ユーザーの質問に答える構⽂的に正しい クエリを⽣成して下さい。回答は以下の順序で構成して下さい: 最初に⽣成された クエリ、次に⽇本語による説明。答えに必要な情報が⽋けている場合は、追加の 質問をして下さい。

    以下の表のテーブル名とカラム名のみを使⽤するようにして下さい。存在しない カラムを問い合わせないように注意してください。JSON ⽂字列を含むカラムを 参照する場合は、SQLite 組み込みの JSON 関数と演算⼦を使⽤して下さい。 -------- {TABLE_SCHEMA} -------- {question} スキーマ情報を JSON で与える スキーマに存在しない情報の利⽤ (ハルシネーション)をある程度 防⽌できる(こともある) ⽇本語‧英語による指⽰で出⼒の精度にはあまり差は無さそう? (本資料では英語プロンプトを与えた場合の結果を⽰す)
  5. ©MIXI 6 プロンプト(実際に与えたもの) You will act as a SQLite3 query

    generator. Please generate a syntactically correct query that answers the user's question according to the table schema shown below. Your responses should be structured in the following order: first, a generated query, followed by an explanation in Japanese. If any essential information needed for the answer is missing, please prompt the user with additional questions. Please ensure to only use the table names and column names in the tables below. Be careful to not query for columns that do not exist. When referring to a column that contains a JSON string, use SQLite built-in JSON functions and operators. The following is the table schema: -------- {TABLE_SCHEMA} -------- {question}
  6. ©MIXI 7 例1: 年齢の計算 & 階級ごとに集計 question = ユーザーの⼈数を年齢層別に集計して下さい。階級は「20歳未満」「20歳以上30歳未 満」「30歳以上40歳未満」「40歳以上」の4つとします。

    ```sql SELECT CASE WHEN age < 20 THEN '20歳未満' WHEN age >= 20 AND age < 30 THEN '20歳以上30歳未満' WHEN age >= 30 AND age < 40 THEN '30歳以上40歳未満' ELSE '40歳以上' END AS age_group, COUNT(*) AS user_count FROM (SELECT id, (strftime('%Y', 'now') - strftime('%Y', birthday)) - (strftime('%m-%d', 'now') < strftime('%m-%d', birthday)) AS age FROM users) GROUP BY age_group; ``` このクエリは、まずユーザーの年齢を計算し、その結果を元に年齢層を分けています。年齢の計算は現在の年から誕⽣⽇の年を引き、その後現在 の⽇付が誕⽣⽇より前であれば1を引くことで⾏っています。その結果を元にCASE⽂を使って年齢層を分け、その年齢層ごとにユーザー数をカウ ントしています。 Good! ※なお、何度か試⾏したところ 誕⽣⽇から実⾏⽇までの⽇数を 365 で割る⽅法も 提案されやすかった(うるう年の関係で不正確)
  7. ©MIXI 8 例2: スナップショットテーブルの参照(1/2) question = ユーザーIDが1のユーザーとともだち関係となっているユーザーの数を教えて下さい。 ポイント: l スナップショットであることを認識できるか?

    WHERE snapshot_date = … で絞り込まなければ 重複してカウントしてしまう 名前 型 説明 id INTEGER 関係 ID snapsho t_date DATE スナップショットの ⽇付 user_id INTEGER ユーザー ID friend_ user_id INTEGER ともだちのユーザー ID 1,2022-06-11,1,2 2,2022-06-11,2,1 3,2022-06-11,1,3 4,2022-06-11,3,1 5,2022-06-12,1,2 6,2022-06-12,2,1 7,2022-06-12,1,3 8,2022-06-12,3,1 9,2022-06-12,2,3 10,2022-06-12,3,2 1 2 3 1 2 3 2022- 06-11 2022- 06-12 データ例 左データを図⽰
  8. ©MIXI 9 例2: スナップショットテーブルの参照(2/2) question = ユーザーIDが1のユーザーとともだち関係となっているユーザーの数を教えて下さい。 Query: ```sql SELECT

    COUNT(friend_user_id) AS friend_count FROM friendships_snapshot WHERE user_id = 1 AND snapshot_date = (SELECT MAX(snapshot_date) FROM friendships_snapshot WHERE user_id = 1); ``` ⽇本語の説明: このクエリは、ユーザーIDが1のユーザーと友達関係にある他のユーザ ーの数をカウントしています。また、`snapshot_date` が最新のデータ のみを使⽤します。なぜなら、古い `snapshot_date` のデータを含むと、 以前は友達だったが現在は友達でないユーザーまでカウントされてしま うからです。 OK 名前 型 説明 id INTEGER 関係 ID snapshot_date DATE スナップショットの⽇付 user_id INTEGER ユーザー ID friend_user_id INTEGER ともだちのユーザー ID l クエリは概ね OK • サブクエリの WHERE 句は趣旨的には不要 (「最新の」ではなく「ユーザー 1 にとも だちがいる⽇の中で最新の⽇」の意になる) l クエリの説明には不正確な点がある ※ただし、何度か試⾏したところ snapshot_date を指定しない誤答の ⽣成が⾮常に多かった
  9. ©MIXI 10 例3: ⾏動ログの絞り込み(1/2) question = 全ユーザー数、チュートリアルが 完了したユーザーの数、1つでもステージを クリアしたことがあるユーザーの数を教えて下さい。 ポイント:

    l 正しい event_name で絞り込めるか? l STRING に⼊っている JSON を解析する クエリを組み⽴てられるか? SQLite3 は JSON を扱う関数や演算⼦が存在する 1,2023-06-01 01:01:00.000,1,complete_tutorial, 2,2023-06-01 01:02:00.000,1,start_stage,"{""stage_id"":1}" 3,2023-06-01 01:03:00.000,1,end_stage,"{""stage_id"":1,""result"":""success""}" 4,2023-06-02 02:01:00.000,2,complete_tutorial, 5,2023-06-02 02:02:00.000,2,start_stage,"{""stage_id"":1}" 6,2023-06-02 02:03:00.000,2,end_stage,"{""stage_id"":1,""result"":""failed""}" ◀ データ例 名前 型 説明 id INTEGER ログ ID event_timestamp TIMESTAMP ログの発⽣時刻 user_id INTEGER ユーザー ID event_name STRING ログの種類 • complete_tutorial • start_stage • end_stage parameters STRING (JSON) ログのパラメータ • start_stage: {"stage_id": "STRING"} • end_stage {"stage_id": "STRING", "result": "STRING"}
  10. ©MIXI 11 例3: ⾏動ログの絞り込み(2/2) question = 全ユーザー数、チュートリアルが完了したユーザーの数、1つでもステージをクリアし たことがあるユーザーの数を教えて下さい。 ```sql SELECT

    (SELECT COUNT(*) FROM users) AS total_users, (SELECT COUNT(DISTINCT user_id) FROM events WHERE event_name = 'complete_tutorial') AS tutorial_completed_users, (SELECT COUNT(DISTINCT user_id) FROM events WHERE event_name = 'end_stage' AND JSON_EXTRACT(parameters, '$.result') = 'success') AS stage_cleared_users; ``` このクエリは、以下の3つの情報を取得します。 1. `total_users`: `users`テーブルから全ユーザー数をカウントします。 2. `tutorial_completed_users`: `events`テーブルから、`event_name`が `complete_tutorial`となっているユーザーの数をカウントします。同⼀ユ ーザーが複数回チュートリアルを完了した場合も1回とカウントします。 3. `stage_cleared_users`: `events`テーブルから、`event_name`が `end_stage`で、かつ`parameters`の`result`が`success`となっているユー ザーの数をカウントします。同⼀ユーザーが複数回ステージをクリアし た場合も1回とカウントします。 Good! l event_name の指定‧JSON の解析とも⾏えている ※なお、何度か試⾏したところ それぞれの値を別々のクエリで取得する ⽅法も提案されやすかった
  11. ©MIXI 12 例4: 対応する⾏動ログが存在しない質問(1/2) question = 退会したユーザー数を教えて下さい。 ポイント: l 対応するログが存在しない場合において

    その旨を認識できるか? ログ種類を妄想(ハルシネーション)せずに 回答を拒否できるか? 1,2023-06-01 01:01:00.000,1,complete_tutorial, 2,2023-06-01 01:02:00.000,1,start_stage,"{""stage_id"":1}" 3,2023-06-01 01:03:00.000,1,end_stage,"{""stage_id"":1,""result"":""success""}" 4,2023-06-02 02:01:00.000,2,complete_tutorial, 5,2023-06-02 02:02:00.000,2,start_stage,"{""stage_id"":1}" 6,2023-06-02 02:03:00.000,2,end_stage,"{""stage_id"":1,""result"":""failed""}" こ の DB に は 退 会 ロ グ は な い 名前 型 説明 id INTEGER ログ ID event_timestamp TIMESTAMP ログの発⽣時刻 user_id INTEGER ユーザー ID event_name STRING ログの種類 • complete_tutorial • start_stage • end_stage parameters STRING (JSON) ログのパラメータ • start_stage: {"stage_id": "STRING"} • end_stage {"stage_id": "STRING", "result": "STRING"}
  12. ©MIXI 13 例4: 対応する⾏動ログが存在しない質問(2/2) question = 退会したユーザー数を教えて下さい。 退会したユーザーを正確に数えるためには、ユーザーの⾏動を追跡する ための特定のログが必要となります。しかし、提供されたスキーマでは、 ユーザーが退会したことを⽰す特定のログの存在が確認できません。そ

    のため、現状ではこの質問に直接的に答えることはできません。退会ロ グが存在する場合、そのログの名称やパラメータなどについて詳しく教 えていただけますか? 退会したユーザーを特定する⽅法やその他の関連情報がある場合は、そ れについても教えてください。その情報を基に新たなクエリを作成しま す。 l クエリは⽣成せず、追加の質問を要求 • プロンプトに「必要な情報が⽋けている場合は追加 の質問をして下さい」との指定が効いた (これがないと以下のようなでたらめが⽣成されることも ↓) Good! ※特にこの例は GPT-3.5 では うまくいかないケースが多かった GPT-4 でも temperature を 下げないと失敗する場合がちらほら Generated query: ```sql SELECT COUNT(id) AS num_of_unsubscribed_users FROM users WHERE birthday IS NOT NULL ``` Explanation in Japanese: 上記のクエリは、ユーザー情報テーブル(users)から、退会したユー ザーの数を数えるためのクエリです。退会したユーザーは、誕⽣⽇ (birthday)がNULLではないユーザーとして定義されます。したがっ て、誕⽣⽇がNULLではないユーザーの数を数えることで、退会した ユーザー数を求めることができます。クエリの結果は、 「num_of_unsubscribed_users」という別名で返されます。
  13. ©MIXI 14 LLM に SQL クエリを作らせる⽅法 以下の⽅法がおそらくは代表的(ただし1ヶ⽉後には陳腐化している可能性も) *1: コードの⽣成に加え実⾏もできる機能。ファイルを渡して処理させられる /

    *2: 構造化データのやりとりができる機能 概要 ⽅法 特徴 ① 最初にスキーマ情報を 全て渡す プロンプトの末尾にスキーマ情報を全て⼊ れて問い合わせる • あらゆる⽣成 AI(Web UI 含む)で簡単に試すことがで きる • テーブル数‧カラム数(∝ ⼊⼒⽂字数)が多い場合は 精度が低下するリスクがある他、場合によっては制限 トークン数をオーバーしてしまい現実的ではない ② 対話的にスキーマ 情報を渡す 1. プロンプトにテーブルの⼀覧のみを渡 して、回答に必要なテーブルを列挙さ せる 2. 回答に必要なテーブルの詳細なスキー マ情報を渡す ReAct などの枠組みや ChatGPT Function Calling*2 で⼀連の流れを⾃動化可能 • 全スキーマ情報を渡すよりもトークン数を節約できる • 対話的処理を⾃動化させる場合は実装が必要 (Web UI しかない場合は⾃動化困難) • 最初に正しいテーブルを特定できなければ ⽣成がうまくいかないリスクがある ③ ChatGPT Code Interpreter*1 スキーマとデータを与えてスキーマ分析‧ クエリ発⾏コードを⽣成‧実⾏させる (原理的には ② の延⻑) • クエリの実⾏及び可視化まで可能 • Web UI 専⽤かつネット接続ができない(8/3 現在)た め⼩〜中規模データのアドホックな分析向き ④ クエリ⽣成 SaaS など (基本的に⽅法はブラックボックス) • 簡便だが、あまり⾃由度は⾼くない点に注意を要する
  14. ©MIXI 15 LLM にうまく SQL クエリを作らせるには? 例 1~4 はそれなりにうまく⾏く場合もあるが、実際のデータに対しては正しいクエリを 確実に⽣成させるのは難しい感触(特に

    JOIN などを要する複雑なケース) ただし、以下の⽅法で⽣成精度をある程度は上げることが可能 l プロンプトの⼯夫 • スキーマ参照の指⽰や、情報不⾜時の指⽰を加える • with 句の使⽤などを指⽰することでより可読性が⾼いクエリが⽣成できるとの報告★も l パラメータの調整 特に temperature を低め(例: 0 ~ 0.1)にすると良さそう l 質問応答例の提⽰ (few-shot prompting) l l ★ ⾼橋光(2023)『SQLを活⽤したデータ分析におけるChatGPTの活⽤法』 ??? ポイント1 ??? ??? ポイント2 ??? むしろこれがないと 絶対にうまくいかない これもやった⽅が良い 実 は 本 発 表 の メ イ ン は こ ち ら
  15. ©MIXI 16 「ポイント1」がなかった場合どうなっていたか? 例2〜4 でいずれも正しくないクエリが⽣成されてしまう(クエリのみ抜粋) ★ ただし例 3, 4 は、追加情報を求めてきたり「仮にイベント名が

    〜 であれば」などと注釈を含めたりする場合もあった SELECT COUNT(*) FROM friendships_snapshot WHERE user_id = 1; SELECT COUNT(DISTINCT users.id) AS total_users, COUNT(DISTINCT CASE WHEN events.event_name = 'tutorial_completed' THEN events.user_id END) AS tutorial_completed_users, COUNT(DISTINCT CASE WHEN events.event_name = 'stage_cleared' THEN events.user_id END) AS stage_cleared_users FROM users LEFT JOIN events ON users.id = events.user_id; SELECT COUNT(DISTINCT user_id) FROM events WHERE event_name = 'user_deactivated'; Bad… スナップショットを積み上げるテーブルだが スナップショット⽇で絞り込まれていない Bad… 正しくないイベント名が指定されている Bad… 存在しないイベント名が指定されている 例2 例3 例4
  16. ©MIXI 17 You will act as a SQLite3 query generator.

    Please generate a syntactically correct query that answers the user's question according to the table schema shown below. Your responses should be structured in the following order: first, a generated query, followed by an explanation in Japanese. If any essential information needed for the answer is missing, please prompt the user with additional questions. Please ensure to only use the table names and column names in the tables below. Be careful to not query for columns that do not exist. When referring to a column that contains a JSON string, use SQLite built-in JSON functions and operators. The following is the table schema: -------- [{"name": "users", "columns": [{"name": "id"}, {"name": "birthday"}]}, {"name": "events", "columns": [{"name": "id"}, {"name": "event_timestamp"}, {"name": "user_id"}, {"name": "event_name"}, {"name": "parameters"}]}, {"name": "friendships_snapshot", "columns": [{"name": "id"}, {"name": "snapshot_date"}, {"name": "user_id"}, {"name": "friend_user_id"}]}] You will act as a SQLite3 query generator. Please generate a syntactically correct query that answers the user's question according to the table schema shown below. Your responses should be structured in the following order: first, a generated query, followed by an explanation in Japanese. If any essential information needed for the answer is missing, please prompt the user with additional questions. Please ensure to only use the table names and column names in the tables below. Be careful to not query for columns that do not exist. When referring to a column that contains a JSON string, use SQLite built-in JSON functions and operators. The following is the table schema: -------- [{"name": "users", "description": "ユーザー情報。¥n", "columns": [{"name": "id", "description": "ユーザー ID"}, {"name": "birthday", "description": " 誕生日。年齢の計算に使用する。ユーザーが未入力の場合は NULL"}]}, {"name": "events", "description": "ユーザーの行動ログ。¥n", "columns": [{"name": "id", "description": "ログ ID"}, {"name": "event_timestamp", "description": "ログの発生日時"}, {"name": "user_id", "description": "ログ を発生させたユーザーの ID"}, {"name": "event_name", "description": "ログの 種類。以下のいずれか: `complete_tutorial`: チュートリアル完了, `start_stage`: ステージ開始, `end_stage`: ステージ終了"}, {"name": "parameters", "description": "ログのパラメーターを JSON 文字列で格納する。 パラメータはログの種類によって異なる。¥n- `complete_tutorial`: NULL¥n- `start_stage`¥n - `stage_id`: ステージ ID¥n- `end_stage`¥n - `stage_id`: ステージ ID¥n - `result`: プレイ結果。以下のいずれか: `success`: クリア, `failed`: 失敗, `cancel`: キャンセル¥n"}]}, {"name": "friendships_snapshot", "description": "`snapshot_date` 時点における、ユー ザーのともだち関係。異なる `snapshot_date` で同一のともだち関係が存在する ことがあるため、ある時点でのともだち関係を参照する場合は `snapshot_date` を指定する必要がある。¥n", "columns": [{"name": "id", "description": "ログ ID"}, {"name": "snapshot_date", "description": "スナップショットの日付"}, {"name": "user_id", "description": "ユーザー ID"}, {"name": "friend_user_id", "description": "ともだちのユーザー ID"}]}] ポイント1 なし ポイント1 あり データに関する情報 メタデータ の詳細な記述を LLM に渡している
  17. ©MIXI 18 ポイント1: 詳細なメタデータの提供 l あるデータがどのようなものかを説明するデータ ▶ l 様々な種類があるが★ クエリ⽣成を⾏う

    LLM にとって (⼈間にとっても)重要なのは何が⼊っているかの情報 取り扱うデータによってはドメイン固有の⽤語定義も メタデータに含めたり、プロンプトに含める必要がある 例: ゲームのキャラクターに「タイプ」が属性としてあった場合、 「タイプ」が何かを理解できないかも知れない(「型」と勘違いされるかも) ★ データの管理者やアクセス権、個⼈情報の有無、データリネージ(データの上流‧下流に関する情報)、アクセスパタ ーン、バックアップ規定、廃棄基準など。クエリ⽣成以上のこともさせたければこれらの情報も必要になりうる メタデータ 名前 型 説明 id INTEGER ユーザー ID birthday DATE 誕⽣⽇(年齢計算⽤) シンプルなメタデータの例 - name: users description: | ユーザー情報。 columns: - name: id description: "ユーザー ID" - name: birthday description: "誕生日。年齢の計算に使 用する。ユーザーが未入力の場合は NULL" YAML での簡単なメタデータ表現例 (dbt のモデル定義ファイル)
  18. ©MIXI 20 メタデータ管理の実際 実際には Wiki やスプレッドシートで管理しているケースが多いと思われる (ソース: 私の経験より) ⼈間が読む上ではあまり問題なくても、LLM の⼊⼒に⽤いるには厄介な場合も

    l メタデータがドキュメント内にテキスト形式で書かれている → 抽出が必要 ただし、⽣成 AI を利⽤してある程度の⾃動化は可能かも l 古い情報‧新しい情報が混在していて最新のものを特定できない l メタデータが Wiki 内で散逸している‧複数の Wiki/ファイルに散逸している l そもそもメタデータに関する情報がドキュメント化されていない (⼝頭やチャットでのやりとりに留まっている、コードを読まないと分からない)
  19. ©MIXI 22 [補⾜] dbt を使っていればモデル定義ファイルを流⽤できる ELT パイプラインの T (Transform; 変換)

    などを効率化する dbt (data build tool) では テーブルやビュー(dbt ⽤語ではモデル)のスキーマ定義を YAML で管理しているため流⽤可能 version: 2 models: - name: users description: | ユーザー情報。 columns: - name: id description: "ユーザー ID" - name: birthday description: "誕生日。年齢の計算に使用する。ユーザーが未入力の場合は NULL" ◀ dbt のスキーマ定義 YAML ファイル例
  20. ©MIXI 23 [補⾜] データカタログの導⼊はどうか? 組織内の様々なデータのメタデータを⼀元的に管理し、検索‧閲覧を可能にするサービスとして データカタログと呼ばれるものがある(GCP Dataplex = 旧 Data

    Catalog, OpenMetadata, DataHub など) ⼀⾒素晴らしいソリューションだが、データカタログそのものを管理するコストに加え、 何よりデータカタログの使⽤を統制することが⾮常に難しいため慎重な導⼊を要する [1] ゆずたそ 編著‧はせりょ‧株式会社⾵⾳屋(2020)『データマネジメントが30分で分かる本』位置 No. 917 より引⽤ [2] 松元亮太(2022)『メタデータ‧マネジメント⼊⾨』スライド 29, 31 より引⽤ 筆者の場合「メタデータのためのツールや体制」の導⼊では、上⼿くいきませんでした。Wikiでの分散アプローチだけが⽣き残りました。 最初の数ヶ⽉は順調なのですが、年単位では挫折しました。もしくは、形酸化したツールに予算と⼯数を垂れ流し続けることになり、挫折以上 に有害な事態に陥りました。 ... その上、直接的な売上への貢献が⾒えにくい箇所ですので、ビジネスの注⼒領域やマクロの景気が変わると、体制変更の煽りを受けやすいと⾔ えます。開発チームや管理チームが、メタデータ領域に専念できなくなり、メンテナンス不⾜によるメタデータの品質低下で、除々に使われな くなります。([1] より引⽤) カタログ‧ゴーストタウン現象 ... しかしながら、エンタープライズになればなるほど、組織に協⼒を促す難易度が⾼くなります。 結果的にメタデータ⼊⼒の継続に失敗し、ゴーストタウンが誕⽣します。 ([2] より引⽤)
  21. ©MIXI 24 ポイント2: データマートの整備 データの前処理や複数テーブルの結合までを LLM にやらせるのは難易度が上がる ⽤途に合わせてデータの抽出‧加⼯を済ませたデータマートを⽤意すると(⼈間にとっても)便利 例: l

    スナップショットテーブルのうち最新の状態のみに関⼼があるなら最新のみを抽出しておく l 「チュートリアルクリア済み」が重要なら⾏動ログテーブルから当該ログを問い合わせて フラグとして JOIN するところまで済ませておく、など データソース1 データソース2 データソース3 ︙ データレイク層 ⽣データ テーブル ⽣データ テーブル データウェアハウス層 前処理済み テーブル 前処理済み テーブル データマート層 ⽤途A⽤ テーブル ⽤途B⽤ テーブル ⽣成 AI ⽣成 AI は加⼯済みの 限られたテーブルのみを参照する
  22. ©MIXI 25 ポイント2 (発展): セマンティックレイヤーで⽣成 AI の可能性が広がる? 「ビジネス指標」と「データ及び集計⽅法」の対応を持たせておくと、指定した指標‧軸から SQL を組み⽴てて問い合わせ‧結果を取得するセマンティックレイヤーは⽣成

    AI にも有益そう ★ 本発表では時間の都合上説明を省きますが、セマンティックレイヤーについては下記解説が分かりやすいです m(_ _)m ‧たくまん(2023)『セマンティックレイヤー / Headless BIとは』 ‧相樂悟(2023)『「コードでデータ分析に関わる指標を管理できる ”Semantic Layer”、dbtとLookerで何が違うの?」 あなたのこの疑問、解消します』 DB Semantic Layer 年齢層: users_extended.age = ~20, [20, 30), [30, 40), 40~ チュートリアル完了: events.event_name = ‘complete_tutorial ... 指標定義(イメージ) dimension: 年齢層 measure: ユーザー数 filter: チュートリアル完了 dimension: 年齢層 measure: ユーザー数 filter: チュートリアル完了 「チュートリアルが完了 しているユーザーの数を 年齢層別に教えて下さい」 SELECT age_group, COUNT(DISTINCT user_id) FROM … 指標‧軸から SQL を組み⽴て テキストから 指標‧軸を 指定させる これが できたら ▼ 便利そう
  23. ©MIXI 26 試案: Looker Explore の URL を LLM に⽣成させるのはどうか?

    Looker は Explore(指標‧軸を指定して結果を閲覧する画⾯)への URL パラメータで指標‧軸を指定できる AI に URL を⽣成させればテキストを⼊⼒としてすぐに⾒たい画⾯へ⾶ぶことができる ★ Explore の閲覧には Standard 以上のユーザーライセンスを要する点に注意(Viewer では閲覧できない) DB Looker view: user { dimension: age_group { ... } dimension: is_tutorial_completed { ... } measure: count { ... } ... } LookML ③「チュートリアルが完了 しているユーザーの数を 年齢層別に教えて下さい」 SELECT age_group, COUNT(DISTINCT user_id) FROM … ⑦指標‧軸から SQL を組み⽴て ①LookML から必要な部分のみ抽出 (Python の lkml パッケージで parse 可能) ②URL の⽣成ルールをプロンプトで指⽰ ④ https://____.looker.com/explore/${explore}? fields=age_group,is_tutorial_completed&... ⑥指標‧軸を指定 ⑧クエリ結果を 画⾯に表⽰ ⑤ URL に アクセス
  24. ©MIXI 27 試案: Looker Explore の URL を LLM に⽣成させるプロンプト例

    以下のようなプロンプトに LookML から抽出した情報を含めるとある程度⽣成できた URL の組み⽴てもテキストで指⽰しているが、Function Calling を使えばより確実にできそう You will act as a Looker Explore URL generator. Please generate a URL that answers the user's question according to the View metadata shown below. Your responses must be output in the following order: the generated URL, followed by a description in Japanese. If any information necessary for the answer is missing, please ask the user additional questions. You can use the following explores: <explore の一覧>. Note that the field identifier consists of the View name and the Dimension or the Measure name, separated by a period. The URL is output according to the following format: https://${LOOKER_URL}/explore/${explore_name}?fields=${fields}&pivots=${pivots}&f[${filtered_field}]=${filter_condition}&sorts={sort_field} - explore_name: The name of the Explore to be used, one of: <explore の一覧>. - fields: The field identifiers to be used, separated by commas. Note that all fields used for pivoting, filtering, and sorting must also be specified. - pivots: The field identifiers to be used for pivoting, separated by commas. - filtered_field: The field identifier to be used for filtering. To apply multiple filters, repeat `f[${filtered_fields}]={filter_conditions}` separated by ampersands. - filter_condition: The filter condition to be used. To match multiple values, separate them with commas. - sort_field: The field identifier to be used for sorting. To apply multiple sorts, separate them with commas. The following are valid example URLs: <正しい URL の例とその説明> The following is the view metadata: -------- <view の LookML を JSON に変換したデータ>
  25. ©MIXI 28 まとめ 現状、正確な SQL を確実に⽣成させるのは難しい感触だが、以下によって精度は上げられる l プロンプトの⼯夫 l パラメータの調整

    l 質問応答例の提⽰ (few-shot prompting) l 詳細かつ構造化されたメタデータの整備 l ⽤途に応じたデータマートの整備 • 今後はセマンティックレイヤーにも注⽬ 今後 LLM のモデルアップデートやデータウェアハウス‧BI ツール側でのサポートは進みそうだが それでもメタデータなどは我々が整備する必要がある → これから⽣成 AI の活⽤の幅が更に広まった時、メタデータを含めたデータの質が鍵になる! これらのテクニックは今後のモデル発展で 変わったり不要になったりするかも 今後モデルが発展しても必要なもの ⼈間がデータを活⽤する上でも有益になる
  26. ©MIXI 参考⽂献 l ⾼橋光(2023)『SQLを活⽤したデータ分析におけるChatGPTの活⽤法』 第17回 意思決定のためのデ⼀⼣分析勉強会 https://speakerdeck.com/hikarut/sqlwohuo-yong-sitadetafen-xi-niokeruchatgptnohuo-yong-fa l @nownabe(2023)『PaLM API

    を使って⾃然⾔語で BigQuery にクエリしてみる』(アクセス⽇: 2023-07-27) https://zenn.dev/google_cloud_jp/articles/palm-api-gen-bigquery l 松元亮太(2022)『メタデータ‧マネジメント⼊⾨』⾵⾳屋TechTalk#1 https://speakerdeck.com/rytmq/20221205 l ゆずたそ 編著‧はせりょ‧株式会社⾵⾳屋(2020)『データマネジメントが30分で分かる本』 l たくまん(2023)『セマンティックレイヤー / Headless BIとは』(アクセス⽇: 2023-07-27) https://zenn.dev/churadata/articles/e779a733c5fb35 l 相樂悟(2023)『「コードでデータ分析に関わる指標を管理できる ”Semantic Layer”、dbtとLookerで何が違うの?」あなたのこの疑 問、解消します』 DevelopersIO 2023 https://speakerdeck.com/sagara/kododedetafen-xi-niguan-waruzhi-biao-woguan-li-dekiru-semantic-layer-dbttolookerdehe-gawei-uno- anatanokonoyi-wen-jie-xiao-simasu 29