
Snowflake Cortex Analystを試してみた
※ この記事はnote株式会社 Advent Calendar 2024の5日目の記事です。
noteでデータエンジニアのリーダーをやっています。久保田です。
LLMが色々な業務を効率化しているこの昨今、データ活用周りでもたくさんのサービスが生まれています。
その中でもやはり注目は、「SQLを書かずに、自然言語でデータの分析」という分野ではないでしょうか。
データ活用の重要性が叫ばれ、各企業が自身のサービスのデータを収集し活用していっていると思います。
しかし、データ活用は簡単なものではないです。データを活用するためにはそのデータへの知識が必要となります。
例えばnoteであれば
とあるクリエイターの記事のPVを集計して、タイトル別に出したい
とします。
これを素のテーブルを使って集計しようとすると、以下の操作が必要になります
以下のテーブルを結合
閲覧履歴が入っているテーブル
note記事テーブル
クリエイターの情報が入っているテーブル
note記事データのタイトルカラムをgroup by
select文を書き、countする
閲覧履歴のテーブルはそのままだと重いので、ログの発生時刻のカラムをwhere句で絞りこむ
知っていれば簡単ですが、知らないとまずどこのテーブルを使えばいいのか?どのテーブルを結合すればいいのか?というところからスタートします。
やりたいことは非常に単純なのに、解決方法が複雑に感じます。
そのためにデータカタログを整えるわけですが、データカタログにある数百のテーブルから目的のテーブルを探すのも時間がかかります。
テーブルによってはカラムがとても多いかもしれませんし、そこから探すだけでもかなり労力がかかります。
目的のテーブル・カラムを見つけたいだけならそれで何とかなるかもしれませんが、集計となると、今後はSQLの知識が必要なります。
上記の例ならば単純なcount(1)ですが、そうでなかった場合、SQLの知識の有無で結果が変わってきてしまう可能性があります。
例えば、ユニークユーザー数でcountをしたいとした時、count(distinct user_id)としなければなりません。
そういった知識による差を埋めるため、データマートを整えてあらかじめ集計して提供するわけですが、そうすると今後はデータマートにあるデータしか見れません。新しいデータを見たいとなると、データエンジニアに依頼して、というフローになります。スピード感が落ちてしまうので、あまり嬉しくはないですね。
なので結局、データに詳しいアナリストに相談して工数がかかってしまったり、最悪の場合は諦めてしまったりする、ということになってしまいます。
そこで今回は、Snowflakeから提供されているCortex Analystを検証してみたいと思います。
Cortex Analystは
Snowflake内のテーブルデータに対して自然言語で問い合わせを行う仕組みを簡単に構築
できるものです。
早速試してみます。
目的としては、「とあるクリエイターの記事のPVを集計して、タイトル別に出したい」という要望に柔軟に叶えられる仕組みを構築します。
cortex analystのざっくりとした仕組みは以下のようになっています。

