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 }; | |