Spaces:
Running
Running
// ===== KIMI MEMORY DATABASE OPTIMIZATION SUGGESTIONS ===== | |
/** | |
* Performance Optimization Guide for Kimi Memory System | |
* | |
* This file contains recommendations for database schema optimizations | |
* to improve query performance in the memory system. | |
*/ | |
// RECOMMENDED DEXIE INDEX CONFIGURATION | |
// Add these indexes to your database schema for optimal performance | |
const RECOMMENDED_MEMORY_INDEXES = { | |
// Current schema (for reference) | |
current: "++id, character, category, type, timestamp, isActive, confidence, importance, keywords", | |
// OPTIMIZED schema with composite indexes | |
optimized: [ | |
"++id", // Primary key (auto-increment) | |
// Single field indexes (existing) | |
"character", | |
"category", | |
"type", | |
"timestamp", | |
"isActive", | |
"confidence", | |
"importance", | |
"*keywords", // Multi-entry index for keyword array | |
// COMPOSITE INDEXES for frequent query patterns | |
"[character+isActive]", // Filter by character and active status | |
"[character+category]", // Get memories by character and category | |
"[character+category+isActive]", // Most common query pattern | |
"[character+timestamp]", // Chronological queries by character | |
"[isActive+importance]", // Get active memories by importance | |
"[isActive+timestamp]", // Recent active memories | |
"[character+type+isActive]", // Filter by character, type, and status | |
// Advanced composite indexes for complex queries | |
"[character+isActive+importance]", // Prioritized active memories by character | |
"[character+category+timestamp]" // Category-specific chronological queries | |
] | |
}; | |
// QUERY OPTIMIZATION EXAMPLES | |
const OPTIMIZED_QUERY_PATTERNS = { | |
// BEFORE: Multiple filter operations | |
getAllMemoriesOld: ` | |
db.memories | |
.where("character").equals(character) | |
.filter(m => m.isActive !== false) | |
.reverse() | |
.sortBy("timestamp") | |
`, | |
// AFTER: Use composite index | |
getAllMemoriesOptimized: ` | |
db.memories | |
.where("[character+isActive]").equals([character, true]) | |
.reverse() | |
.sortBy("timestamp") | |
`, | |
// BEFORE: Filter after retrieval | |
getMemoriesByCategoryOld: ` | |
db.memories | |
.where("[character+category]").equals([character, category]) | |
.and(m => m.isActive) | |
`, | |
// AFTER: Direct composite index | |
getMemoriesByCategoryOptimized: ` | |
db.memories | |
.where("[character+category+isActive]").equals([character, category, true]) | |
`, | |
// NEW: Efficient importance-based queries | |
getTopMemoriesByImportance: ` | |
db.memories | |
.where("[character+isActive+importance]") | |
.between([character, true, 0.8], [character, true, 1.0]) | |
.reverse() | |
.limit(10) | |
` | |
}; | |
// PERFORMANCE MONITORING UTILITIES | |
class MemoryDatabaseProfiler { | |
constructor() { | |
this.queryTimes = new Map(); | |
this.queryCount = new Map(); | |
} | |
// Wrap database operations to measure performance | |
async profileQuery(queryName, queryFn) { | |
const start = performance.now(); | |
const result = await queryFn(); | |
const duration = performance.now() - start; | |
// Update statistics | |
if (!this.queryTimes.has(queryName)) { | |
this.queryTimes.set(queryName, []); | |
this.queryCount.set(queryName, 0); | |
} | |
this.queryTimes.get(queryName).push(duration); | |
this.queryCount.set(queryName, this.queryCount.get(queryName) + 1); | |
// Log slow queries | |
if (duration > 50) { | |
// 50ms threshold | |
console.warn(`π Slow query detected: ${queryName} took ${duration.toFixed(2)}ms`); | |
} | |
return result; | |
} | |
// Get performance statistics | |
getStats() { | |
const stats = {}; | |
for (const [queryName, times] of this.queryTimes.entries()) { | |
const count = this.queryCount.get(queryName); | |
const avgTime = times.reduce((sum, time) => sum + time, 0) / times.length; | |
const maxTime = Math.max(...times); | |
const minTime = Math.min(...times); | |
stats[queryName] = { | |
count, | |
avgTime: Math.round(avgTime * 100) / 100, | |
maxTime: Math.round(maxTime * 100) / 100, | |
minTime: Math.round(minTime * 100) / 100, | |
totalTime: Math.round(times.reduce((sum, time) => sum + time, 0) * 100) / 100 | |
}; | |
} | |
return stats; | |
} | |
// Reset statistics | |
reset() { | |
this.queryTimes.clear(); | |
this.queryCount.clear(); | |
} | |
} | |
// MEMORY USAGE OPTIMIZATION | |
const MEMORY_CLEANUP_STRATEGIES = { | |
// Strategy 1: Batch cleanup operations | |
batchCleanup: async (db, maxBatchSize = 100) => { | |
const oldMemories = await db.memories.where("isActive").equals(false).limit(maxBatchSize).toArray(); | |
if (oldMemories.length > 0) { | |
await db.memories.bulkDelete(oldMemories.map(m => m.id)); | |
console.log(`π§Ή Batch deleted ${oldMemories.length} inactive memories`); | |
} | |
}, | |
// Strategy 2: Incremental keyword cleanup | |
cleanupKeywords: async db => { | |
const memoriesWithEmptyKeywords = await db.memories | |
.filter(m => !m.keywords || m.keywords.length === 0) | |
.limit(50) | |
.toArray(); | |
for (const memory of memoriesWithEmptyKeywords) { | |
const keywords = deriveKeywords(memory.content || ""); | |
await db.memories.update(memory.id, { keywords }); | |
} | |
}, | |
// Strategy 3: Compress old memories | |
compressOldMemories: async (db, daysThreshold = 90) => { | |
const cutoff = new Date(); | |
cutoff.setDate(cutoff.getDate() - daysThreshold); | |
const oldMemories = await db.memories | |
.where("timestamp") | |
.below(cutoff) | |
.and(m => m.isActive && !m.compressed) | |
.limit(20) | |
.toArray(); | |
for (const memory of oldMemories) { | |
// Compress by removing redundant fields and shortening content | |
const compressed = { | |
compressed: true, | |
originalLength: memory.content?.length || 0, | |
content: memory.content?.substring(0, 100) + "...", | |
// Remove non-essential fields | |
sourceText: undefined, | |
tags: memory.tags?.slice(0, 3) // Keep only top 3 tags | |
}; | |
await db.memories.update(memory.id, compressed); | |
} | |
} | |
}; | |
// EXPORT UTILITIES | |
if (typeof window !== "undefined") { | |
window.KIMI_MEMORY_DB_OPTIMIZATION = { | |
RECOMMENDED_MEMORY_INDEXES, | |
OPTIMIZED_QUERY_PATTERNS, | |
MemoryDatabaseProfiler, | |
MEMORY_CLEANUP_STRATEGIES | |
}; | |
} | |
export { RECOMMENDED_MEMORY_INDEXES, OPTIMIZED_QUERY_PATTERNS, MemoryDatabaseProfiler, MEMORY_CLEANUP_STRATEGIES }; | |