なので、まずはセマンティックモデルを作成し、アップロードする必要があります。
テーブルは今回のテスト用に以下のようなものを作成しました。
create database cortex_analyst_sample;
create or replace table article_pv_logs (
id integer,
article_id integer,
user_id integer,
created_at datetime
);
insert into article_pv_logs values
(1,1,1,'2024-12-01 00:00:00'),
(2,1,2,'2024-12-01 00:10:00'),
(3,1,3,'2024-12-01 00:12:00'),
(4,1,4,'2024-12-02 01:00:00'),
(5,1,5,'2024-12-02 04:00:00'),
(6,2,1,'2024-12-04 00:00:00'),
(7,2,2,'2024-12-02 00:00:00'),
(8,2,3,'2024-12-03 00:00:00'),
(9,2,6,'2024-12-02 07:00:00');
(10,3,6,'2024-12-02 07:00:00');
create or replace table articles (
id integer,
user_id integer,
title string,
created_at datetime
);
insert into articles values
(1, 1, 'title_A', '2024-12-01 00:00:00'),
(2, 2, 'title_B', '2024-12-02 00:00:00');
(3, 1, 'title_A2', '2024-12-02 00:00:00');
create table users (
id integer,
name string,
created_at datetime
);
insert into users values
(1, 'user_A', '2024-12-01 00:00:00'),
(2, 'user_B', '2024-12-01 00:00:00'),
(3, 'user_C', '2024-12-01 00:00:00'),
(4, 'user_D', '2024-12-02 00:00:00'),
(5, 'user_E', '2024-12-02 00:00:00'),
(6, 'user_F', '2024-12-02 00:00:00');
セマンティックモデルは以下のようにしてみました。
name: sample
tables:
- name: ARTICLES
description: 記事データが保存されているテーブル
base_table:
database: CORTEX_ANALYST_SAMPLE
schema: PUBLIC
table: ARTICLES
primary_key:
columns:
- id
dimensions:
- name: TITLE
synonyms:
- 記事タイトル
- 記事名
- title
- タイトル
description: 記事のタイトル
expr: TITLE
data_type: TEXT
sample_values:
- title_A
- title_B
- name: ID
synonyms:
- ''
description: 記事ごとにユニークに割り振られるユニークID
expr: ID
data_type: NUMBER
sample_values:
- '1'
- '2'
- name: USER_ID
synonyms:
- 記事を作ったユーザーID
- ユーザーID
description: 記事を作ったユーザーのID
expr: USER_ID
data_type: NUMBER
sample_values:
- '1'
- '2'
time_dimensions:
- name: CREATED_AT
synonyms:
- 記事の作成時刻
- 記事の作成日時
description: 記事が作成された時間
expr: CREATED_AT
data_type: TIMESTAMP_NTZ
sample_values:
- '2024-12-01 00:00:00'
- '2024-12-02 00:00:00'
- name: ARTICLE_PV_LOGS
description: ユーザーの記事の閲覧履歴が入っているテーブル
base_table:
database: CORTEX_ANALYST_SAMPLE
schema: PUBLIC
table: ARTICLE_PV_LOGS
primary_key:
columns:
- id
dimensions:
- name: ID
synonyms:
- ログID
description: ログの発生のたびに割り振られるユニークID
expr: ARTICLE_ID
data_type: NUMBER
sample_values:
- '1'
- '2'
- name: ARTICLE_ID
synonyms:
- 記事ID
description: ユーザーが閲覧した記事のIDが入っている
expr: ARTICLE_ID
data_type: NUMBER
sample_values:
- '1'
- '2'
- name: USER_ID
synonyms:
- ユーザーID
description: 記事を閲覧したユーザーのIDが入っている
expr: USER_ID
data_type: NUMBER
sample_values:
- '1'
- '2'
- '3'
time_dimensions:
- name: CREATED_AT
synonyms:
- 閲覧時刻
- 閲覧日時
description: ユーザーが記事を閲覧した日時
expr: CREATED_AT
data_type: TIMESTAMP_NTZ
sample_values:
- '2024-12-01 00:00:00'
- '2024-12-01 00:10:00'
- '2024-12-01 00:12:00'
- name: USERS
description: ユーザーの情報が入っているテーブル
base_table:
database: CORTEX_ANALYST_SAMPLE
schema: PUBLIC
table: USERS
primary_key:
columns:
- id
dimensions:
- name: NAME
synonyms:
- ユーザー名
description: ユーザーが自身で設定したユーザー名
expr: NAME
data_type: TEXT
sample_values:
- user_A
- user_B
- user_C
- name: ID
synonyms:
- ユーザーID
description: ユーザーごとに割り振られるユニークなID
expr: ID
data_type: NUMBER
sample_values:
- '1'
- '2'
- '3'
time_dimensions:
- name: CREATED_AT
synonyms:
- ユーザーの登録日時
description: ユーザーが登録した日時が入っている
expr: CREATED_AT
data_type: TIMESTAMP_NTZ
sample_values:
- '2024-12-01 00:00:00'
- '2024-12-02 00:00:00'
relationships:
- name: ARTICLE_PV_LOGS_to_ARTICLES
left_table: ARTICLE_PV_LOGS
right_table: ARTICLES
join_type: inner
relationship_type: many_to_one
relationship_columns:
- left_column: article_id
right_column: id
- name: ARTICLE_PV_LOGS_to_USERS
left_table: ARTICLE_PV_LOGS
right_table: USERS
join_type: left_outer
relationship_type: many_to_one
relationship_columns:
- left_column: user_id
right_column: id
- name: ARTICLES_to_USERS
left_table: ARTICLES
right_table: USERS
join_type: left_outer
relationship_type: many_to_one
relationship_columns:
- left_column: user_id
right_column: id
ポイントはrelationshipsの部分で、最近joinができるようになりました。
では実行してみます。
https://github.com/Snowflake-Labs/semantic-model-generator
こちらで公開されているデモアプリ経由で試してみます。

質問を入力して実行すると、SQLが実行され、結果が表示されました。

少し条件を加えて、2024年12月2日以降のPVのみを条件に指定してみます。

いい感じですね。
最後に、セマンティックモデルに記載していない、つまり知らないことを聞いてみます。

ちゃんとわからないと答えてくれましたね。
非常に簡単な内容ではありましたが、cortex analystでデータ活用の課題を解決する可能性が見えたかな、と思います。
所感としては、やはりセマンティックモデルをどれくらい整えられるか、が非常に重要かなと感じました。(一度relationshipsのところを間違えていて、集計結果がずれてしまっていた)
なので、全てのモデルに対して、ではなく、しっかりとデータを整えた上で必要なモデルの必要なカラムを提供する、というのがいいのではないか、と感じています。
今までのようにデータ基盤を作ってはいどうぞ、ではなく、データ活用をしやすいようにセマンティックレイヤーを整える、ということもデータエンジニアの役割になってくるのではないでしょうか。
取り急ぎnoteでは早く社内で使えるようにしていきたいと思います。
ありがとうございました。
▼noteエンジニアアドベントカレンダーはこちら
https://qiita.com/advent-calendar/2024/note
▼さらにnoteの技術記事が読みたい方はこちら