INDX
Capturing Relationships with "Graph RAG" - A New Dimension of Contextual Understanding
Blog
RAG Optimization

Capturing Relationships with "Graph RAG" - A New Dimension of Contextual Understanding

Solve complex data relationships missed by traditional vector search with knowledge graphs. Learn how to extract deeper insights using Neo4j and NebulaGraph.

K
Kensuke Takatani
COO
10 min

グラフRAGで関係性を捉える〜文脈理解の新次元〜

従来のRAG(Retrieval-Augmented Generation)システムでは、ベクトル検索を用いて関連する文書を取得していました。しかし、この手法ではデータ間の複雑な関係性を十分に捉えることができませんでした。

従来のRAGの限界

ベクトル検索ベースのRAGでは以下の課題がありました:

  • 孤立した情報検索: 各文書が独立して処理され、文書間の関係が失われる
  • 文脈の断片化: 長い文書を分割する際、重要な関係性が切断される
  • 複合的な質問への対応困難: 複数のエンティティ間の関係を問う質問に対する精度の低下

グラフRAGによる解決

グラフRAGは、ナレッジグラフを活用してこれらの課題を解決します:

1. エンティティとリレーションの抽出

python
1# エンティティ抽出の例
2entities = ["Apple", "iPhone", "スマートフォン市場"]
3relations = [
4    ("Apple", "製造", "iPhone"),
5    ("iPhone", "競合", "スマートフォン市場")
6]

2. グラフデータベースの活用

Neo4jを使用したグラフ構築:

cypher
1CREATE (apple:Company {name: "Apple"})
2CREATE (iphone:Product {name: "iPhone"})
3CREATE (market:Market {name: "スマートフォン市場"})
4CREATE (apple)-[:MANUFACTURES]->(iphone)
5CREATE (iphone)-[:COMPETES_IN]->(market)

NebulaGraphでの分散処理:

ngql
1INSERT VERTEX Company(name) VALUES "Apple":("Apple");
2INSERT VERTEX Product(name) VALUES "iPhone":("iPhone");
3INSERT EDGE manufactures() VALUES "Apple"->"iPhone":();

実装アーキテクチャ

ステップ1: 文書の前処理とエンティティ抽出

typescript
1interface EntityExtraction {
2  entities: Entity[]
3  relations: Relation[]
4  confidence: number
5}
6
7async function extractEntitiesAndRelations(document: string): Promise<EntityExtraction> {
8  // LLMを使用したエンティティ・リレーション抽出
9  const extraction = await llm.extract({
10    text: document,
11    schema: entityRelationSchema
12  })
13  return extraction
14}

ステップ2: グラフの構築と更新

