@soulcraft/brainy 3.34.0 → 3.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +63 -0
- package/README.md +32 -12
- package/dist/brainy.d.ts +15 -0
- package/dist/brainy.js +63 -34
- package/dist/hnsw/hnswIndex.d.ts +128 -1
- package/dist/hnsw/hnswIndex.js +411 -17
- package/dist/hnsw/hnswIndexOptimized.d.ts +3 -15
- package/dist/hnsw/hnswIndexOptimized.js +11 -42
- package/dist/hnsw/partitionedHNSWIndex.js +1 -1
- package/dist/interfaces/IIndex.d.ts +195 -0
- package/dist/interfaces/IIndex.js +15 -0
- package/dist/storage/adapters/baseStorageAdapter.d.ts +17 -0
- package/dist/storage/adapters/fileSystemStorage.d.ts +32 -0
- package/dist/storage/adapters/fileSystemStorage.js +66 -0
- package/dist/storage/adapters/gcsStorage.d.ts +36 -0
- package/dist/storage/adapters/gcsStorage.js +90 -0
- package/dist/storage/adapters/memoryStorage.d.ts +32 -0
- package/dist/storage/adapters/memoryStorage.js +43 -0
- package/dist/storage/adapters/opfsStorage.d.ts +36 -0
- package/dist/storage/adapters/opfsStorage.js +101 -0
- package/dist/storage/adapters/s3CompatibleStorage.d.ts +36 -0
- package/dist/storage/adapters/s3CompatibleStorage.js +112 -0
- package/dist/utils/memoryDetection.d.ts +119 -0
- package/dist/utils/memoryDetection.js +321 -0
- package/dist/utils/unifiedCache.d.ts +75 -1
- package/dist/utils/unifiedCache.js +123 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,69 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [3.36.0](https://github.com/soulcraftlabs/brainy/compare/v3.35.0...v3.36.0) (2025-10-10)
|
|
6
|
+
|
|
7
|
+
#### 🚀 Always-Adaptive Caching with Enhanced Monitoring
|
|
8
|
+
|
|
9
|
+
**Zero Breaking Changes** - Internal optimizations with automatic performance improvements
|
|
10
|
+
|
|
11
|
+
#### What's New
|
|
12
|
+
|
|
13
|
+
- **Renamed API**: `getLazyModeStats()` → `getCacheStats()` (backward compatible)
|
|
14
|
+
- **Enhanced Metrics**: Changed `lazyModeEnabled: boolean` → `cachingStrategy: 'preloaded' | 'on-demand'`
|
|
15
|
+
- **Improved Thresholds**: Updated preloading threshold from 30% to 80% for better cache utilization
|
|
16
|
+
- **Better Terminology**: Eliminated "lazy mode" concept in favor of "adaptive caching strategy"
|
|
17
|
+
- **Production Monitoring**: Comprehensive diagnostics for capacity planning and tuning
|
|
18
|
+
|
|
19
|
+
#### Benefits
|
|
20
|
+
|
|
21
|
+
- ✅ **Clearer Semantics**: "preloaded" vs "on-demand" instead of confusing "lazy mode enabled/disabled"
|
|
22
|
+
- ✅ **Better Cache Utilization**: 80% threshold maximizes memory usage before switching to on-demand
|
|
23
|
+
- ✅ **Enhanced Monitoring**: `getCacheStats()` provides actionable insights for production deployments
|
|
24
|
+
- ✅ **Backward Compatible**: Deprecated `lazy` option still accepted (ignored, always adaptive)
|
|
25
|
+
- ✅ **Zero Config**: System automatically chooses optimal strategy based on dataset size and available memory
|
|
26
|
+
|
|
27
|
+
#### API Changes
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
// New API (recommended)
|
|
31
|
+
const stats = brain.hnsw.getCacheStats()
|
|
32
|
+
console.log(`Strategy: ${stats.cachingStrategy}`) // 'preloaded' or 'on-demand'
|
|
33
|
+
console.log(`Hit Rate: ${stats.unifiedCache.hitRatePercent}%`)
|
|
34
|
+
console.log(`Recommendations: ${stats.recommendations.join(', ')}`)
|
|
35
|
+
|
|
36
|
+
// Old API (deprecated but still works)
|
|
37
|
+
const oldStats = brain.hnsw.getLazyModeStats() // Returns same data
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
#### Documentation Updates
|
|
41
|
+
|
|
42
|
+
- Added comprehensive migration guide: `docs/guides/migration-3.36.0.md`
|
|
43
|
+
- Added operations guide: `docs/operations/capacity-planning.md`
|
|
44
|
+
- Updated architecture docs with new terminology
|
|
45
|
+
- Renamed example: `monitor-lazy-mode.ts` → `monitor-cache-performance.ts`
|
|
46
|
+
|
|
47
|
+
#### Files Changed
|
|
48
|
+
|
|
49
|
+
- `src/hnsw/hnswIndex.ts`: Core adaptive caching improvements
|
|
50
|
+
- `src/interfaces/IIndex.ts`: Updated interface documentation
|
|
51
|
+
- `docs/guides/migration-3.36.0.md`: Complete migration guide
|
|
52
|
+
- `docs/operations/capacity-planning.md`: Enterprise operations guide
|
|
53
|
+
- `examples/monitor-cache-performance.ts`: Production monitoring example
|
|
54
|
+
- All documentation updated to reflect new terminology
|
|
55
|
+
|
|
56
|
+
#### Migration
|
|
57
|
+
|
|
58
|
+
**No action required!** All changes are backward compatible. Update your code to use `getCacheStats()` when convenient.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
### [3.35.0](https://github.com/soulcraftlabs/brainy/compare/v3.34.0...v3.35.0) (2025-10-10)
|
|
63
|
+
|
|
64
|
+
- feat: implement HNSW index rebuild and unified index interface (6a4d1ae)
|
|
65
|
+
- cleaning up (12d78ba)
|
|
66
|
+
|
|
67
|
+
|
|
5
68
|
### [3.34.0](https://github.com/soulcraftlabs/brainy/compare/v3.33.0...v3.34.0) (2025-10-09)
|
|
6
69
|
|
|
7
70
|
- test: adjust type-matching tests for real embeddings (v3.33.0) (1c5c77e)
|
package/README.md
CHANGED
|
@@ -19,6 +19,32 @@
|
|
|
19
19
|
|
|
20
20
|
## 🎉 Key Features
|
|
21
21
|
|
|
22
|
+
### ⚡ **NEW in 3.36.0: Production-Scale Memory & Performance**
|
|
23
|
+
|
|
24
|
+
**Enterprise-grade adaptive sizing and zero-overhead optimizations:**
|
|
25
|
+
|
|
26
|
+
- **🎯 Adaptive Memory Sizing**: Auto-scales from 2GB to 128GB+ based on available system resources
|
|
27
|
+
- Container-aware (Docker/K8s cgroups v1/v2 detection)
|
|
28
|
+
- Environment-smart (development 25%, container 40%, production 50% allocation)
|
|
29
|
+
- Model memory accounting (150MB Q8, 250MB FP32 reserved before cache)
|
|
30
|
+
|
|
31
|
+
- **⚡ Sync Fast Path**: Zero async overhead when vectors are cached
|
|
32
|
+
- Intelligent sync/async branching - synchronous when data is in memory
|
|
33
|
+
- Falls back to async only when loading from storage
|
|
34
|
+
- Massive performance win for hot paths (vector search, distance calculations)
|
|
35
|
+
|
|
36
|
+
- **📊 Production Monitoring**: Comprehensive diagnostics
|
|
37
|
+
- `getCacheStats()` - UnifiedCache hit rates, fairness metrics, memory pressure
|
|
38
|
+
- Actionable recommendations for tuning
|
|
39
|
+
- Tracks model memory, cache efficiency, and competition across indexes
|
|
40
|
+
|
|
41
|
+
- **🛡️ Zero Breaking Changes**: All optimizations are internal - your code stays the same
|
|
42
|
+
- Public API unchanged
|
|
43
|
+
- Automatic memory detection and allocation
|
|
44
|
+
- Progressive enhancement for existing applications
|
|
45
|
+
|
|
46
|
+
**[📖 Operations Guide →](docs/operations/capacity-planning.md)** | **[🎯 Migration Guide →](docs/guides/migration-3.36.0.md)**
|
|
47
|
+
|
|
22
48
|
### 🚀 **NEW in 3.21.0: Enhanced Import & Neural Processing**
|
|
23
49
|
|
|
24
50
|
- **📊 Progress Tracking**: Unified progress reporting with automatic time estimation
|
|
@@ -38,7 +64,7 @@
|
|
|
38
64
|
|
|
39
65
|
- **Modern Syntax**: `brain.add()`, `brain.find()`, `brain.relate()`
|
|
40
66
|
- **Type Safety**: Full TypeScript integration
|
|
41
|
-
- **Zero Config**: Works out of the box with
|
|
67
|
+
- **Zero Config**: Works out of the box with intelligent storage auto-detection
|
|
42
68
|
- **Consistent Parameters**: Clean, predictable API surface
|
|
43
69
|
|
|
44
70
|
### ⚡ **Performance & Reliability**
|
|
@@ -352,7 +378,7 @@ const brain = new Brainy()
|
|
|
352
378
|
|
|
353
379
|
// 2. Custom configuration
|
|
354
380
|
const brain = new Brainy({
|
|
355
|
-
storage: { type: '
|
|
381
|
+
storage: { type: 'filesystem', path: './brainy-data' },
|
|
356
382
|
embeddings: { model: 'all-MiniLM-L6-v2' },
|
|
357
383
|
cache: { enabled: true, maxSize: 1000 }
|
|
358
384
|
})
|
|
@@ -368,7 +394,7 @@ const customBrain = new Brainy({
|
|
|
368
394
|
|
|
369
395
|
**What's Auto-Detected:**
|
|
370
396
|
|
|
371
|
-
- **Storage**: S3/GCS/R2 → Filesystem
|
|
397
|
+
- **Storage**: S3/GCS/R2 → Filesystem (priority order)
|
|
372
398
|
- **Models**: Always Q8 for optimal balance
|
|
373
399
|
- **Features**: Minimal → Default → Full based on environment
|
|
374
400
|
- **Memory**: Optimal cache sizes and batching
|
|
@@ -390,13 +416,12 @@ Most users **never need this** - zero-config handles everything. For advanced us
|
|
|
390
416
|
const brain = new Brainy() // Uses Q8 automatically
|
|
391
417
|
|
|
392
418
|
// Storage control (auto-detected by default)
|
|
393
|
-
const
|
|
394
|
-
const diskBrain = new Brainy({storage: 'disk'}) // Local filesystem
|
|
419
|
+
const diskBrain = new Brainy({storage: 'disk'}) // Local filesystem
|
|
395
420
|
const cloudBrain = new Brainy({storage: 'cloud'}) // S3/GCS/R2
|
|
396
421
|
|
|
397
422
|
// Legacy full config (still supported)
|
|
398
423
|
const legacyBrain = new Brainy({
|
|
399
|
-
storage: {
|
|
424
|
+
storage: {type: 'filesystem', path: './data'}
|
|
400
425
|
})
|
|
401
426
|
```
|
|
402
427
|
|
|
@@ -665,12 +690,7 @@ const context = await brain.find({
|
|
|
665
690
|
Brainy supports multiple storage backends:
|
|
666
691
|
|
|
667
692
|
```javascript
|
|
668
|
-
//
|
|
669
|
-
const brain = new Brainy({
|
|
670
|
-
storage: {type: 'memory'}
|
|
671
|
-
})
|
|
672
|
-
|
|
673
|
-
// FileSystem (Node.js)
|
|
693
|
+
// FileSystem (Node.js - recommended for development)
|
|
674
694
|
const brain = new Brainy({
|
|
675
695
|
storage: {
|
|
676
696
|
type: 'filesystem',
|
package/dist/brainy.d.ts
CHANGED
|
@@ -1070,6 +1070,21 @@ export declare class Brainy<T = any> implements BrainyInterface<T> {
|
|
|
1070
1070
|
/**
|
|
1071
1071
|
* Rebuild indexes if there's existing data but empty indexes
|
|
1072
1072
|
*/
|
|
1073
|
+
/**
|
|
1074
|
+
* Rebuild indexes from persisted data if needed (v3.35.0+)
|
|
1075
|
+
*
|
|
1076
|
+
* FIXES FOR CRITICAL BUGS:
|
|
1077
|
+
* - Bug #1: GraphAdjacencyIndex rebuild never called ✅ FIXED
|
|
1078
|
+
* - Bug #2: Early return blocks recovery when count=0 ✅ FIXED
|
|
1079
|
+
* - Bug #4: HNSW index has no rebuild mechanism ✅ FIXED
|
|
1080
|
+
*
|
|
1081
|
+
* Production-grade rebuild with:
|
|
1082
|
+
* - Handles millions of entities via pagination
|
|
1083
|
+
* - Smart threshold-based decisions (auto-rebuild < 1000 items)
|
|
1084
|
+
* - Progress reporting for large datasets
|
|
1085
|
+
* - Parallel index rebuilds for performance
|
|
1086
|
+
* - Robust error recovery (continues on partial failures)
|
|
1087
|
+
*/
|
|
1073
1088
|
private rebuildIndexesIfNeeded;
|
|
1074
1089
|
/**
|
|
1075
1090
|
* Close and cleanup
|
package/dist/brainy.js
CHANGED
|
@@ -2385,59 +2385,88 @@ export class Brainy {
|
|
|
2385
2385
|
/**
|
|
2386
2386
|
* Rebuild indexes if there's existing data but empty indexes
|
|
2387
2387
|
*/
|
|
2388
|
+
/**
|
|
2389
|
+
* Rebuild indexes from persisted data if needed (v3.35.0+)
|
|
2390
|
+
*
|
|
2391
|
+
* FIXES FOR CRITICAL BUGS:
|
|
2392
|
+
* - Bug #1: GraphAdjacencyIndex rebuild never called ✅ FIXED
|
|
2393
|
+
* - Bug #2: Early return blocks recovery when count=0 ✅ FIXED
|
|
2394
|
+
* - Bug #4: HNSW index has no rebuild mechanism ✅ FIXED
|
|
2395
|
+
*
|
|
2396
|
+
* Production-grade rebuild with:
|
|
2397
|
+
* - Handles millions of entities via pagination
|
|
2398
|
+
* - Smart threshold-based decisions (auto-rebuild < 1000 items)
|
|
2399
|
+
* - Progress reporting for large datasets
|
|
2400
|
+
* - Parallel index rebuilds for performance
|
|
2401
|
+
* - Robust error recovery (continues on partial failures)
|
|
2402
|
+
*/
|
|
2388
2403
|
async rebuildIndexesIfNeeded() {
|
|
2389
2404
|
try {
|
|
2390
|
-
// Check if
|
|
2405
|
+
// Check if auto-rebuild is explicitly disabled
|
|
2406
|
+
if (this.config.disableAutoRebuild === true) {
|
|
2407
|
+
if (!this.config.silent) {
|
|
2408
|
+
console.log('⚡ Auto-rebuild explicitly disabled via config');
|
|
2409
|
+
}
|
|
2410
|
+
return;
|
|
2411
|
+
}
|
|
2412
|
+
// BUG #2 FIX: Don't trust counts - check actual storage instead
|
|
2413
|
+
// Counts can be lost/corrupted in container restarts
|
|
2391
2414
|
const entities = await this.storage.getNouns({ pagination: { limit: 1 } });
|
|
2392
2415
|
const totalCount = entities.totalCount || 0;
|
|
2393
|
-
|
|
2394
|
-
|
|
2416
|
+
// If storage is truly empty, no rebuild needed
|
|
2417
|
+
if (totalCount === 0 && entities.items.length === 0) {
|
|
2395
2418
|
return;
|
|
2396
2419
|
}
|
|
2397
2420
|
// Intelligent decision: Auto-rebuild only for small datasets
|
|
2398
2421
|
// For large datasets, use lazy loading for optimal performance
|
|
2399
2422
|
const AUTO_REBUILD_THRESHOLD = 1000; // Only auto-rebuild if < 1000 items
|
|
2400
|
-
// Check if
|
|
2423
|
+
// Check if indexes need rebuilding
|
|
2401
2424
|
const metadataStats = await this.metadataIndex.getStats();
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
console.log(`✅ Index rebuilt: ${newStats.totalEntries} entries`);
|
|
2412
|
-
}
|
|
2413
|
-
}
|
|
2414
|
-
else {
|
|
2415
|
-
// Large dataset - use lazy loading
|
|
2416
|
-
if (!this.config.silent) {
|
|
2417
|
-
console.log(`⚡ Large dataset (${totalCount} items) - using lazy loading for optimal startup performance`);
|
|
2418
|
-
console.log('💡 Tip: Indexes will build automatically as you use the system');
|
|
2419
|
-
}
|
|
2420
|
-
}
|
|
2425
|
+
const hnswIndexSize = this.index.size();
|
|
2426
|
+
const graphIndexSize = await this.graphIndex.size();
|
|
2427
|
+
const needsRebuild = metadataStats.totalEntries === 0 ||
|
|
2428
|
+
hnswIndexSize === 0 ||
|
|
2429
|
+
graphIndexSize === 0 ||
|
|
2430
|
+
this.config.disableAutoRebuild === false; // Explicitly enabled
|
|
2431
|
+
if (!needsRebuild) {
|
|
2432
|
+
// All indexes populated, no rebuild needed
|
|
2433
|
+
return;
|
|
2421
2434
|
}
|
|
2422
|
-
//
|
|
2423
|
-
if (this.config.disableAutoRebuild ===
|
|
2435
|
+
// Small dataset: Rebuild all indexes for best performance
|
|
2436
|
+
if (totalCount < AUTO_REBUILD_THRESHOLD || this.config.disableAutoRebuild === false) {
|
|
2424
2437
|
if (!this.config.silent) {
|
|
2425
|
-
console.log(
|
|
2438
|
+
console.log(this.config.disableAutoRebuild === false
|
|
2439
|
+
? '🔄 Auto-rebuild explicitly enabled - rebuilding all indexes...'
|
|
2440
|
+
: `🔄 Small dataset (${totalCount} items) - rebuilding all indexes...`);
|
|
2441
|
+
}
|
|
2442
|
+
// BUG #1 FIX: Actually call graphIndex.rebuild()
|
|
2443
|
+
// BUG #4 FIX: Actually call HNSW index.rebuild()
|
|
2444
|
+
// Rebuild all 3 indexes in parallel for performance
|
|
2445
|
+
const startTime = Date.now();
|
|
2446
|
+
await Promise.all([
|
|
2447
|
+
metadataStats.totalEntries === 0 ? this.metadataIndex.rebuild() : Promise.resolve(),
|
|
2448
|
+
hnswIndexSize === 0 ? this.index.rebuild() : Promise.resolve(),
|
|
2449
|
+
graphIndexSize === 0 ? this.graphIndex.rebuild() : Promise.resolve()
|
|
2450
|
+
]);
|
|
2451
|
+
const duration = Date.now() - startTime;
|
|
2452
|
+
if (!this.config.silent) {
|
|
2453
|
+
console.log(`✅ All indexes rebuilt in ${duration}ms:\n` +
|
|
2454
|
+
` - Metadata: ${await this.metadataIndex.getStats().then(s => s.totalEntries)} entries\n` +
|
|
2455
|
+
` - HNSW Vector: ${this.index.size()} nodes\n` +
|
|
2456
|
+
` - Graph Adjacency: ${await this.graphIndex.size()} relationships`);
|
|
2426
2457
|
}
|
|
2427
|
-
return;
|
|
2428
2458
|
}
|
|
2429
|
-
else
|
|
2430
|
-
//
|
|
2459
|
+
else {
|
|
2460
|
+
// Large dataset: Use lazy loading for fast startup
|
|
2431
2461
|
if (!this.config.silent) {
|
|
2432
|
-
console.log(
|
|
2462
|
+
console.log(`⚡ Large dataset (${totalCount} items) - using lazy loading for optimal startup`);
|
|
2463
|
+
console.log('💡 Indexes will build automatically as you query the system');
|
|
2433
2464
|
}
|
|
2434
|
-
await this.metadataIndex.rebuild();
|
|
2435
2465
|
}
|
|
2436
|
-
// Note: GraphAdjacencyIndex will rebuild itself as relationships are added
|
|
2437
|
-
// Vector index should already be populated if storage has data
|
|
2438
2466
|
}
|
|
2439
2467
|
catch (error) {
|
|
2440
|
-
console.warn('Warning: Could not
|
|
2468
|
+
console.warn('Warning: Could not rebuild indexes:', error);
|
|
2469
|
+
// Don't throw - allow system to start even if rebuild fails
|
|
2441
2470
|
}
|
|
2442
2471
|
}
|
|
2443
2472
|
/**
|
package/dist/hnsw/hnswIndex.d.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Based on the paper: "Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs"
|
|
4
4
|
*/
|
|
5
5
|
import { DistanceFunction, HNSWConfig, HNSWNoun, Vector, VectorDocument } from '../coreTypes.js';
|
|
6
|
+
import type { BaseStorage } from '../storage/baseStorage.js';
|
|
6
7
|
export declare class HNSWIndex {
|
|
7
8
|
private nouns;
|
|
8
9
|
private entryPointId;
|
|
@@ -13,8 +14,11 @@ export declare class HNSWIndex {
|
|
|
13
14
|
private distanceFunction;
|
|
14
15
|
private dimension;
|
|
15
16
|
private useParallelization;
|
|
17
|
+
private storage;
|
|
18
|
+
private unifiedCache;
|
|
16
19
|
constructor(config?: Partial<HNSWConfig>, distanceFunction?: DistanceFunction, options?: {
|
|
17
20
|
useParallelization?: boolean;
|
|
21
|
+
storage?: BaseStorage;
|
|
18
22
|
});
|
|
19
23
|
/**
|
|
20
24
|
* Set whether to use parallelization for performance-critical operations
|
|
@@ -45,7 +49,7 @@ export declare class HNSWIndex {
|
|
|
45
49
|
/**
|
|
46
50
|
* Remove an item from the index
|
|
47
51
|
*/
|
|
48
|
-
removeItem(id: string): boolean
|
|
52
|
+
removeItem(id: string): Promise<boolean>;
|
|
49
53
|
/**
|
|
50
54
|
* Get all nouns in the index
|
|
51
55
|
* @deprecated Use getNounsPaginated() instead for better scalability
|
|
@@ -93,11 +97,86 @@ export declare class HNSWIndex {
|
|
|
93
97
|
* Get the configuration
|
|
94
98
|
*/
|
|
95
99
|
getConfig(): HNSWConfig;
|
|
100
|
+
/**
|
|
101
|
+
* Get vector safely (always uses adaptive caching via UnifiedCache)
|
|
102
|
+
*
|
|
103
|
+
* Production-grade adaptive caching (v3.36.0+):
|
|
104
|
+
* - Vector already loaded: Returns immediately (O(1))
|
|
105
|
+
* - Vector in cache: Loads from UnifiedCache (O(1) hash lookup)
|
|
106
|
+
* - Vector on disk: Loads from storage → UnifiedCache (O(disk))
|
|
107
|
+
* - Cost-aware caching: UnifiedCache manages memory competition
|
|
108
|
+
*
|
|
109
|
+
* @param noun The HNSW noun (may have empty vector if not yet loaded)
|
|
110
|
+
* @returns Promise<Vector> The vector (loaded on-demand if needed)
|
|
111
|
+
*/
|
|
112
|
+
private getVectorSafe;
|
|
113
|
+
/**
|
|
114
|
+
* Get vector synchronously if available in memory (v3.36.0+)
|
|
115
|
+
*
|
|
116
|
+
* Sync fast path optimization:
|
|
117
|
+
* - Vector in memory: Returns immediately (zero overhead)
|
|
118
|
+
* - Vector in cache: Returns from UnifiedCache synchronously
|
|
119
|
+
* - Returns null if vector not available (caller must handle async path)
|
|
120
|
+
*
|
|
121
|
+
* Use for sync fast path in distance calculations - eliminates async overhead
|
|
122
|
+
* when vectors are already cached.
|
|
123
|
+
*
|
|
124
|
+
* @param noun The HNSW noun
|
|
125
|
+
* @returns Vector | null - vector if in memory/cache, null if needs async load
|
|
126
|
+
*/
|
|
127
|
+
private getVectorSync;
|
|
128
|
+
/**
|
|
129
|
+
* Preload multiple vectors in parallel via UnifiedCache
|
|
130
|
+
*
|
|
131
|
+
* Optimization for search operations:
|
|
132
|
+
* - Loads all candidate vectors before distance calculations
|
|
133
|
+
* - Reduces serial disk I/O (parallel loads are faster)
|
|
134
|
+
* - Uses UnifiedCache's request coalescing to prevent stampede
|
|
135
|
+
* - Always active (no "mode" check) for optimal performance
|
|
136
|
+
*
|
|
137
|
+
* @param nodeIds Array of node IDs to preload
|
|
138
|
+
*/
|
|
139
|
+
private preloadVectors;
|
|
140
|
+
/**
|
|
141
|
+
* Calculate distance with sync fast path (v3.36.0+)
|
|
142
|
+
*
|
|
143
|
+
* Eliminates async overhead when vectors are in memory:
|
|
144
|
+
* - Sync path: Vector in memory → returns number (zero overhead)
|
|
145
|
+
* - Async path: Vector needs loading → returns Promise<number>
|
|
146
|
+
*
|
|
147
|
+
* Callers must handle union type: `const dist = await Promise.resolve(distance)`
|
|
148
|
+
*
|
|
149
|
+
* @param queryVector The query vector
|
|
150
|
+
* @param noun The target noun (may have empty vector in lazy mode)
|
|
151
|
+
* @returns number | Promise<number> - sync when cached, async when needs load
|
|
152
|
+
*/
|
|
153
|
+
private distanceSafe;
|
|
96
154
|
/**
|
|
97
155
|
* Get all nodes at a specific level for clustering
|
|
98
156
|
* This enables O(n) clustering using HNSW's natural hierarchy
|
|
99
157
|
*/
|
|
100
158
|
getNodesAtLevel(level: number): HNSWNoun[];
|
|
159
|
+
/**
|
|
160
|
+
* Rebuild HNSW index from persisted graph data (v3.35.0+)
|
|
161
|
+
*
|
|
162
|
+
* This is a production-grade O(N) rebuild that restores the pre-computed graph structure
|
|
163
|
+
* from storage. Much faster than re-building which is O(N log N).
|
|
164
|
+
*
|
|
165
|
+
* Designed for millions of entities with:
|
|
166
|
+
* - Cursor-based pagination (no memory overflow)
|
|
167
|
+
* - Batch processing (configurable batch size)
|
|
168
|
+
* - Progress reporting (optional callback)
|
|
169
|
+
* - Error recovery (continues on partial failures)
|
|
170
|
+
* - Lazy mode support (memory-efficient for constrained environments)
|
|
171
|
+
*
|
|
172
|
+
* @param options Rebuild options
|
|
173
|
+
* @returns Promise that resolves when rebuild is complete
|
|
174
|
+
*/
|
|
175
|
+
rebuild(options?: {
|
|
176
|
+
lazy?: boolean;
|
|
177
|
+
batchSize?: number;
|
|
178
|
+
onProgress?: (loaded: number, total: number) => void;
|
|
179
|
+
}): Promise<void>;
|
|
101
180
|
/**
|
|
102
181
|
* Get level statistics for understanding the hierarchy
|
|
103
182
|
*/
|
|
@@ -115,6 +194,54 @@ export declare class HNSWIndex {
|
|
|
115
194
|
maxLayer: number;
|
|
116
195
|
totalNodes: number;
|
|
117
196
|
};
|
|
197
|
+
/**
|
|
198
|
+
* Get cache performance statistics for monitoring and diagnostics (v3.36.0+)
|
|
199
|
+
*
|
|
200
|
+
* Production-grade monitoring:
|
|
201
|
+
* - Adaptive caching strategy (preloading vs on-demand)
|
|
202
|
+
* - UnifiedCache performance (hits, misses, evictions)
|
|
203
|
+
* - HNSW-specific cache statistics
|
|
204
|
+
* - Fair competition metrics across all indexes
|
|
205
|
+
* - Actionable recommendations for tuning
|
|
206
|
+
*
|
|
207
|
+
* Use this to:
|
|
208
|
+
* - Diagnose performance issues (low hit rate = increase cache)
|
|
209
|
+
* - Monitor memory competition (fairness violations = adjust costs)
|
|
210
|
+
* - Verify adaptive caching decisions (memory estimates vs actual)
|
|
211
|
+
* - Track cache efficiency over time
|
|
212
|
+
*
|
|
213
|
+
* @returns Comprehensive caching and performance statistics
|
|
214
|
+
*/
|
|
215
|
+
getCacheStats(): {
|
|
216
|
+
cachingStrategy: 'preloaded' | 'on-demand';
|
|
217
|
+
autoDetection: {
|
|
218
|
+
entityCount: number;
|
|
219
|
+
estimatedVectorMemoryMB: number;
|
|
220
|
+
availableCacheMB: number;
|
|
221
|
+
threshold: number;
|
|
222
|
+
rationale: string;
|
|
223
|
+
};
|
|
224
|
+
unifiedCache: {
|
|
225
|
+
totalSize: number;
|
|
226
|
+
maxSize: number;
|
|
227
|
+
utilizationPercent: number;
|
|
228
|
+
itemCount: number;
|
|
229
|
+
hitRatePercent: number;
|
|
230
|
+
totalAccessCount: number;
|
|
231
|
+
};
|
|
232
|
+
hnswCache: {
|
|
233
|
+
vectorsInCache: number;
|
|
234
|
+
cacheKeyPrefix: string;
|
|
235
|
+
estimatedMemoryMB: number;
|
|
236
|
+
};
|
|
237
|
+
fairness: {
|
|
238
|
+
hnswAccessCount: number;
|
|
239
|
+
hnswAccessPercent: number;
|
|
240
|
+
totalAccessCount: number;
|
|
241
|
+
fairnessViolation: boolean;
|
|
242
|
+
};
|
|
243
|
+
recommendations: string[];
|
|
244
|
+
};
|
|
118
245
|
/**
|
|
119
246
|
* Search within a specific layer
|
|
120
247
|
* Returns a map of noun IDs to distances, sorted by distance
|