BigQueryでも話題の「仮想グラフ」をDuckDBでサクッと体験しよう

はじめに

こんにちは!FLINTERS BASEでデータエンジニアをしている梶山です。

データ界隈で大人気の「DuckDB」ですが、実はグラフクエリもサポートしていることをご存知でしょうか?

近年、オントロジーやGraphRAG、ナレッジグラフなどの文脈で「グラフデータ」が再び大きな注目を集めています。以前はNeo4jなどの専用グラフデータベースをわざわざ構築したり、普通のSQLでめちゃくちゃ頑張ってJOINしまくる必要がありましたが、最近ではGoogle CloudのBigQueryでも既存のテーブルをグラフとして扱える「BigQuery Graph(仮想グラフ機能)」がGA(一般提供)されるなど、標準SQL(SQL/PGQ)やGQLを用いて手軽にグラフ分析ができる時代が到来しています。

仮想グラフというのは簡単にいうと、データの実態は普通のリレーショナルテーブル(行と列)のまま、その上に『これはグラフですよ』という仮想的なレイヤー(ビュー)を被せるみたいな感じです。

そこで今回は、ローカル(今回はGoogle Colaboratory)環境で動作するDuckDBを使って、このトレンドである「仮想グラフ(SQL/PGQ)」の概念と基本的な使い方を体験してみましょう!

DuckDBでグラフを扱う準備

それではGoogle ColaboratoryでDuckDBの準備をしましょう。以下のコードをセルにコピペして実行していってください。
まずは、Colab上でSQLを快適に書くためのライブラリ(jupysqlとduckdb-engine)をインストールします。

# Jupyter環境でSQLを直接書けるようにするツール等をインストール
!pip install jupysql duckdb-engine

次に、SQLを実行するための「マジックコマンド(%sql)」を有効にし、ファイルを作成しないインメモリモードでDuckDBに接続します。

# SQLマジックコマンドを読み込む
%load_ext sql

# DuckDBのインメモリDBに接続する
%sql duckdb://

最後に、今回の主役であるグラフ機能拡張(DuckPGQ)をインストールしてロードします。DuckDBのグラフ機能はコミュニティ拡張として提供されているため、最初にインストールとロードが必要です。またセルの一番上に %%sql と書くことで、そのセル全体をSQLとして実行できます。

# DuckPGQのインストール
%%sql 
INSTALL duckpgq FROM community;
LOAD duckpgq;

これで、DuckDB上で仮想グラフ(SQL/PGQ)を扱う準備が整いました!

仮想グラフを作ってみる

それでは、先ほど説明した「仮想グラフ」を実際に定義してみましょう。

仮想グラフを作る手順は、大きく分けて2ステップです。まずは実体となる通常のテーブルを作成し、そのあとにグラフとしての繋がり(レイヤー)を定義します。

以下のコードを実行してみてください。

%%sql
# 頂点(ノード)と辺(エッジ)の元になるテーブルを作成
CREATE TABLE Person (id BIGINT, name VARCHAR);
CREATE TABLE Knows (person1_id BIGINT, person2_id BIGINT, since DATE);

# データの挿入
INSERT INTO Person VALUES (1, 'Alice'), (2, 'Bob'), (3, 'Charlie');
INSERT INTO Knows VALUES (1, 2, '2020-01-01'), (2, 3, '2021-06-15');

# 既存のテーブルの上に「仮想グラフ」を定義する
CREATE PROPERTY GRAPH social_network
VERTEX TABLES (
    Person
)
EDGE TABLES (
    Knows
        SOURCE KEY (person1_id) REFERENCES Person (id)
        DESTINATION KEY (person2_id) REFERENCES Person (id)
);

前半の CREATE TABLE と INSERT は、普段使っているSQLと全く同じですね。これらがグラフの元データになります。今回は、「Alice」「Bob」「Charlie」という3人のデータと、「AliceはBobを知っている」「BobはCharlieを知っている」という関係性のデータを作りました。

注目していただきたいのは、後半の CREATE PROPERTY GRAPH の部分です。ここで social_network という名前の仮想グラフを定義しています。

VERTEX TABLES (頂点): グラフの「点(ノード)」になるテーブルを指定します。今回は Person テーブルをそのままノードとして扱います。

