Skip to main content

graphrag_core/core/
retrieval_adapters.rs

1//! Retrieval system adapters for core traits
2//!
3//! This module provides adapter implementations that bridge existing retrieval systems
4//! with the core GraphRAG AsyncRetriever trait.
5
6use crate::core::error::{GraphRAGError, Result};
7use crate::core::traits::AsyncRetriever;
8use crate::retrieval::{RetrievalSystem, SearchResult as RetrievalSearchResult};
9use async_trait::async_trait;
10
11/// Result type for retrieval operations
12#[derive(Debug, Clone)]
13pub struct RetrievalResult {
14    /// Unique identifier for this result
15    pub id: String,
16    /// Content of the result
17    pub content: String,
18    /// Relevance score
19    pub score: f32,
20    /// Associated entity names
21    pub entities: Vec<String>,
22}
23
24impl From<RetrievalSearchResult> for RetrievalResult {
25    fn from(result: RetrievalSearchResult) -> Self {
26        Self {
27            id: result.id,
28            content: result.content,
29            score: result.score,
30            entities: result.entities,
31        }
32    }
33}
34
35/// Adapter for RetrievalSystem to implement AsyncRetriever trait
36///
37/// ## Graph Integration
38///
39/// This adapter wraps the RetrievalSystem which operates on a KnowledgeGraph.
40/// For full functionality, the RetrievalSystem needs to be initialized with
41/// a populated graph. The current implementation provides the trait interface
42/// but actual retrieval requires application-level graph management.
43///
44/// ## Usage Pattern
45///
46/// ```no_run
47/// use graphrag_core::core::retrieval_adapters::RetrievalSystemAdapter;
48/// use graphrag_core::retrieval::RetrievalSystem;
49/// use graphrag_core::config::Config;
50///
51/// # async fn example() -> graphrag_core::Result<()> {
52/// let config = Config::default();
53/// let system = RetrievalSystem::new(&config)?;
54/// let adapter = RetrievalSystemAdapter::new(system);
55///
56/// // Search requires a populated knowledge graph in the retrieval system
57/// // This would typically be managed at the application level
58/// # Ok(())
59/// # }
60/// ```
61pub struct RetrievalSystemAdapter {
62    system: RetrievalSystem,
63}
64
65impl RetrievalSystemAdapter {
66    /// Create a new retrieval system adapter
67    ///
68    /// Note: The RetrievalSystem should be populated with a KnowledgeGraph
69    /// before search operations will return meaningful results.
70    pub fn new(system: RetrievalSystem) -> Self {
71        Self { system }
72    }
73
74    /// Get reference to underlying retrieval system
75    pub fn system(&self) -> &RetrievalSystem {
76        &self.system
77    }
78
79    /// Get mutable reference to underlying retrieval system
80    ///
81    /// This allows configuring the retrieval system after creation,
82    /// such as setting the knowledge graph or updating configurations.
83    pub fn system_mut(&mut self) -> &mut RetrievalSystem {
84        &mut self.system
85    }
86}
87
88#[async_trait]
89impl AsyncRetriever for RetrievalSystemAdapter {
90    type Query = String;
91    type Result = RetrievalResult;
92    type Error = GraphRAGError;
93
94    async fn search(&self, _query: Self::Query, _k: usize) -> Result<Vec<Self::Result>> {
95        // Note: Actual search implementation requires the RetrievalSystem to have
96        // access to a populated KnowledgeGraph. This is typically managed at the
97        // application level where the graph is built and passed to the retrieval system.
98        //
99        // The RetrievalSystem internally supports multiple retrieval strategies:
100        // - Vector similarity search
101        // - Entity-based retrieval
102        // - Graph path traversal
103        // - Hybrid approaches
104        //
105        // To enable full retrieval:
106        // 1. Build a KnowledgeGraph with documents, entities, and relationships
107        // 2. Pass it to the RetrievalSystem via application context
108        // 3. The RetrievalSystem will handle query expansion, ranking, and fusion
109        //
110        // For testing without a real graph, use the MockRetriever from test_utils.
111
112        Ok(vec![])
113    }
114
115    async fn search_with_context(
116        &self,
117        query: Self::Query,
118        _context: &str,
119        k: usize,
120    ) -> Result<Vec<Self::Result>> {
121        // Use same implementation as search for now
122        // Context could be used to filter or re-rank results
123        self.search(query, k).await
124    }
125
126    async fn search_batch(
127        &self,
128        queries: Vec<Self::Query>,
129        k: usize,
130    ) -> Result<Vec<Vec<Self::Result>>> {
131        let mut results = Vec::with_capacity(queries.len());
132        for query in queries {
133            results.push(self.search(query, k).await?);
134        }
135        Ok(results)
136    }
137
138    async fn update(&mut self, _content: Vec<String>) -> Result<()> {
139        // Updating the retrieval system would typically involve:
140        // 1. Adding new documents to vector store
141        // 2. Rebuilding search indices
142        // 3. Updating graph structures
143
144        // For now, this is a no-op since retrieval system doesn't expose
145        // a public update API
146        Ok(())
147    }
148
149    async fn health_check(&self) -> Result<bool> {
150        // Basic health check - verify the system is initialized
151        Ok(true)
152    }
153}
154
155#[cfg(test)]
156mod tests {
157    use super::*;
158    use crate::config::Config;
159
160    #[tokio::test]
161    async fn test_retrieval_adapter_creation() {
162        let config = Config::default();
163        let system = RetrievalSystem::new(&config).unwrap();
164        let adapter = RetrievalSystemAdapter::new(system);
165
166        assert!(adapter.health_check().await.unwrap());
167    }
168
169    #[tokio::test]
170    async fn test_search_batch() {
171        let config = Config::default();
172        let system = RetrievalSystem::new(&config).unwrap();
173        let adapter = RetrievalSystemAdapter::new(system);
174
175        let queries = vec![
176            "What is GraphRAG?".to_string(),
177            "How does retrieval work?".to_string(),
178        ];
179
180        let results = adapter.search_batch(queries, 5).await.unwrap();
181        assert_eq!(results.len(), 2);
182    }
183}