Neo4jの実践: グラフが通常のDBより優れる場面
Neo4j は、データをテーブルの行ではなくノードとリレーションシップとして扱うグラフデータベースです。通常のリレーショナルDB(PostgreSQL、MySQL)はトランザクション、レポート、CRUDに非常に強い。しかしプロダクト価値がパス、連鎖、多段のつながりにあるとき、JOINや再帰CTEのSQLはすぐに重く壊れやすくなります。以下は、Neo4jが「通常の」DBに勝つ実務的な合図と、まだグラフが早い場合の整理です。
- グラフ - ノード(エンティティ)+ エッジ(型付きリレーション)+ プロパティ
- Neo4jの強み - 可変深度のリレーション走査(traversal)
- SQLの弱点 - 深いJOIN、「友達の友達」、詐欺/権限の連鎖
- 置き換えではない - トランザクションCRUD、在庫、古典的な分析
- ルール - 問いが「誰経由 / 何経由 / N hops以内」ならNeo4jを検討
グラフとテーブルの違い
PostgreSQLでは外部キーと中間テーブル(user_roles、follows、order_items)で関係をモデル化します。固定深度のクエリはまだ読めます。「関係タイプのフィルタ付きで3-5 hops以内の全ノードを探す」ようなクエリは再帰CTEか多数のJOINになり、実行計画は深度とともに膨らみます。
Neo4jではリレーションシップが first-class です。モデルは人がドメインを語る仕方に近いです:
(:Person)-[:WORKS_AT]->(:Company)(:Account)-[:TRANSFERED_TO]->(:Account)(:User)-[:HAS_ROLE]->(:Role)-[:ALLOWS]->(:Permission)
Cypher のクエリは「テーブルの糊付け」ではなくパターンを記述します。パス深度が事前に不明、または頻繁に変わるときに有利です。
Neo4jが通常のDBより優れるとき
要件に次が定期的に出るならグラフを選びます:
- 可変深度の走査 - 「友達の友達」、サプライチェーン、最終所有者までのパス。
- リレーション上のパターンマッチ - 「条件Dの下でAがC経由でBに繋がる」部分グラフの発見。
- グラフ経由の推薦・類似エンティティ - テキストだけでなく共通近傍とパス。
- 不正検知とリスク - リング、共有デバイス、「無関係」な口座間の短いパス。
- 権限と依存関係 - ロール、グループ、継承を通じたアクセス。
- ナレッジグラフ - 製品、文書、人、システムとその明示的な関係。
SQLがすでに「痛い」サイン:
- 再帰CTEがリリースごとに長くなる;
- 関係スキーマの変更をチームが恐れる;
- レイテンシが単純SELECTではなく深いJOINで伸びる;
- ビジネスが「行をidで」ではなく「連鎖を見せて」と聞く。
実践例: パスと共通近傍
人から最大2ホップでつながる企業を、関係タイプで絞り込む例です。
MATCH path = (p:Person {id: $personId})-[:WORKS_AT|KNOWS*1..2]-(c:Company)
WHERE c.country = $country
RETURN DISTINCT c.name AS company, length(path) AS hops
ORDER BY hops, company
LIMIT 50;
同じ意図をSQLで書くと、再帰・重複除去・深度制限が必要になりがちです。グラフではビジネスの問いに近い定式化になります。
推薦向けの「共通近傍」例:
MATCH (u:User {id: $userId})-[:BOUGHT]->(:Product)<-[:BOUGHT]-(other:User)
WHERE u <> other
WITH other, count(*) AS shared
ORDER BY shared DESC
LIMIT 20
RETURN other.id, shared;
通常のDBがまだ優れるとき
Neo4jはPostgreSQLの万能な置き換えではありません。
次の場合はリレーショナルDBを維持(またはそこから開始)します:
- 主フローがCRUD、注文、決済、在庫、請求である;
- 関係が固定深度(1-2 JOIN)で長年安定している;
- 重い集計、ウィンドウ関数、BI風レポートが必要;
- チームがSQLに強く、グラフレベルのクエリが稀;
- 「ネットワーク」論理が小さく、1つのCTEで十分痛くない。
典型的な失敗: 「グラフが流行っているから」製品全体をNeo4jへ移す。運用負荷が増え、トランザクション核への適合が弱くなります。
ハイブリッド: PostgreSQL + Neo4j
実務では分離がよく効きます:
| 層 | 保存先 | 目的 |
|---|---|---|
| 注文、ユーザー、決済 | PostgreSQL / MySQL | トランザクション、整合性、レポート |
| 関係、パス、ロール、依存 | Neo4j | Traversal と pattern match |
| 意味検索 | ベクトルストア | RAG / semantic search |
お金とステータスの正本はリレーショナルDBです。グラフはイベント(outbox、CDC、キュー)やバッチで同期します。こうすると請求をNeo4jに二重化せず、JOINだけで不正グラフを組まずに済みます。
1-2週間で仮説を検証する
- ユーザー/アナリストの実際の問いを15-20個書く。
- パス、hops、「誰経由」が何割かを印付けする。
- その割合が約30-40%超なら、縮小サブグラフでNeo4jパイロットを組む。
- SQLと比較: 可読性、p95レイテンシ、スキーマ変更コスト。
- 主DBとの同期コストを見積もる。
パイロットがレイテンシ/明瞭さで勝てないならPostgreSQLに留まります。グラフは痛みを解くものであり、アーキテクチャの飾りではありません。
まとめ
Neo4jは、プロダクトが関係で考える場所で通常のDBに勝ちます: 連鎖、ロール、依存、不正検知、ナレッジグラフ、グラフ推薦。通常のDBは、核がトランザクション・固定JOIN・レポートの場所で勝ちます。 多くはハイブリッドが最適: 事実とお金はSQL、構造とパスはグラフ。
関係をNeo4jに切り出すべきか判断したい、またはドメイン向けパイロットを設計したい場合はご連絡ください。
よくある質問
関係についてNeo4jはPostgreSQLより本質的に何が優れるか?
可変深度トラバーサルの速度と明瞭さです。 グラフではエッジがリレーションとして索引付けされ、毎回テーブルJOINで組み立てません。固定1-2 JOINならPostgreSQLで十分なことが多いです。「関係タイプのフィルタ付きN hops」ではNeo4jの方が簡単で安定しがちです。
PostgreSQLの再帰CTEでNeo4jを置き換えられるか?
最初は可能なこともあります。 深度が小さく、グラフが中規模で、クエリが少なければCTEは機能します。深度・分岐・パターンクエリが増えると、CTEは保守が難しく実行計画も高くなります。
製品全体をNeo4jに移す必要があるか?
いいえ。 関係がプロダクト価値になる層だけ移します。注文、決済、在庫、古典的CRUDはリレーショナルDBに残します。そうしないと適合が弱く運用が複雑になります。
CypherはSQLより難しいか?
別の思考モデルであり、必ずしも難しくはありません。 パスとパターンではCypherの方が短く読みやすいです。集計、レポート、ウィンドウ関数ではSQLの方が馴染み深いです。チームには短いオンボーディングとドメインの参照クエリ5-10本が必要です。
既存プロジェクトでNeo4j導入をどう始めるか?
シナリオ1つのパイロットから: 例として権限グラフ、詐欺リング、サービス依存マップ。正本、同期方法、制御用の問い10個を決めます。レイテンシとhit-rateを測ってから他ドメインへの拡大を判断します。