Documentation
¶
Overview ¶
Package temporal - Decay integration for adaptive memory retention.
DecayIntegration modifies NornicDB's decay system based on temporal patterns:
- Frequently accessed nodes decay SLOWER (important memories persist)
- Rarely accessed nodes decay FASTER (forgotten memories fade)
- Nodes with daily patterns maintain longer (routine knowledge)
- Burst-accessed nodes get temporary boost (current focus)
This creates a more human-like memory system where:
- Things you use often stay fresh
- Things you forget naturally fade
- Context matters (current session nodes are prioritized)
Integration points:
- DecayManager: Call GetDecayModifier() to adjust decay rate
- ArchiveManager: Call ShouldArchive() to identify cold nodes
- SearchRanker: Call GetRelevanceBoost() to rank results
ELI12 (Explain Like I'm 12) ¶
Your brain forgets things! But it's SMART about what it forgets:
🧠 Your best friend's name? → NEVER forget (use it daily!) 🧠 What you had for lunch today → Remember for a bit, then forget 🧠 Random fact from 5 years ago → Probably already forgot it
DecayIntegration makes the database work like your brain:
The "decay" is like forgetting. Every memory slowly fades over time. But the Kalman filter velocity tells us HOW to adjust the forgetting speed:
📈 Velocity positive (accessing MORE often): "Hey, you're using this a lot lately - slow down the forgetting!" Decay multiplier: 0.1 (10x slower decay) 📉 Velocity negative (accessing LESS often): "You used to look at this every day, now it's been weeks..." Decay multiplier: 2.0 (2x faster decay) 📊 Velocity stable: "Normal usage pattern, normal forgetting speed" Decay multiplier: 1.0 (normal decay)
Special cases:
🔥 BURST: Looking at something 10 times RIGHT NOW? → "Super important right now!" → Nearly zero decay 📅 DAILY PATTERN: Access every morning at 9am? → "Part of your routine!" → Slower decay ❄️ COLD: Haven't touched in 2 weeks? → "Probably not important anymore" → Faster decay, maybe archive
The Kalman filter smooths out noise. If you access something once by accident, it doesn't suddenly become "important". It waits to see a TREND.
Package temporal - Pattern detection for cyclic access patterns.
PatternDetector identifies recurring access patterns such as:
- Daily patterns (e.g., accessed every morning at 9am)
- Weekly patterns (e.g., accessed on Mondays)
- Burst patterns (clusters of rapid accesses)
- Decay patterns (gradually decreasing access)
ELI12 (Explain Like I'm 12) ¶
Imagine you have a favorite YouTube video. The PatternDetector notices:
📊 Daily Pattern: "You watch this video every day at 7pm after dinner" 📊 Weekly Pattern: "You binge-watch on Saturdays" 📊 Burst Pattern: "You're watching 10 videos right NOW - probably bored!" 📊 Growing: "You're watching more and more cat videos each week" 📊 Decaying: "You used to watch daily, now it's been 2 weeks..."
The detector counts how often you do things at each hour (0-23) and each day (Sunday-Saturday). If one hour has WAY more than others, that's a pattern!
Example:
Hour 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
Count 0 0 0 0 0 0 0 0 2 45 3 2 1 0 1 2 1 0 0 0 1 0 0 0
^^
"9am is clearly your jam!"
The Kalman filter velocity tells us if you're watching MORE or LESS over time. Positive velocity = growing interest, Negative velocity = losing interest.
Package temporal - Query load prediction for resource scaling.
QueryLoadPredictor tracks query volume trends and predicts future load using KalmanVelocity filters. This enables:
- Predicting upcoming query spikes
- Detecting load trends (increasing/decreasing)
- Triggering pre-emptive resource scaling
- Identifying query patterns (peak hours, burst events)
Use cases:
- Auto-scale database connections
- Pre-warm caches before predicted spikes
- Alert on unusual load patterns
- Capacity planning
Example usage:
predictor := temporal.NewQueryLoadPredictor(temporal.DefaultLoadConfig())
// Record each query
predictor.RecordQuery()
// Get current load prediction
prediction := predictor.GetPrediction()
fmt.Printf("Current QPS: %.1f, Predicted (5min): %.1f\n",
prediction.CurrentQPS, prediction.PredictedQPS)
// Check if scaling needed
if predictor.ShouldScaleUp(100) { // threshold QPS
triggerScaleUp()
}
ELI12 (Explain Like I'm 12) ¶
Imagine you're running a lemonade stand. You want to know:
🍋 "How many customers are coming right now?" (Current QPS) 🍋 "Will it get busier or slower?" (Trend) 🍋 "Should I make more lemonade NOW?" (Scale up prediction)
The QueryLoadPredictor counts how many "questions" (queries) the database gets every second. It's like counting customers:
Second 1: 10 queries Second 2: 12 queries Second 3: 15 queries Second 4: 20 queries → "Whoa, we're getting BUSIER! Velocity is positive!" 📈
The Kalman filter smooths out the bumps:
Raw counts: 10, 12, 50, 11, 13 (that 50 was a weird spike!) Filtered: 10, 11, 15, 13, 13 (smoothed - ignores the spike)
Why filter? Because ONE busy second doesn't mean you need to panic! The filter asks: "Is this a REAL trend or just random noise?"
Predictions:
Current: 50 QPS (queries per second) Velocity: +5 QPS/second (getting busier) Predicted in 5 min: 50 + (5 × 300) = 1550 QPS! 😱 → "Better scale up NOW before we're overwhelmed!"
Anomaly detection:
Normal: 50 QPS Suddenly: 500 QPS ← "SPIKE! Something's happening!" Suddenly: 5 QPS ← "DROP! Did something break?"
Peak hour detection:
Hour 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
Count 2 1 1 1 2 5 15 30 50 45 40 30 35 40 50 45 40 35 25 20 15 10 5 3
^^^^^^^^^^^^
"Peak hours are 8-10am and 2-4pm"
This lets us PREPARE before the rush! Pre-warm caches at 7:30am! 🚀
Package temporal - Relationship evolution tracking for dynamic graphs.
RelationshipEvolution tracks how edge weights change over time using KalmanVelocity filters. This enables:
- Detecting strengthening relationships (increasing co-access)
- Detecting weakening relationships (decreasing relevance)
- Predicting future relationship strength
- Identifying emerging connections
Use cases:
- Recommend strengthening edges for pre-fetching
- Prune weakening edges to save memory
- Detect new relationship patterns automatically
- Power dynamic graph visualizations
Example usage:
re := temporal.NewRelationshipEvolution(temporal.DefaultRelationshipConfig())
// Record co-access (updates edge weight)
re.RecordCoAccess("node-1", "node-2", 1.0)
// Get relationship trend
trend := re.GetTrend("node-1", "node-2")
fmt.Printf("Relationship is %s (velocity: %.3f)\n", trend.Direction, trend.Velocity)
// Predict future strength
future := re.PredictStrength("node-1", "node-2", 10)
fmt.Printf("In 10 steps, strength will be: %.3f\n", future)
ELI12 (Explain Like I'm 12) ¶
Think about your friendships. Some get STRONGER over time, some fade:
👫 Best friend in 1st grade → Moved away → Don't talk anymore (WEAKENING) 👫 New kid at school → Hang out more → Now best friends! (STRENGTHENING) 👫 Neighbor → See them same amount → Just neighbors (STABLE)
RelationshipEvolution tracks how "connected" two things are, and whether that connection is growing or shrinking.
In a database, "relationships" are like friendships between data:
📚 "JavaScript" ←→ "React" : Strong connection (always accessed together) 📚 "JavaScript" ←→ "Python": Weak connection (rarely together)
The Kalman filter tracks the TREND:
Week 1: JS+React accessed together 10 times Week 2: JS+React accessed together 15 times Week 3: JS+React accessed together 20 times → Velocity is POSITIVE! Relationship is STRENGTHENING! 📈 Week 1: JS+Python accessed together 5 times Week 2: JS+Python accessed together 3 times Week 3: JS+Python accessed together 1 time → Velocity is NEGATIVE! Relationship is WEAKENING! 📉
Why this matters:
✅ STRENGTHENING relationships: Pre-fetch! If you access JS, also load React ❌ WEAKENING relationships: Maybe delete the connection, save memory 🌱 EMERGING relationships: "Ooh, this is new and growing fast - watch it!"
The Kalman filter makes this smooth. One weird week doesn't change everything. It looks for REAL TRENDS, not random noise.
Package temporal - Session detection via velocity changes.
SessionDetector identifies user context switches by monitoring:
- Time gaps between accesses
- Sudden changes in access rate (velocity)
- Pattern breaks (different time-of-day)
Sessions are important for:
- Co-access inference (nodes accessed in same session are related)
- Context-aware search (prioritize current session nodes)
- Memory consolidation (sessions = semantic boundaries)
ELI12 (Explain Like I'm 12) ¶
Think about how you use your phone. You might:
📱 Morning: Check weather → Check email → Check news (WORK SESSION) ☕ Coffee break 📱 Later: Instagram → TikTok → YouTube (FUN SESSION)
The SessionDetector notices when you switch between "modes":
How it detects session changes:
TIME GAP: If you stop for 5+ minutes, that's probably a new session "You were looking at work stuff, went to lunch, now you're on games"
VELOCITY CHANGE (the Kalman filter magic!): The filter tracks HOW FAST you're accessing things. If velocity suddenly changes, your "mode" changed!
Before: accessing every 2 seconds (fast browsing) After: accessing every 30 seconds (reading something) → "Whoa, you slowed WAY down - new session!"
Why does this matter for memory?
Session 1: [Weather, Email, News] → These are probably related (work stuff) Session 2: [Instagram, TikTok] → These are probably related (fun stuff)
So if you search for "weather", we boost Email and News because they were accessed in the SAME SESSION. That's co-access inference!
Package temporal provides temporal pattern tracking and prediction for NornicDB.
This package tracks when nodes are accessed and uses Kalman filtering to:
- Smooth noisy access patterns
- Predict when nodes will be accessed next
- Detect session boundaries (context switches)
- Identify cyclic patterns (daily, weekly, etc.)
The temporal system integrates with NornicDB's decay system to:
- Slow decay for frequently accessed nodes
- Speed decay for abandoned nodes
- Predict archival candidates
Example usage:
tracker := temporal.NewTracker(temporal.DefaultConfig())
// Record accesses
tracker.RecordAccess("node-123")
tracker.RecordAccess("node-456")
// Get predictions
prediction := tracker.PredictNextAccess("node-123")
fmt.Printf("Node likely accessed in %.1f seconds\n", prediction.SecondsUntil)
// Check for session change
if tracker.IsSessionBoundary("node-123") {
fmt.Println("User context has changed!")
}
ELI12 (Explain Like I'm 12) ¶
Imagine you're keeping a diary of when your friends visit:
📅 Monday: Sarah came at 3pm 📅 Tuesday: Sarah came at 3pm 📅 Wednesday: Sarah came at 3:15pm 📅 Thursday: ???
The Tracker is like a smart diary that notices patterns:
🧠 "Sarah visits around 3pm every day" 🧠 "Mike comes on weekends" 🧠 "Random friend hasn't visited in 2 weeks - maybe forgot about us?"
The Kalman filter is the "smart" part. When Sarah came at 3:15pm on Wednesday, instead of panicking ("OMG she's 15 minutes late!"), it smoothly updates:
Before: "Sarah comes at 3:00pm" After: "Sarah comes around 3:03pm" (small adjustment)
It's like averaging, but SMARTER because it:
- Trusts patterns more than single weird events
- Notices if someone is visiting MORE or LESS often (velocity)
- Can predict: "At this rate, Sarah will visit at 2:50pm next week"
Why Kalman instead of simple averaging?
- Simple average: "3pm + 3pm + 3:15pm = 3:05pm average"
- Kalman: "3pm, 3pm, then 3:15pm... she might be getting later, or maybe it was just traffic. I'll say 3:03pm and watch for more data."
The Kalman filter LEARNS the trend (velocity) and uses it to predict!
Index ¶
- type Config
- type DecayComponent
- type DecayIntegration
- func (di *DecayIntegration) GetColdNodes(limit int) []string
- func (di *DecayIntegration) GetDecayModifier(nodeID string) DecayModifier
- func (di *DecayIntegration) GetEffectiveDecayRate(nodeID string) float64
- func (di *DecayIntegration) GetHotNodes(limit int) []string
- func (di *DecayIntegration) GetRelevanceBoost(nodeID string) float64
- func (di *DecayIntegration) GetStats() DecayIntegrationStats
- func (di *DecayIntegration) RecordAccess(nodeID string)
- func (di *DecayIntegration) RecordAccessAt(nodeID string, timestamp time.Time)
- func (di *DecayIntegration) Reset()
- func (di *DecayIntegration) ShouldArchive(nodeID string, currentScore float64, archiveThreshold float64) bool
- type DecayIntegrationConfig
- type DecayIntegrationStats
- type DecayModifier
- type DetectedPattern
- type GlobalStats
- type LoadConfig
- type LoadPrediction
- type LoadStats
- type NodeAccess
- type NodeStats
- type PatternDetector
- func (pd *PatternDetector) DetectPatterns(nodeID string, currentVelocity float64) []DetectedPattern
- func (pd *PatternDetector) GetPeakAccessTime(nodeID string) (hour int, day int, confidence float64)
- func (pd *PatternDetector) HasPattern(nodeID string, patternType PatternType, velocity float64) bool
- func (pd *PatternDetector) RecordAccess(nodeID string, timestamp time.Time)
- func (pd *PatternDetector) Reset()
- func (pd *PatternDetector) ResetNode(nodeID string)
- type PatternDetectorConfig
- type PatternType
- type Prediction
- type QueryLoadPredictor
- func (qlp *QueryLoadPredictor) GetLoadLevel(maxQPS float64) int
- func (qlp *QueryLoadPredictor) GetPrediction() LoadPrediction
- func (qlp *QueryLoadPredictor) GetStats() LoadStats
- func (qlp *QueryLoadPredictor) PredictPeakTime() time.Time
- func (qlp *QueryLoadPredictor) RecordQueries(count int)
- func (qlp *QueryLoadPredictor) RecordQuery()
- func (qlp *QueryLoadPredictor) RecordQueryAt(timestamp time.Time)
- func (qlp *QueryLoadPredictor) Reset()
- func (qlp *QueryLoadPredictor) ShouldScaleDown(thresholdQPS float64, minQPS float64) bool
- func (qlp *QueryLoadPredictor) ShouldScaleUp(thresholdQPS float64) bool
- type RelationshipConfig
- type RelationshipEvolution
- func (re *RelationshipEvolution) DecayIdleRelationships(maxIdleHours float64) int
- func (re *RelationshipEvolution) GetEmergingRelationships(limit int) []RelationshipTrend
- func (re *RelationshipEvolution) GetStats() RelationshipStats
- func (re *RelationshipEvolution) GetStrengtheningRelationships(limit int) []RelationshipTrend
- func (re *RelationshipEvolution) GetTrend(sourceID, targetID string) *RelationshipTrend
- func (re *RelationshipEvolution) GetWeakeningRelationships(limit int) []RelationshipTrend
- func (re *RelationshipEvolution) PredictStrength(sourceID, targetID string, steps int) float64
- func (re *RelationshipEvolution) RecordCoAccess(sourceID, targetID string, weight float64)
- func (re *RelationshipEvolution) RecordCoAccessAt(sourceID, targetID string, weight float64, timestamp time.Time)
- func (re *RelationshipEvolution) Reset()
- func (re *RelationshipEvolution) ShouldPrune(sourceID, targetID string, threshold float64) bool
- func (re *RelationshipEvolution) UpdateWeight(sourceID, targetID string, newWeight float64)
- type RelationshipStats
- type RelationshipTrend
- type Session
- type SessionDetector
- func (sd *SessionDetector) AddListener(listener func(SessionEvent))
- func (sd *SessionDetector) GetActiveSessions() []*Session
- func (sd *SessionDetector) GetCoAccessedNodes(nodeID string) []string
- func (sd *SessionDetector) GetCurrentSession(nodeID string) *Session
- func (sd *SessionDetector) GetSessionHistory(nodeID string, limit int) []*Session
- func (sd *SessionDetector) GetVelocity(nodeID string) float64
- func (sd *SessionDetector) IsSessionBoundary(nodeID string) bool
- func (sd *SessionDetector) RecordAccess(nodeID string, timestamp time.Time) SessionEvent
- func (sd *SessionDetector) Reset()
- type SessionDetectorConfig
- type SessionEvent
- type SessionEventType
- type Tracker
- func (t *Tracker) GetAccessRateTrend(nodeID string) (velocity float64, trend string)
- func (t *Tracker) GetColdNodes(limit int) []string
- func (t *Tracker) GetGlobalStats() GlobalStats
- func (t *Tracker) GetHotNodes(limit int) []string
- func (t *Tracker) GetStats(nodeID string) *NodeStats
- func (t *Tracker) IsSessionBoundary(nodeID string) bool
- func (t *Tracker) PredictNextAccess(nodeID string) *Prediction
- func (t *Tracker) RecordAccess(nodeID string)
- func (t *Tracker) RecordAccessAt(nodeID string, timestamp time.Time)
- func (t *Tracker) Reset()
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct {
// MaxTrackedNodes - maximum number of nodes to track (LRU eviction)
MaxTrackedNodes int
// MinAccessesForPrediction - minimum accesses before making predictions
MinAccessesForPrediction int
// SessionTimeoutSeconds - gap that indicates a new session
SessionTimeoutSeconds float64
// VelocityChangeThreshold - velocity change that triggers session boundary
VelocityChangeThreshold float64
// FilterConfig for the underlying Kalman velocity filter
FilterConfig filter.VelocityConfig
// EnableAdaptiveFilter - use adaptive filter that switches modes
EnableAdaptiveFilter bool
// CleanupInterval - how often to clean up stale entries
CleanupInterval time.Duration
// MaxHistoryPerNode - maximum access history entries per node
MaxHistoryPerNode int
}
Config holds temporal tracker configuration.
func DefaultConfig ¶
func DefaultConfig() Config
DefaultConfig returns sensible defaults for temporal tracking.
func HighPrecisionConfig ¶
func HighPrecisionConfig() Config
HighPrecisionConfig returns config for high-precision temporal tracking.
func LowMemoryConfig ¶
func LowMemoryConfig() Config
LowMemoryConfig returns config optimized for memory efficiency.
type DecayComponent ¶
DecayComponent represents a single factor affecting decay.
type DecayIntegration ¶
type DecayIntegration struct {
// contains filtered or unexported fields
}
DecayIntegration manages decay rate modifications based on temporal data.
func NewDecayIntegration ¶
func NewDecayIntegration(cfg DecayIntegrationConfig) *DecayIntegration
NewDecayIntegration creates a new decay integration system.
func NewDecayIntegrationWithComponents ¶
func NewDecayIntegrationWithComponents( cfg DecayIntegrationConfig, tracker *Tracker, pattern *PatternDetector, session *SessionDetector, ) *DecayIntegration
NewDecayIntegrationWithComponents creates decay integration with existing components.
func (*DecayIntegration) GetColdNodes ¶
func (di *DecayIntegration) GetColdNodes(limit int) []string
GetColdNodes returns nodes that are candidates for archival.
func (*DecayIntegration) GetDecayModifier ¶
func (di *DecayIntegration) GetDecayModifier(nodeID string) DecayModifier
GetDecayModifier returns the decay rate modifier for a node.
func (*DecayIntegration) GetEffectiveDecayRate ¶
func (di *DecayIntegration) GetEffectiveDecayRate(nodeID string) float64
GetEffectiveDecayRate returns the actual decay rate for a node.
func (*DecayIntegration) GetHotNodes ¶
func (di *DecayIntegration) GetHotNodes(limit int) []string
GetHotNodes returns nodes that should be prioritized (slow decay).
func (*DecayIntegration) GetRelevanceBoost ¶
func (di *DecayIntegration) GetRelevanceBoost(nodeID string) float64
GetRelevanceBoost returns a relevance boost for search ranking.
func (*DecayIntegration) GetStats ¶
func (di *DecayIntegration) GetStats() DecayIntegrationStats
GetStats returns current statistics.
func (*DecayIntegration) RecordAccess ¶
func (di *DecayIntegration) RecordAccess(nodeID string)
RecordAccess records an access and updates all temporal components.
func (*DecayIntegration) RecordAccessAt ¶
func (di *DecayIntegration) RecordAccessAt(nodeID string, timestamp time.Time)
RecordAccessAt records an access at a specific time.
func (*DecayIntegration) Reset ¶
func (di *DecayIntegration) Reset()
Reset clears all temporal data.
func (*DecayIntegration) ShouldArchive ¶
func (di *DecayIntegration) ShouldArchive(nodeID string, currentScore float64, archiveThreshold float64) bool
ShouldArchive checks if a node should be archived based on temporal data.
type DecayIntegrationConfig ¶
type DecayIntegrationConfig struct {
// BaseDecayRate - the default decay rate per hour (0-1)
BaseDecayRate float64
// FrequentAccessBoost - how much to slow decay for frequent access (0.1 = 10x slower)
FrequentAccessBoost float64
// RareAccessPenalty - how much to speed decay for rare access (2.0 = 2x faster)
RareAccessPenalty float64
// DailyPatternBoost - boost for nodes with daily patterns
DailyPatternBoost float64
// BurstBoostDuration - how long burst boost lasts (seconds)
BurstBoostDuration float64
// BurstBoostMultiplier - decay multiplier during burst
BurstBoostMultiplier float64
// SessionBoostMultiplier - decay multiplier for current session nodes
SessionBoostMultiplier float64
// MinDecayMultiplier - minimum decay multiplier (prevent immortal nodes)
MinDecayMultiplier float64
// MaxDecayMultiplier - maximum decay multiplier (prevent instant death)
MaxDecayMultiplier float64
// VelocityWeight - how much velocity affects decay
VelocityWeight float64
// PatternWeight - how much patterns affect decay
PatternWeight float64
// RecencyWeight - how much recency affects decay
RecencyWeight float64
}
DecayIntegrationConfig holds configuration for decay integration.
func AggressiveDecayConfig ¶
func AggressiveDecayConfig() DecayIntegrationConfig
AggressiveDecayConfig returns config that forgets faster.
func ConservativeDecayConfig ¶
func ConservativeDecayConfig() DecayIntegrationConfig
ConservativeDecayConfig returns config that preserves more memories.
func DefaultDecayIntegrationConfig ¶
func DefaultDecayIntegrationConfig() DecayIntegrationConfig
DefaultDecayIntegrationConfig returns sensible defaults.
type DecayIntegrationStats ¶
type DecayIntegrationStats struct {
TrackedNodes int
ActiveSessions int
TotalAccesses int64
AverageMultiplier float64
}
GetStats returns statistics for the decay integration.
type DecayModifier ¶
type DecayModifier struct {
// Multiplier for decay rate (0.5 = half decay speed, 2.0 = double decay speed)
Multiplier float64
// Reason for the modification
Reason string
// Confidence in this modification (0-1)
Confidence float64
// Components that contributed to this modifier
Components []DecayComponent
}
DecayModifier represents how decay should be adjusted.
type DetectedPattern ¶
type DetectedPattern struct {
Type PatternType
Confidence float64
PeakHour int // 0-23, for daily patterns
PeakDay int // 0-6 (Sunday=0), for weekly patterns
Period float64 // Estimated period in seconds
LastSeen time.Time // When pattern was last observed
}
DetectedPattern holds information about a detected pattern.
type GlobalStats ¶
type GlobalStats struct {
TotalAccesses int64
TrackedNodes int
UptimeSeconds float64
AccessesPerSec float64
}
GlobalStats returns global tracking statistics.
type LoadConfig ¶
type LoadConfig struct {
// FilterConfig for the underlying Kalman velocity filter
FilterConfig filter.VelocityConfig
// BucketDurationSeconds - duration of each measurement bucket
BucketDurationSeconds float64
// SpikeThreshold - QPS velocity above which is a "spike"
SpikeThreshold float64
// DropThreshold - QPS velocity below which is a "drop"
DropThreshold float64
// AnomalyStdDevs - number of standard deviations for anomaly detection
AnomalyStdDevs float64
// ScaleUpThreshold - relative increase that suggests scaling up
ScaleUpThreshold float64
// ScaleDownThreshold - relative decrease that suggests scaling down
ScaleDownThreshold float64
// PeakDetectionWindow - hours to track for peak detection
PeakDetectionWindow int
}
LoadConfig holds configuration for query load prediction.
func DefaultLoadConfig ¶
func DefaultLoadConfig() LoadConfig
DefaultLoadConfig returns sensible defaults.
func HighSensitivityLoadConfig ¶
func HighSensitivityLoadConfig() LoadConfig
HighSensitivityLoadConfig returns config for high-sensitivity detection.
type LoadPrediction ¶
type LoadPrediction struct {
// Current metrics
CurrentQPS float64 // Queries per second (smoothed)
CurrentQPM float64 // Queries per minute (smoothed)
RawQPS float64 // Unfiltered QPS
TotalQueries int64
// Trend
Velocity float64 // Rate of change (positive = increasing load)
Trend string // "increasing", "decreasing", "stable"
// Predictions
PredictedQPS5m float64 // Predicted QPS in 5 minutes
PredictedQPS15m float64 // Predicted QPS in 15 minutes
PredictedQPS1h float64 // Predicted QPS in 1 hour
// Confidence
Confidence float64
// Time-of-day pattern
PeakHour int
IsNearPeak bool
// Anomaly detection
IsAnomaly bool
AnomalyType string // "spike", "drop", "sustained_high", "sustained_low"
// Timestamp
Timestamp time.Time
}
LoadPrediction represents a query load prediction.
type LoadStats ¶
type LoadStats struct {
TotalQueries int64
UptimeSeconds float64
AverageQPS float64
CurrentQPS float64
PeakQPS float64
PeakHour int
}
LoadStats holds statistics about query load.
type NodeAccess ¶
NodeAccess represents a single access event.
type NodeStats ¶
type NodeStats struct {
NodeID string
// Access counts
TotalAccesses int64
AccessesInHour int
AccessesInDay int
AccessesInWeek int
// Timing
FirstAccess time.Time
LastAccess time.Time
AverageInterval float64 // seconds between accesses
// Predictions
PredictedNextAccess time.Time
PredictionConfidence float64
// Pattern detection
HasDailyPattern bool
HasWeeklyPattern bool
PeakHour int // 0-23
PeakDay int // 0-6 (Sunday=0)
// Session info
CurrentSessionStart time.Time
SessionCount int
// Filter state
AccessRateVelocity float64 // rate of change of access frequency
}
NodeStats holds temporal statistics for a single node.
type PatternDetector ¶
type PatternDetector struct {
// contains filtered or unexported fields
}
PatternDetector detects access patterns for nodes.
func NewPatternDetector ¶
func NewPatternDetector(cfg PatternDetectorConfig) *PatternDetector
NewPatternDetector creates a new pattern detector.
func (*PatternDetector) DetectPatterns ¶
func (pd *PatternDetector) DetectPatterns(nodeID string, currentVelocity float64) []DetectedPattern
DetectPatterns analyzes access patterns for a node.
func (*PatternDetector) GetPeakAccessTime ¶
func (pd *PatternDetector) GetPeakAccessTime(nodeID string) (hour int, day int, confidence float64)
GetPeakAccessTime returns the predicted best time to access a node.
func (*PatternDetector) HasPattern ¶
func (pd *PatternDetector) HasPattern(nodeID string, patternType PatternType, velocity float64) bool
HasPattern checks if a node has a specific pattern type.
func (*PatternDetector) RecordAccess ¶
func (pd *PatternDetector) RecordAccess(nodeID string, timestamp time.Time)
RecordAccess records an access for pattern analysis.
func (*PatternDetector) ResetNode ¶
func (pd *PatternDetector) ResetNode(nodeID string)
ResetNode clears pattern data for a specific node.
type PatternDetectorConfig ¶
type PatternDetectorConfig struct {
// MinSamplesForPattern - minimum accesses to detect patterns
MinSamplesForPattern int
// DailyConfidenceThreshold - min confidence to report daily pattern
DailyConfidenceThreshold float64
// WeeklyConfidenceThreshold - min confidence to report weekly pattern
WeeklyConfidenceThreshold float64
// BurstWindowSeconds - time window for burst detection
BurstWindowSeconds float64
// BurstMinAccesses - minimum accesses in window to be a burst
BurstMinAccesses int
// GrowthThreshold - velocity above which is "growing"
GrowthThreshold float64
// DecayThreshold - velocity below which is "decaying"
DecayThreshold float64
}
PatternDetectorConfig holds configuration for pattern detection.
func DefaultPatternDetectorConfig ¶
func DefaultPatternDetectorConfig() PatternDetectorConfig
DefaultPatternDetectorConfig returns sensible defaults.
type PatternType ¶
type PatternType string
PatternType represents detected pattern types.
const ( PatternNone PatternType = "none" PatternDaily PatternType = "daily" PatternWeekly PatternType = "weekly" PatternBurst PatternType = "burst" PatternDecaying PatternType = "decaying" PatternGrowing PatternType = "growing" )
type Prediction ¶
type Prediction struct {
NodeID string
PredictedTime time.Time
SecondsUntil float64
Confidence float64
BasedOnAccesses int
AccessRateTrend string // "increasing", "stable", "decreasing"
}
Prediction represents a predicted future access.
type QueryLoadPredictor ¶
type QueryLoadPredictor struct {
// contains filtered or unexported fields
}
QueryLoadPredictor predicts query load using velocity tracking.
func NewQueryLoadPredictor ¶
func NewQueryLoadPredictor(cfg LoadConfig) *QueryLoadPredictor
NewQueryLoadPredictor creates a new query load predictor.
func (*QueryLoadPredictor) GetLoadLevel ¶
func (qlp *QueryLoadPredictor) GetLoadLevel(maxQPS float64) int
GetLoadLevel returns a simplified load level (0-5).
func (*QueryLoadPredictor) GetPrediction ¶
func (qlp *QueryLoadPredictor) GetPrediction() LoadPrediction
GetPrediction returns the current load prediction.
func (*QueryLoadPredictor) GetStats ¶
func (qlp *QueryLoadPredictor) GetStats() LoadStats
GetStats returns query load statistics.
func (*QueryLoadPredictor) PredictPeakTime ¶
func (qlp *QueryLoadPredictor) PredictPeakTime() time.Time
PredictPeakTime predicts when the next peak will occur.
func (*QueryLoadPredictor) RecordQueries ¶
func (qlp *QueryLoadPredictor) RecordQueries(count int)
RecordQueries records multiple query events (batch recording).
func (*QueryLoadPredictor) RecordQuery ¶
func (qlp *QueryLoadPredictor) RecordQuery()
RecordQuery records a query event.
func (*QueryLoadPredictor) RecordQueryAt ¶
func (qlp *QueryLoadPredictor) RecordQueryAt(timestamp time.Time)
RecordQueryAt records a query at a specific time.
func (*QueryLoadPredictor) Reset ¶
func (qlp *QueryLoadPredictor) Reset()
Reset clears all load data.
func (*QueryLoadPredictor) ShouldScaleDown ¶
func (qlp *QueryLoadPredictor) ShouldScaleDown(thresholdQPS float64, minQPS float64) bool
ShouldScaleDown checks if load is decreasing and below threshold.
func (*QueryLoadPredictor) ShouldScaleUp ¶
func (qlp *QueryLoadPredictor) ShouldScaleUp(thresholdQPS float64) bool
ShouldScaleUp checks if load is increasing and above threshold.
type RelationshipConfig ¶
type RelationshipConfig struct {
// FilterConfig for the underlying Kalman velocity filter
FilterConfig filter.VelocityConfig
// MaxTrackedRelationships - maximum relationships to track (LRU eviction)
MaxTrackedRelationships int
// StrengthenThreshold - velocity above which is "strengthening"
StrengthenThreshold float64
// WeakenThreshold - velocity below which is "weakening"
WeakenThreshold float64
// MinObservationsForTrend - minimum observations before reporting trend
MinObservationsForTrend int
// DecayIdleRelationships - decay weight of idle relationships
DecayIdleRelationships bool
// IdleDecayRate - how much to decay per hour of inactivity
IdleDecayRate float64
}
RelationshipConfig holds configuration for relationship evolution tracking.
func DefaultRelationshipConfig ¶
func DefaultRelationshipConfig() RelationshipConfig
DefaultRelationshipConfig returns sensible defaults.
type RelationshipEvolution ¶
type RelationshipEvolution struct {
// contains filtered or unexported fields
}
RelationshipEvolution tracks edge weight changes over time.
func NewRelationshipEvolution ¶
func NewRelationshipEvolution(cfg RelationshipConfig) *RelationshipEvolution
NewRelationshipEvolution creates a new relationship evolution tracker.
func (*RelationshipEvolution) DecayIdleRelationships ¶
func (re *RelationshipEvolution) DecayIdleRelationships(maxIdleHours float64) int
DecayIdleRelationships applies decay to relationships not updated recently.
func (*RelationshipEvolution) GetEmergingRelationships ¶
func (re *RelationshipEvolution) GetEmergingRelationships(limit int) []RelationshipTrend
GetEmergingRelationships returns new relationships with positive velocity.
func (*RelationshipEvolution) GetStats ¶
func (re *RelationshipEvolution) GetStats() RelationshipStats
GetStats returns statistics about relationship tracking.
func (*RelationshipEvolution) GetStrengtheningRelationships ¶
func (re *RelationshipEvolution) GetStrengtheningRelationships(limit int) []RelationshipTrend
GetStrengtheningRelationships returns relationships that are getting stronger.
func (*RelationshipEvolution) GetTrend ¶
func (re *RelationshipEvolution) GetTrend(sourceID, targetID string) *RelationshipTrend
GetTrend returns the evolution trend for a relationship.
func (*RelationshipEvolution) GetWeakeningRelationships ¶
func (re *RelationshipEvolution) GetWeakeningRelationships(limit int) []RelationshipTrend
GetWeakeningRelationships returns relationships that are getting weaker.
func (*RelationshipEvolution) PredictStrength ¶
func (re *RelationshipEvolution) PredictStrength(sourceID, targetID string, steps int) float64
PredictStrength predicts the relationship strength n steps ahead.
func (*RelationshipEvolution) RecordCoAccess ¶
func (re *RelationshipEvolution) RecordCoAccess(sourceID, targetID string, weight float64)
RecordCoAccess records a co-access event between two nodes. weight should be 1.0 for simple co-access, or can be weighted.
func (*RelationshipEvolution) RecordCoAccessAt ¶
func (re *RelationshipEvolution) RecordCoAccessAt(sourceID, targetID string, weight float64, timestamp time.Time)
RecordCoAccessAt records co-access at a specific time.
func (*RelationshipEvolution) Reset ¶
func (re *RelationshipEvolution) Reset()
Reset clears all relationship data.
func (*RelationshipEvolution) ShouldPrune ¶
func (re *RelationshipEvolution) ShouldPrune(sourceID, targetID string, threshold float64) bool
ShouldPrune checks if a relationship should be pruned (very weak and weakening).
func (*RelationshipEvolution) UpdateWeight ¶
func (re *RelationshipEvolution) UpdateWeight(sourceID, targetID string, newWeight float64)
UpdateWeight updates the weight of an existing relationship. Use this for explicit weight updates (not just co-access).
type RelationshipStats ¶
type RelationshipStats struct {
TrackedRelationships int
TotalUpdates int64
Strengthening int
Weakening int
Stable int
UptimeSeconds float64
}
RelationshipStats holds statistics about relationship tracking.
type RelationshipTrend ¶
type RelationshipTrend struct {
// Direction: "strengthening", "weakening", "stable"
Direction string
// Velocity: rate of change (positive = strengthening)
Velocity float64
// CurrentStrength: current filtered weight
CurrentStrength float64
// PredictedStrength: predicted weight in 5 steps
PredictedStrength float64
// Confidence: confidence in the trend (0-1)
Confidence float64
// ObservationCount: number of weight updates
ObservationCount int
// LastUpdate: when the relationship was last updated
LastUpdate time.Time
}
RelationshipTrend represents the evolution trend of a relationship.
type Session ¶
type Session struct {
ID string
StartTime time.Time
EndTime time.Time
NodeIDs []string // Nodes accessed in this session
Duration time.Duration
IsCurrent bool
}
Session represents a detected user session.
type SessionDetector ¶
type SessionDetector struct {
// contains filtered or unexported fields
}
SessionDetector detects session boundaries from access patterns.
func NewSessionDetector ¶
func NewSessionDetector(cfg SessionDetectorConfig) *SessionDetector
NewSessionDetector creates a new session detector.
func (*SessionDetector) AddListener ¶
func (sd *SessionDetector) AddListener(listener func(SessionEvent))
AddListener adds a listener for session events.
func (*SessionDetector) GetActiveSessions ¶
func (sd *SessionDetector) GetActiveSessions() []*Session
GetActiveSessions returns all currently active sessions.
func (*SessionDetector) GetCoAccessedNodes ¶
func (sd *SessionDetector) GetCoAccessedNodes(nodeID string) []string
GetCoAccessedNodes returns nodes accessed in the same session.
func (*SessionDetector) GetCurrentSession ¶
func (sd *SessionDetector) GetCurrentSession(nodeID string) *Session
GetCurrentSession returns the current session for a node.
func (*SessionDetector) GetSessionHistory ¶
func (sd *SessionDetector) GetSessionHistory(nodeID string, limit int) []*Session
GetSessionHistory returns session history for a node.
func (*SessionDetector) GetVelocity ¶
func (sd *SessionDetector) GetVelocity(nodeID string) float64
GetVelocity returns the current access rate velocity for a node.
func (*SessionDetector) IsSessionBoundary ¶
func (sd *SessionDetector) IsSessionBoundary(nodeID string) bool
IsSessionBoundary checks if the last access was a session boundary.
func (*SessionDetector) RecordAccess ¶
func (sd *SessionDetector) RecordAccess(nodeID string, timestamp time.Time) SessionEvent
RecordAccess records an access and checks for session boundaries.
type SessionDetectorConfig ¶
type SessionDetectorConfig struct {
// TimeGapThresholdSeconds - gap that triggers new session
TimeGapThresholdSeconds float64
// VelocityChangeThreshold - relative change that triggers session
VelocityChangeThreshold float64
// MinSessionDurationSeconds - minimum duration to be a valid session
MinSessionDurationSeconds float64
// MaxSessionDurationSeconds - maximum session duration (force break)
MaxSessionDurationSeconds float64
// FilterConfig for velocity tracking
FilterConfig filter.VelocityConfig
}
SessionDetectorConfig holds configuration for session detection.
func DefaultSessionDetectorConfig ¶
func DefaultSessionDetectorConfig() SessionDetectorConfig
DefaultSessionDetectorConfig returns sensible defaults.
type SessionEvent ¶
type SessionEvent struct {
Type SessionEventType
Timestamp time.Time
NodeID string
OldRate float64
NewRate float64
Reason string
}
SessionEvent represents a session boundary event.
type SessionEventType ¶
type SessionEventType string
SessionEventType represents types of session events.
const ( SessionStart SessionEventType = "start" SessionEnd SessionEventType = "end" SessionContinue SessionEventType = "continue" )
type Tracker ¶
type Tracker struct {
// contains filtered or unexported fields
}
Tracker is the main temporal tracking system.
func NewTracker ¶
NewTracker creates a new temporal tracker with the given configuration.
The tracker monitors node access patterns over time and uses Kalman filtering to smooth noisy data and predict future accesses. It automatically detects session boundaries and cyclic patterns.
Parameters:
- cfg: Configuration for tracking behavior (use DefaultConfig() for defaults)
Returns:
- *Tracker ready to record accesses and make predictions
Example 1 - Basic Access Tracking:
tracker := temporal.NewTracker(temporal.DefaultConfig())
// Simulate user accessing documents over time
for i := 0; i < 10; i++ {
tracker.RecordAccess("doc-123")
time.Sleep(5 * time.Second)
}
// Get statistics
stats := tracker.GetNodeStats("doc-123")
fmt.Printf("Accessed %d times, avg %.1f seconds between accesses\n",
stats.AccessCount, stats.AverageIntervalSeconds)
Example 2 - Predicting Next Access:
tracker := temporal.NewTracker(temporal.DefaultConfig())
// User accesses a file regularly
for i := 0; i < 5; i++ {
tracker.RecordAccess("project-file")
time.Sleep(1 * time.Hour) // Every hour
}
// Predict when they'll access it next
prediction := tracker.PredictNextAccess("project-file")
if prediction != nil {
fmt.Printf("Likely to access in %.0f minutes\n", prediction.SecondsUntil/60)
// Output: "Likely to access in 60 minutes"
}
Example 3 - Session Boundary Detection:
tracker := temporal.NewTracker(temporal.DefaultConfig())
// User is actively working
tracker.RecordAccess("doc-1")
time.Sleep(30 * time.Second)
tracker.RecordAccess("doc-1")
time.Sleep(30 * time.Second)
// Long gap - user left for lunch
time.Sleep(2 * time.Hour)
// Check if session changed
if tracker.IsSessionBoundary("doc-1") {
fmt.Println("New session detected - user returned!")
// Clear short-term context, log session end, etc.
}
Example 4 - Integration with Decay System:
tracker := temporal.NewTracker(temporal.DefaultConfig())
decayManager := decay.New(nil)
// Track accesses and update decay
onAccess := func(nodeID string) {
tracker.RecordAccess(nodeID)
// Predict if node will be accessed soon
pred := tracker.PredictNextAccess(nodeID)
if pred != nil && pred.SecondsUntil < 3600 { // Within 1 hour
// Slow decay for nodes that will be accessed soon
memory.ImportanceWeight = 0.9
}
}
ELI12:
Think of NewTracker like starting a stopwatch collection for tracking when your friends visit:
- Every time Sarah visits, you click her stopwatch: RECORD ACCESS
- After a few visits, you notice "Sarah comes every day around 3pm"
- The tracker can predict: "Sarah will probably visit tomorrow at 3pm"
- If she doesn't visit for a week, it notices: "Session ended, she forgot about us"
The Kalman filter is the "smart brain" that:
- Notices patterns (daily visits, weekly visits, etc.)
- Handles noise (if she comes at 3:05pm once, don't panic)
- Detects trends (is she visiting MORE often or LESS often?)
- Makes predictions (when will she visit next?)
Real-world Uses:
- Cache management: "This file will be accessed in 5 minutes, keep it warm!"
- Memory decay: "This hasn't been accessed in 2 weeks, archive it"
- Context switching: "User moved from coding to meetings (30 min gap)"
- Predictive loading: "User opens Report.docx every Monday at 9am"
Performance:
- RecordAccess: O(1) - very fast
- PredictNextAccess: O(1) - simple calculation
- Memory: ~500 bytes per tracked node
- MaxTrackedNodes uses LRU eviction (least recently used gets removed)
Thread Safety:
All methods are thread-safe for concurrent access from multiple goroutines.
func (*Tracker) GetAccessRateTrend ¶
GetAccessRateTrend returns the access rate trend for a node.
func (*Tracker) GetColdNodes ¶
GetColdNodes returns nodes with decreasing access rates.
func (*Tracker) GetGlobalStats ¶
func (t *Tracker) GetGlobalStats() GlobalStats
GetGlobalStats returns global statistics.
func (*Tracker) GetHotNodes ¶
GetHotNodes returns nodes with increasing access rates.
func (*Tracker) IsSessionBoundary ¶
IsSessionBoundary checks if a significant session change occurred for a node.
func (*Tracker) PredictNextAccess ¶
func (t *Tracker) PredictNextAccess(nodeID string) *Prediction
PredictNextAccess predicts when a node will be accessed next.
func (*Tracker) RecordAccess ¶
RecordAccess records an access to a node at the current time.
This is the primary method for feeding access events into the temporal tracker. Each call updates the node's access statistics, smooths the data with Kalman filtering, and checks for session boundaries.
Parameters:
- nodeID: Unique identifier for the node being accessed
Example 1 - Simple Access Tracking:
tracker := temporal.NewTracker(temporal.DefaultConfig())
// Record every time user opens a document
tracker.RecordAccess("doc-readme")
tracker.RecordAccess("doc-api")
tracker.RecordAccess("doc-readme") // Accessed again
// Tracker now knows doc-readme is accessed more frequently
Example 2 - Integration with Storage Engine:
tracker := temporal.NewTracker(temporal.DefaultConfig())
engine := storage.NewBadgerEngine("./data")
// Hook into node retrieval
originalGet := engine.GetNode
engine.GetNode = func(id storage.NodeID) (*storage.Node, error) {
tracker.RecordAccess(string(id)) // Track access
return originalGet(id)
}
Example 3 - Real-time Recommendation System:
tracker := temporal.NewTracker(temporal.DefaultConfig())
func handleUserAction(userID, itemID string) {
tracker.RecordAccess(itemID)
// Get all recently accessed items
recentItems := tracker.GetRecentlyAccessed(10)
// Recommend similar items
recommendations := findSimilarItems(recentItems)
showRecommendations(userID, recommendations)
}
ELI12:
Think of RecordAccess like clicking a button on your stopwatch app:
- Click! = "I just used this thing"
- The app remembers: "Oh, you use this every hour"
- Next time, it can guess: "You'll probably use it again in 1 hour"
It's like your phone learning you check Instagram every morning at 7am, so it preloads it for you!
Performance:
- O(1) constant time operation
- Thread-safe with mutex protection
- Automatic LRU eviction when MaxTrackedNodes exceeded
Thread Safety:
Safe to call concurrently from multiple goroutines.
func (*Tracker) RecordAccessAt ¶
RecordAccessAt records an access at a specific time.