Memory Retrieval Guide
This guide covers effective strategies for searching and retrieving memories using the Papr Memory API. Learn how to write effective queries, handle search results, and optimize retrieval performance.
Search Capabilities
The Papr Memory API provides powerful semantic search capabilities:
- Natural Language Queries: Write detailed, descriptive queries
- Metadata Filtering: Use metadata for better targeting
- Context-Aware Search: Include conversation and emotional context
- Result Ranking: Automatic relevance-based ranking
Writing Effective Queries
The search API works best with detailed, contextual queries:
const searchMemories = async (query: string) => {
const response = await fetch('https://memory.papr.ai/v1/memory/search', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': '<your-api-key>',
'X-Client-Type': 'your_app_name',
'Accept-Encoding': 'gzip'
},
body: JSON.stringify({
query,
rank_results: false // Results are already semantically ranked
})
});
return response.json();
};
// Good query examples
const queries = [
"Find detailed discussions about API performance issues from the last month, focusing on timeout errors and customer impact",
"Locate product feedback about the new dashboard features, particularly comments about usability and suggested improvements",
"Retrieve meeting notes from recent planning sessions that discuss Q2 objectives and resource allocation"
];
Search Patterns
1. Topic-Based Search
async function searchByTopic(
topic: string,
subtopics: string[] = [],
timeframe?: string
) {
let query = `Find comprehensive information about ${topic}`;
if (subtopics.length > 0) {
query += ` specifically relating to ${subtopics.join(', ')}`;
}
if (timeframe) {
query += ` from ${timeframe}`;
}
return searchMemories(query);
}
// Example usage
const results = await searchByTopic(
'user authentication',
['password reset', 'two-factor authentication'],
'the past quarter'
);
2. Context-Based Search
async function searchWithContext(
topic: string,
context: {
project?: string,
team?: string,
status?: string,
priority?: string
}
) {
let query = `Find information about ${topic}`;
if (context.project) {
query += ` within the ${context.project} project`;
}
if (context.team) {
query += ` involving the ${context.team} team`;
}
if (context.status) {
query += ` with ${context.status} status`;
}
if (context.priority) {
query += ` marked as ${context.priority} priority`;
}
return searchMemories(query);
}
// Example usage
const results = await searchWithContext('implementation timeline', {
project: 'Dashboard Redesign',
team: 'Frontend',
status: 'in-progress',
priority: 'high'
});
3. Emotional Context Search
async function searchByEmotion(
topic: string,
emotion: string,
intensity?: 'high' | 'moderate' | 'low'
) {
let query = `Find ${topic} discussions`;
if (intensity) {
query += ` with ${intensity} levels of ${emotion} sentiment`;
} else {
query += ` expressing ${emotion}`;
}
return searchMemories(query);
}
// Example usage
const results = await searchByEmotion(
'product feedback',
'frustration',
'high'
);
Processing Search Results
Handle and organize search results effectively:
interface SearchResult {
memories: Memory[];
nodes: Node[];
}
class MemoryProcessor {
// Group results by hierarchy
static groupByHierarchy(results: SearchResult) {
return results.memories.reduce((acc, memory) => {
const hierarchy = memory.metadata?.hierarchical_structures || 'Uncategorized';
acc[hierarchy] = acc[hierarchy] || [];
acc[hierarchy].push(memory);
return acc;
}, {});
}
// Sort results by relevance and date
static sortResults(memories: Memory[]) {
return memories.sort((a, b) => {
const dateA = new Date(a.metadata?.createdAt || 0);
const dateB = new Date(b.metadata?.createdAt || 0);
return dateB.getTime() - dateA.getTime();
});
}
// Extract key insights
static extractInsights(memories: Memory[]) {
return memories.map(memory => ({
id: memory.id,
content: memory.content,
topics: memory.metadata?.topics?.split(',').map(t => t.trim()) || [],
emotions: memory.metadata?.["emotion tags"]?.split(',').map(e => e.trim()) || [],
created: new Date(memory.metadata?.createdAt)
}));
}
}
// Example usage
const response = await searchMemories('feature feedback');
const grouped = MemoryProcessor.groupByHierarchy(response);
const sorted = MemoryProcessor.sortResults(response.memories);
const insights = MemoryProcessor.extractInsights(response.memories);
Search Optimization
1. Query Building
class QueryBuilder {
private query: string[];
private filters: string[];
constructor(baseQuery: string) {
this.query = [baseQuery];
this.filters = [];
}
addTimeframe(timeframe: string) {
this.filters.push(`from ${timeframe}`);
return this;
}
addContext(context: string) {
this.filters.push(`in the context of ${context}`);
return this;
}
addFocus(focus: string) {
this.filters.push(`focusing on ${focus}`);
return this;
}
build() {
return [...this.query, ...this.filters].join(' ');
}
}
// Example usage
const builder = new QueryBuilder('Find discussions about API performance')
.addTimeframe('the last month')
.addContext('customer support tickets')
.addFocus('response time issues');
const query = builder.build();
const results = await searchMemories(query);
2. Result Caching
class MemoryCache {
private cache: Map<string, {
results: SearchResult,
timestamp: number
}>;
private ttl: number; // Time to live in milliseconds
constructor(ttlMinutes: number = 5) {
this.cache = new Map();
this.ttl = ttlMinutes * 60 * 1000;
}
async get(query: string): Promise<SearchResult | null> {
const cached = this.cache.get(query);
if (!cached) return null;
if (Date.now() - cached.timestamp > this.ttl) {
this.cache.delete(query);
return null;
}
return cached.results;
}
set(query: string, results: SearchResult) {
this.cache.set(query, {
results,
timestamp: Date.now()
});
}
clear() {
this.cache.clear();
}
}
// Example usage
const cache = new MemoryCache(10); // 10 minutes TTL
async function cachedSearch(query: string): Promise<SearchResult> {
const cached = await cache.get(query);
if (cached) return cached;
const results = await searchMemories(query);
cache.set(query, results);
return results;
}
Best Practices
Query Writing
- Be specific and detailed in your queries
- Include relevant context and timeframes
- Use natural language descriptions
Result Handling
- Process results based on your needs
- Implement appropriate sorting/filtering
- Cache frequently accessed results
Performance
- Use the
Accept-Encoding: gzip
header - Implement client-side caching
- Batch related searches when possible
- Use the
Error Handling
- Implement retry logic for failed searches
- Handle rate limits appropriately
- Provide fallback options when needed
Next Steps
- Explore our API Reference for detailed endpoint information
- Check out our Context Handling Guide for more context management strategies
- View our Memory Management Guide for memory organization tips