第 3 章: 知識グラフを育てる
CRUD 操作でデータを自在に操る
知識グラフは一度作ったら終わりではありません。ビジネスの変化に合わせてデータを追加、更新、削除していくことで、その価値は高まり続けます。この章では、データの基本的な操作である CRUD(Create, Read, Update, Delete)を Cypher で実行する方法を学びます。
3.1 CREATE: 新しいノードとリレーションシップの作成
ビジネスシナリオ
新規クライアントとして「D 社」との契約が成立しました。また、新入社員の「山田」さんが入社し、新規プロジェクト「ブロックチェーン導入支援」のテクニカルリードに任命されました。
CREATE 句は、新しいノードやリレーションシップをグラフに追加するために使用します。個別に作成することも、MATCH 句と組み合わせて既存のノード間に新しい関係性を築くことも可能です。
基本的なノード作成
// 新しい会社、従業員、プロジェクトのノードをそれぞれ作成
CREATE (c:Company {name: "D社", industry: "フィンテック", founded: 2018})
CREATE (e:Employee {name: "山田", title: "テクニカルリード", experience: 6})
CREATE (p:Project {name: "ブロックチェーン導入支援", status: "計画中", budget: 12000000})
既存ノードとの関係性作成
// 山田さんがD社に勤務するという関係を作成
MATCH (e:Employee {name: "山田"}), (c:Company {name: "D社"})
CREATE (e)-[:WORKS_FOR {since: 2025, position: "シニア"}]->(c)
// 山田さんがブロックチェーンプロジェクトを主導するという関係を作成
MATCH (e:Employee {name: "山田"}), (p:Project {name: "ブロックチェーン導入支援"})
CREATE (e)-[:LEADS {responsibility: "技術設計"}]->(p)
CREATE (e)-[:PARTICIPATES_IN {role: "テクニカルリード"}]->(p)
MERGE: 重複を防ぐスマートな作成
CREATE 句は常に新しい要素を作成しますが、誤ってスクリプトを複数回実行すると、同じデータが重複して作成されてしまいます。これを避けるために MERGE 句 がよく使われます。
// スキルが存在しなければ作成し、存在すれば何もしない
MERGE (s:Skill {name: "ブロックチェーン"})
ON CREATE SET s.category = "新技術", s.demand = "高"
ON MATCH SET s.lastUpdated = datetime()
// 山田さんがブロックチェーンスキルを持つという関係をMERGEで作成
MATCH (e:Employee {name: "山田"})
MERGE (s:Skill {name: "ブロックチェーン"})
MERGE (e)-[:HAS_SKILL {level: "上級"}]->(s)
3.2 MATCH & WHERE: データの検索とフィルタリング
ビジネスシナリオ
社内にいる全ての「エンジニア」をリストアップしたい。また、「AI 関連スキル」(Python または機械学習)を持つ従業員を特定したい。
MATCH はグラフから特定のパターンを見つけ出すための句です。WHERE 句を組み合わせることで、ノードやリレーションシップのプロパティに基づいて結果をフィルタリングできます。
基本的な検索とフィルタリング
// 全てのエンジニアを検索
MATCH (e:Employee)
WHERE e.title CONTAINS 'エンジニア'
RETURN e.name, e.title, e.experience
ORDER BY e.experience DESC
複数条件での検索
// AI関連スキルを持つ従業員を検索
MATCH (e:Employee)-[:HAS_SKILL]->(s:Skill)
WHERE s.name IN ['Python', '機械学習', 'データ分析']
RETURN e.name, collect(s.name) AS aiSkills
範囲検索と複合条件
// 経験5年以上で、進行中のプロジェクトに参加している従業員
MATCH (e:Employee)-[:PARTICIPATES_IN]->(p:Project)
WHERE e.experience >= 5 AND p.status = '進行中'
RETURN e.name, e.experience, p.name, p.status
パフォーマンス最適化のヒント
クエリのパフォーマンスを考える上で重要なのは、検索の開始点をできるだけ絞り込むことです:
// ❌ 非効率: 全ノードから検索
MATCH (n)
WHERE n:Employee AND n.title = 'エンジニア'
RETURN n.name
// ✅ 効率的: 最初からEmployeeラベルを指定
MATCH (e:Employee)
WHERE e.title = 'エンジニア'
RETURN e.name
3.3 SET & REMOVE: プロパティ(属性)の更新と削除
ビジネスシナリオ
「鈴木」さんが「シニアエンジニア」に昇進しました。また、「DX 戦略策定」プロジェクトが完了したため、ステータスを更新し、一時的に使用していた内部用の追跡情報を削除します。
SET 句は、既存のノードやリレーションシップに新しいプロパティを追加したり、既存のプロパティ値を更新したりするために使用します。一方、REMOVE 句はプロパティやラベルを削除するために使用します。
プロパティの更新
// 鈴木さんの役職を更新
MATCH (e:Employee {name: "鈴木"})
SET e.title = "シニアエンジニア",
e.promotionDate = date(),
e.salary = e.salary * 1.15 // 15%昇給
RETURN e.name, e.title, e.promotionDate
複数プロパティの一括更新
// プロジェクトのステータスと関連情報を更新
MATCH (p:Project {name: "DX戦略策定"})
SET p.status = "完了",
p.completedDate = date(),
p.actualBudget = 2800000,
p.successMetrics = ["ROI: 250%", "効率化: 30%", "満足度: 95%"]
RETURN p.name, p.status, p.completedDate
プロパティとラベルの削除
// 完了したプロジェクトから一時的な追跡情報を削除
MATCH (p:Project {name: "DX戦略策定"})
REMOVE p.internalTrackingId, p.tempNotes
// 完了プロジェクト用のラベルを追加
SET p:CompletedProject
RETURN p.name, labels(p) AS projectLabels
条件付き更新
// 経験年数に応じて従業員のレベルを自動設定
MATCH (e:Employee)
SET e.level =
CASE
WHEN e.experience >= 10 THEN "シニア"
WHEN e.experience >= 5 THEN "ミドル"
ELSE "ジュニア"
END
RETURN e.name, e.experience, e.level
3.4 DELETE & DETACH DELETE: ノードとリレーションシップの削除
ビジネスシナリオ
完了した「DX 戦略策定」プロジェクトのノードは、アクティブな分析対象から外すため、関連するリレーションシップと共にデータベースから削除します。
DELETE 句はノードやリレーションシップを削除しますが、ここで極めて重要なルールがあります。それは、「リレーションシップが接続されたままのノードは削除できない」という点です。これは、グラフの整合性を保ち、意図しないデータの分断を防ぐための重要な設計思想です。
リレーションシップの個別削除
// 特定のプロジェクト参加関係を削除
MATCH (e:Employee {name: "佐藤"})-[r:PARTICIPATES_IN]->(p:Project {name: "DX戦略策定"})
DELETE r
RETURN "プロジェクト参加関係を削除しました" AS message
DETACH DELETE: ノードと関連リレーションシップの一括削除
// プロジェクトノードと、それに接続する全てのリレーションシップを一度に削除
MATCH (p:Project {name: "DX戦略策定"})
DETACH DELETE p
RETURN "プロジェクトと関連する全ての関係を削除しました" AS message
条件付き削除
// 完了から1年以上経過したプロジェクトをアーカイブ(削除)
MATCH (p:Project)
WHERE p.status = "完了"
AND p.completedDate < date() - duration({years: 1})
DETACH DELETE p
RETURN "古い完了プロジェクトをアーカイブしました" AS message
削除前の確認クエリ
削除を実行する前に、影響範囲を確認することは重要です:
// 削除対象のプロジェクトと関連する従業員を事前確認
MATCH (p:Project {name: "DX戦略策定"})<-[:PARTICIPATES_IN]-(e:Employee)
RETURN p.name AS project, collect(e.name) AS affectedEmployees
3.5 CRUD 操作のベストプラクティス
1. データ整合性の確保
// MERGEを使用して重複を防ぐ
MERGE (e:Employee {email: "yamada@example.com"})
ON CREATE SET e.name = "山田", e.createdDate = datetime()
ON MATCH SET e.lastLoginDate = datetime()
2. トランザクションの活用
// 複数の関連操作をトランザクションで囲む
BEGIN
MATCH (e:Employee {name: "山田"})
SET e.title = "シニアエンジニア"
WITH e
MATCH (p:Project {name: "新規プロジェクト"})
CREATE (e)-[:LEADS]->(p)
COMMIT
3. 適切なインデックスの使用
// よく検索されるプロパティにインデックスを作成
CREATE INDEX FOR (e:Employee) ON (e.email)
CREATE INDEX FOR (p:Project) ON (p.status)
操作別の安全ガイドライン
操作 | 構文例 | 注意点 | ベストプラクティス |
---|---|---|---|
CREATE | CREATE (n:Label {prop: 'value'}) | 重複作成の可能性 | MERGE の使用を検討 |
MATCH | MATCH (n:Label) WHERE n.prop = 'value' | パフォーマンス | インデックスの活用 |
SET | SET n.prop = 'newValue' | 既存データの上書き | 更新前の値を確認 |
REMOVE | REMOVE n.prop | データの永続的な削除 | 削除前のバックアップ |
DELETE | DELETE n | 関連データへの影響 | DETACH DELETE の使用 |
MERGE | MERGE (n:Label {prop: 'value'}) | パフォーマンス | 適切な ON CREATE/MATCH 句 |
MATCH 句と CREATE/MERGE 句を組み合わせることは、単にデータを作成するだけでなく、既存のグラフに新しい知識を「織り込む」行為、すなわち「グラフのエンリッチメント(豊かにすること)」の基本単位です。これは、既知のアンカーポイントを見つけ出し、それらの間に新しい事実(リレーションシップ)を表明するプロセスであり、知識グラフが時間とともに価値を増していく核心的なメカニズムと言えます。
前へ: 第 2 章: Cypher の世界へようこそ | 次へ: 第 4 章: パターンを使いこなす
関連記事
著者: hnish