はじめに
こんにちは!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ベースで直感的にグラフを扱える時代。ぜひ皆さんも、手元のデータで「繋がり」を分析する面白さを体験してみてください!