EDGE TABLES (辺): グラフの「線(エッジ)」になるテーブルを指定します。ここでは Knows テーブルを指定し、「誰から (SOURCE KEY)」「誰へ (DESTINATION KEY)」繋がっているのかを、Person テーブルの id に紐付けて(REFERENCES)定義しています。

これだけで準備は完了です! データを新しい形式に変換したり、別のデータベースにコピーしたりすることなく、既存のテーブル資産のままグラフネットワークが構築されました。

次はいよいよ、この仮想グラフに対して、直感的なパターンマッチング(グラフクエリ)を実行してみましょう。

グラフクエリを実行してみる

仮想グラフが定義できたら、いよいよクエリを実行してネットワークを探索してみましょう。 SQL/PGQの最大の魅力は、複雑な JOIN や再帰クエリ(Recursive CTE)を書かなくても、直感的な構文で「繋がり」を抽出できることです。

パターンマッチング(基本的な繋がりを探す)

まずは「誰が誰を知っているか」という基本的な関係性を抽出してみます。ここでは GRAPH_TABLE 関数を使用します。

%%sql
FROM GRAPH_TABLE (social_network
    MATCH (a:Person)-[k:Knows]->(b:Person)
    COLUMNS (a.name AS person1, b.name AS person2, k.since)
);

MATCH 句の中に注目してください。

  • () はノード(頂点)を表します。
  • [] はエッジ(辺)を表します。
  • -> は関係の方向を表します。

つまり、(a)-[k]->(b) と書くだけで、「Person a から Person b に向かって Knows エッジが伸びているパターン」をすべて見つけ出してくれます。

パス探索(n歩先の繋がりを探す)

グラフクエリの真骨頂がこの「パス探索」です。通常のSQLで「友達の友達の友達...」を探そうとすると非常に複雑なクエリになりますが、SQL/PGQなら驚くほどシンプルに書けます。

%%sql
FROM GRAPH_TABLE (social_network
    MATCH p = ANY SHORTEST (a:Person)-[k:Knows]->{1,3}(b:Person)
    WHERE a.name = 'Alice' AND b.name = 'Charlie'
    COLUMNS (a.name AS start_person, b.name AS end_person, path_length(p) AS hops)
);

ここでは「AliceからCharlieまでの最短経路」を探しています。

  • {1,3} という量指定子を使うことで、「1〜3ホップ(階層)先まで」という可変長の探索を1行で指示しています。
  • path_length(p) を使うことで、最終的に何ホップで辿り着いたか(この例ではAlice → Bob → Charlieなので 2)を簡単に取得できます。

この機能は、SNSの「知り合いかも?」機能や、金融取引におけるマネーロンダリングの経路特定などで使われていたりします。

組み込みのグラフアルゴリズム

DuckPGQには、パターンを探索するだけでなく、ネットワーク全体の特徴を計算する「グラフアルゴリズム」も関数として組み込まれています。

%%sql
FROM pagerank(social_network, Person, Knows);

これは、Googleの検索エンジンの根幹としても知られる PageRank(ページランク) を計算するクエリです。「誰がネットワーク内で一番重要か(多くの人から知られているか)」を、この1行だけでスコア化してくれます。
このように、仮想グラフを作成すれば、使い慣れたSQLの延長線上で非常に高度なグラフ分析が可能になります!

終わりに

今回は、DuckDBの拡張機能「DuckPGQ」を使って、リレーショナルデータをそのままグラフとして扱う「仮想グラフ(SQL/PGQ)」の基本的な使い方をご紹介しました。

DuckDBは元々、ローカルで爆速動作するOLAP(分析向け)データベースです。そのため、「グラフクエリで複雑な関係性を抽出したあと、そのまま通常のSQL(GROUP BYなど)で高速に集計する」といった、リレーショナルとグラフをシームレスに行き来するような通常のデータ分析用途でも強力な威力を発揮します。

また、最近の生成AIトレンドとも非常に相性が良いです。「複雑な専用インフラを構築するまでもないけど、AIに参照させるための一時的(使い捨て)のナレッジグラフをローカルでサクッと構築・検証したい」といったユースケースにはまさにうってつけだと感じています。DuckDBにはMCP(Model Context Protocol)サーバーも用意されているので、時間があるときにAIエージェントとの連携なども試してみたいですね。

SQLベースで直感的にグラフを扱える時代。ぜひ皆さんも、手元のデータで「繋がり」を分析する面白さを体験してみてください!