typescript
1class GraphRAGSystem {
2  constructor(private graphDB: Neo4jConnection) {}
3  
4  async buildKnowledgeGraph(documents: Document[]) {
5    for (const doc of documents) {
6      const extraction = await extractEntitiesAndRelations(doc.content)
7      await this.updateGraph(extraction)
8    }
9  }
10  
11  private async updateGraph(extraction: EntityExtraction) {
12    // グラフへのエンティティとリレーションの追加
13    await this.graphDB.run(
14      \`MERGE (e:Entity {name: $name, type: $type})
15       SET e.properties = $properties\`,
16      extraction.entities
17    )
18  }
19}

ステップ3: グラフベースの検索

typescript
1async function graphSearch(query: string): Promise<SearchResult[]> {
2  // 1. クエリからエンティティを抽出
3  const queryEntities = await extractEntitiesFromQuery(query)
4  
5  // 2. グラフトラバーサルで関連情報を取得
6  const cypherQuery = \`
7    MATCH (e:Entity)-[r*1..3]-(related:Entity)
8    WHERE e.name IN $entities
9    RETURN e, r, related
10  \`
11  
12  const results = await graphDB.run(cypherQuery, {
13    entities: queryEntities
14  })
15  
16  // 3. 取得したコンテキストでLLMに回答生成を依頼
17  return generateResponse(results, query)
18}

実用例:企業分析システム

企業の関係性を分析するシステムでの活用例:

typescript
1// 複雑な関係性クエリの例
2const query = "AppleとSamsungの競合関係において、特許訴訟が市場シェアに与えた影響を分析してください"
3
4// グラフRAGによる検索
5const context = await graphSearch(query)
6/*
7取得されるコンテキスト:
8- Apple ← 競合 → Samsung
9- Apple ← 特許訴訟 → Samsung  
10- Samsung → 市場シェア変動 → スマートフォン市場
11- 特許訴訟 → 影響 → 市場シェア
12*/

パフォーマンス最適化

1. インデックス戦略

cypher
1// Neo4jでの効率的なインデックス作成
2CREATE INDEX entity_name_index FOR (e:Entity) ON (e.name)
3CREATE INDEX relation_type_index FOR ()-[r:RELATES_TO]-() ON (r.type)

2. キャッシング戦略

typescript
1class CachedGraphRAG {
2  private cache = new Map<string, SearchResult[]>()
3  
4  async search(query: string): Promise<SearchResult[]> {
5    const cacheKey = this.generateCacheKey(query)
6    if (this.cache.has(cacheKey)) {
7      return this.cache.get(cacheKey)!
8    }
9    
10    const results = await this.graphSearch(query)
11    this.cache.set(cacheKey, results)
12    return results
13  }
14}

評価と改善

精度評価メトリクス

typescript
1interface EvaluationMetrics {
2  relationAccuracy: number    // 関係性抽出の精度
3  retrievalRecall: number     // 検索の再現率
4  answerRelevance: number     // 回答の関連性
5  graphCompleteness: number   // グラフの完成度
6}
7
8async function evaluateGraphRAG(testQueries: TestQuery[]): Promise<EvaluationMetrics> {
9  // 評価ロジックの実装
10}

まとめ

グラフRAGは従来のベクトル検索ベースのRAGを大幅に改善し、以下の価値を提供します:

  • 関係性の保持: エンティティ間の複雑な関係を維持
  • 文脈の豊富化: マルチホップな関係から深い洞察を獲得
  • スケーラビリティ: 大規模なナレッジベースでも効率的な検索

Neo4jやNebulaGraphといった成熟したグラフデータベースを活用することで、エンタープライズレベルのRAGシステムを構築できます。次世代の知識検索システムとして、グラフRAGの導入を検討してみてはいかがでしょうか。`,

en: `# Capturing Relationships with "Graph RAG" - A New Dimension of Contextual Understanding

Traditional RAG (Retrieval-Augmented Generation) systems have relied on vector search to retrieve relevant documents. However, this approach fails to adequately capture the complex relationships between data points.

Limitations of Traditional RAG

Vector search-based RAG systems face several challenges:

  • Isolated information retrieval: Each document is processed independently, losing inter-document relationships
  • Context fragmentation: Important relationships are severed when long documents are split
  • Difficulty with complex queries: Poor accuracy when answering questions about relationships between multiple entities

Solutions with Graph RAG

Graph RAG leverages knowledge graphs to address these challenges:

1. Entity and Relation Extraction

python
1# Example of entity extraction
2entities = ["Apple", "iPhone", "Smartphone Market"]
3relations = [
4    ("Apple", "manufactures", "iPhone"),
5    ("iPhone", "competes_in", "Smartphone Market")
6]

2. Leveraging Graph Databases

Building graphs with Neo4j:

cypher
1CREATE (apple:Company {name: "Apple"})
2CREATE (iphone:Product {name: "iPhone"})
3CREATE (market:Market {name: "Smartphone Market"})
4CREATE (apple)-[:MANUFACTURES]->(iphone)
5CREATE (iphone)-[:COMPETES_IN]->(market)

Distributed processing with NebulaGraph:

ngql
1INSERT VERTEX Company(name) VALUES "Apple":("Apple");
2INSERT VERTEX Product(name) VALUES "iPhone":("iPhone");
3INSERT EDGE manufactures() VALUES "Apple"->"iPhone":();

Implementation Architecture

Step 1: Document Preprocessing and Entity Extraction

typescript
1interface EntityExtraction {
2  entities: Entity[]
3  relations: Relation[]
4  confidence: number
5}
6
7async function extractEntitiesAndRelations(document: string): Promise<EntityExtraction> {
8  // Entity-relation extraction using LLM
9  const extraction = await llm.extract({
10    text: document,
11    schema: entityRelationSchema
12  })
13  return extraction
14}

Step 2: Graph Construction and Updates

typescript
1class GraphRAGSystem {
2  constructor(private graphDB: Neo4jConnection) {}
3  
4  async buildKnowledgeGraph(documents: Document[]) {
5    for (const doc of documents) {
6      const extraction = await extractEntitiesAndRelations(doc.content)
7      await this.updateGraph(extraction)
8    }
9  }
10  
11  private async updateGraph(extraction: EntityExtraction) {
12    // Adding entities and relations to the graph
13    await this.graphDB.run(
14      \`MERGE (e:Entity {name: $name, type: $type})
15       SET e.properties = $properties\`,
16      extraction.entities
17    )
18  }
19}

Step 3: Graph-Based Search

typescript
1async function graphSearch(query: string): Promise<SearchResult[]> {
2  // 1. Extract entities from query
3  const queryEntities = await extractEntitiesFromQuery(query)
4  
5  // 2. Retrieve related information through graph traversal
6  const cypherQuery = \`
7    MATCH (e:Entity)-[r*1..3]-(related:Entity)
8    WHERE e.name IN $entities
9    RETURN e, r, related
10  \`
11  
12  const results = await graphDB.run(cypherQuery, {
13    entities: queryEntities
14  })
15  
16  // 3. Generate response with LLM using retrieved context
17  return generateResponse(results, query)
18}

Practical Example: Corporate Analysis System

Use case in a corporate relationship analysis system:

typescript
1// Example of complex relationship query
2const query = "Analyze the impact of patent litigation on market share in the competitive relationship between Apple and Samsung"
3
4// Search using Graph RAG
5const context = await graphSearch(query)
6/*
7Retrieved context:
8- Apple ← competes_with → Samsung
9- Apple ← patent_litigation → Samsung  
10- Samsung → market_share_change → Smartphone Market
11- Patent Litigation → impacts → Market Share
12*/

Performance Optimization

1. Indexing Strategy

cypher
1// Creating efficient indexes in Neo4j
2CREATE INDEX entity_name_index FOR (e:Entity) ON (e.name)
3CREATE INDEX relation_type_index FOR ()-[r:RELATES_TO]-() ON (r.type)

2. Caching Strategy

typescript
1class CachedGraphRAG {
2  private cache = new Map<string, SearchResult[]>()
3  
4  async search(query: string): Promise<SearchResult[]> {
5    const cacheKey = this.generateCacheKey(query)
6    if (this.cache.has(cacheKey)) {
7      return this.cache.get(cacheKey)!
8    }
9    
10    const results = await this.graphSearch(query)
11    this.cache.set(cacheKey, results)
12    return results
13  }
14}

Evaluation and Improvement

Accuracy Evaluation Metrics

typescript
1interface EvaluationMetrics {
2  relationAccuracy: number    // Accuracy of relationship extraction
3  retrievalRecall: number     // Recall of search results
4  answerRelevance: number     // Relevance of answers
5  graphCompleteness: number   // Completeness of the graph
6}
7
8async function evaluateGraphRAG(testQueries: TestQuery[]): Promise<EvaluationMetrics> {
9  // Implementation of evaluation logic
10}

Conclusion

Graph RAG significantly improves upon traditional vector search-based RAG, providing the following value:

  • Relationship preservation: Maintains complex relationships between entities
  • Context enrichment: Gains deep insights from multi-hop relationships
  • Scalability: Efficient search even with large-scale knowledge bases

By leveraging mature graph databases like Neo4j and NebulaGraph, you can build enterprise-level RAG systems. Consider adopting Graph RAG as your next-generation knowledge search system.

Tags

グラフRAG
ナレッジグラフ
Neo4j
NebulaGraph
関係性抽出