@soulcraft/brainy 0.48.0 → 0.49.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/README.md +268 -554
- package/dist/brainyData.d.ts +83 -2
- package/dist/brainyData.js +536 -66
- package/dist/brainyData.js.map +1 -1
- package/dist/coreTypes.d.ts +74 -12
- package/dist/distributed/configManager.d.ts +9 -0
- package/dist/distributed/configManager.js +129 -10
- package/dist/distributed/configManager.js.map +1 -1
- package/dist/hnsw/hnswIndex.d.ts +1 -1
- package/dist/hnsw/hnswIndex.js +44 -25
- package/dist/hnsw/hnswIndex.js.map +1 -1
- package/dist/hnsw/optimizedHNSWIndex.d.ts +1 -1
- package/dist/hnsw/optimizedHNSWIndex.js +3 -3
- package/dist/hnsw/optimizedHNSWIndex.js.map +1 -1
- package/dist/storage/adapters/baseStorageAdapter.d.ts +18 -2
- package/dist/storage/adapters/baseStorageAdapter.js +69 -4
- package/dist/storage/adapters/baseStorageAdapter.js.map +1 -1
- package/dist/storage/adapters/fileSystemStorage.d.ts +14 -8
- package/dist/storage/adapters/fileSystemStorage.js +90 -22
- package/dist/storage/adapters/fileSystemStorage.js.map +1 -1
- package/dist/storage/adapters/memoryStorage.d.ts +0 -8
- package/dist/storage/adapters/memoryStorage.js +26 -45
- package/dist/storage/adapters/memoryStorage.js.map +1 -1
- package/dist/storage/adapters/opfsStorage.d.ts +40 -8
- package/dist/storage/adapters/opfsStorage.js +195 -44
- package/dist/storage/adapters/opfsStorage.js.map +1 -1
- package/dist/storage/adapters/optimizedS3Search.js +4 -3
- package/dist/storage/adapters/optimizedS3Search.js.map +1 -1
- package/dist/storage/adapters/s3CompatibleStorage.d.ts +3 -10
- package/dist/storage/adapters/s3CompatibleStorage.js +41 -44
- package/dist/storage/adapters/s3CompatibleStorage.js.map +1 -1
- package/dist/storage/backwardCompatibility.d.ts +84 -0
- package/dist/storage/backwardCompatibility.js +141 -0
- package/dist/storage/backwardCompatibility.js.map +1 -0
- package/dist/storage/baseStorage.d.ts +33 -19
- package/dist/storage/baseStorage.js +116 -195
- package/dist/storage/baseStorage.js.map +1 -1
- package/dist/utils/metadataFilter.d.ts +79 -0
- package/dist/utils/metadataFilter.js +229 -0
- package/dist/utils/metadataFilter.js.map +1 -0
- package/dist/utils/metadataIndex.d.ts +148 -0
- package/dist/utils/metadataIndex.js +639 -0
- package/dist/utils/metadataIndex.js.map +1 -0
- package/dist/utils/metadataIndexCache.d.ts +60 -0
- package/dist/utils/metadataIndexCache.js +119 -0
- package/dist/utils/metadataIndexCache.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart metadata filtering for vector search
|
|
3
|
+
* Filters DURING search to ensure relevant results
|
|
4
|
+
* Simple API that just works without configuration
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Check if a value matches a query with operators
|
|
8
|
+
*/
|
|
9
|
+
function matchesQuery(value, query) {
|
|
10
|
+
// Direct equality check
|
|
11
|
+
if (typeof query !== 'object' || query === null || Array.isArray(query)) {
|
|
12
|
+
return value === query;
|
|
13
|
+
}
|
|
14
|
+
// Check for MongoDB-style operators
|
|
15
|
+
for (const [op, operand] of Object.entries(query)) {
|
|
16
|
+
switch (op) {
|
|
17
|
+
case '$eq':
|
|
18
|
+
if (value !== operand)
|
|
19
|
+
return false;
|
|
20
|
+
break;
|
|
21
|
+
case '$ne':
|
|
22
|
+
if (value === operand)
|
|
23
|
+
return false;
|
|
24
|
+
break;
|
|
25
|
+
case '$gt':
|
|
26
|
+
if (typeof value !== 'number' || typeof operand !== 'number' || !(value > operand))
|
|
27
|
+
return false;
|
|
28
|
+
break;
|
|
29
|
+
case '$gte':
|
|
30
|
+
if (typeof value !== 'number' || typeof operand !== 'number' || !(value >= operand))
|
|
31
|
+
return false;
|
|
32
|
+
break;
|
|
33
|
+
case '$lt':
|
|
34
|
+
if (typeof value !== 'number' || typeof operand !== 'number' || !(value < operand))
|
|
35
|
+
return false;
|
|
36
|
+
break;
|
|
37
|
+
case '$lte':
|
|
38
|
+
if (typeof value !== 'number' || typeof operand !== 'number' || !(value <= operand))
|
|
39
|
+
return false;
|
|
40
|
+
break;
|
|
41
|
+
case '$in':
|
|
42
|
+
if (!Array.isArray(operand) || !operand.includes(value))
|
|
43
|
+
return false;
|
|
44
|
+
break;
|
|
45
|
+
case '$nin':
|
|
46
|
+
if (!Array.isArray(operand) || operand.includes(value))
|
|
47
|
+
return false;
|
|
48
|
+
break;
|
|
49
|
+
case '$exists':
|
|
50
|
+
if ((value !== undefined) !== operand)
|
|
51
|
+
return false;
|
|
52
|
+
break;
|
|
53
|
+
case '$regex':
|
|
54
|
+
const regex = typeof operand === 'string' ? new RegExp(operand) : operand;
|
|
55
|
+
if (!(regex instanceof RegExp) || !regex.test(String(value)))
|
|
56
|
+
return false;
|
|
57
|
+
break;
|
|
58
|
+
case '$includes':
|
|
59
|
+
if (!Array.isArray(value) || !value.includes(operand))
|
|
60
|
+
return false;
|
|
61
|
+
break;
|
|
62
|
+
case '$all':
|
|
63
|
+
if (!Array.isArray(value) || !Array.isArray(operand))
|
|
64
|
+
return false;
|
|
65
|
+
for (const item of operand) {
|
|
66
|
+
if (!value.includes(item))
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
break;
|
|
70
|
+
case '$size':
|
|
71
|
+
if (!Array.isArray(value) || value.length !== operand)
|
|
72
|
+
return false;
|
|
73
|
+
break;
|
|
74
|
+
default:
|
|
75
|
+
// Unknown operator, treat as field name
|
|
76
|
+
if (!matchesFieldQuery(value, op, operand))
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Check if a field matches a query
|
|
84
|
+
*/
|
|
85
|
+
function matchesFieldQuery(obj, field, query) {
|
|
86
|
+
const value = getNestedValue(obj, field);
|
|
87
|
+
return matchesQuery(value, query);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Get nested value from object using dot notation
|
|
91
|
+
*/
|
|
92
|
+
function getNestedValue(obj, path) {
|
|
93
|
+
const parts = path.split('.');
|
|
94
|
+
let current = obj;
|
|
95
|
+
for (const part of parts) {
|
|
96
|
+
if (current === null || current === undefined) {
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
current = current[part];
|
|
100
|
+
}
|
|
101
|
+
return current;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Check if metadata matches the filter
|
|
105
|
+
*/
|
|
106
|
+
export function matchesMetadataFilter(metadata, filter) {
|
|
107
|
+
if (!filter || Object.keys(filter).length === 0) {
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
for (const [key, query] of Object.entries(filter)) {
|
|
111
|
+
// Handle logical operators
|
|
112
|
+
if (key === '$and') {
|
|
113
|
+
if (!Array.isArray(query))
|
|
114
|
+
return false;
|
|
115
|
+
for (const subFilter of query) {
|
|
116
|
+
if (!matchesMetadataFilter(metadata, subFilter))
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (key === '$or') {
|
|
122
|
+
if (!Array.isArray(query))
|
|
123
|
+
return false;
|
|
124
|
+
let matched = false;
|
|
125
|
+
for (const subFilter of query) {
|
|
126
|
+
if (matchesMetadataFilter(metadata, subFilter)) {
|
|
127
|
+
matched = true;
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (!matched)
|
|
132
|
+
return false;
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (key === '$not') {
|
|
136
|
+
if (matchesMetadataFilter(metadata, query))
|
|
137
|
+
return false;
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
// Handle field queries
|
|
141
|
+
const value = getNestedValue(metadata, key);
|
|
142
|
+
if (!matchesQuery(value, query)) {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Calculate metadata boost score
|
|
150
|
+
*/
|
|
151
|
+
export function calculateMetadataScore(metadata, filter, scoring) {
|
|
152
|
+
if (!scoring || !scoring.metadataBoosts) {
|
|
153
|
+
return 0;
|
|
154
|
+
}
|
|
155
|
+
let score = 0;
|
|
156
|
+
for (const [field, boost] of Object.entries(scoring.metadataBoosts)) {
|
|
157
|
+
const value = getNestedValue(metadata, field);
|
|
158
|
+
if (typeof boost === 'function') {
|
|
159
|
+
score += boost(value, filter);
|
|
160
|
+
}
|
|
161
|
+
else if (value !== undefined) {
|
|
162
|
+
// Check if the field matches the filter
|
|
163
|
+
const fieldFilter = filter[field];
|
|
164
|
+
if (fieldFilter && matchesQuery(value, fieldFilter)) {
|
|
165
|
+
score += boost;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return score;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Apply compound scoring to search results
|
|
173
|
+
*/
|
|
174
|
+
export function applyCompoundScoring(results, filter, scoring) {
|
|
175
|
+
if (!scoring || (!scoring.vectorWeight && !scoring.metadataWeight)) {
|
|
176
|
+
return results;
|
|
177
|
+
}
|
|
178
|
+
const vectorWeight = scoring.vectorWeight ?? 1.0;
|
|
179
|
+
const metadataWeight = scoring.metadataWeight ?? 0.0;
|
|
180
|
+
return results.map(result => {
|
|
181
|
+
const metadataScore = calculateMetadataScore(result.metadata, filter, scoring);
|
|
182
|
+
const combinedScore = (result.score * vectorWeight) + (metadataScore * metadataWeight);
|
|
183
|
+
return {
|
|
184
|
+
...result,
|
|
185
|
+
score: combinedScore
|
|
186
|
+
};
|
|
187
|
+
}).sort((a, b) => b.score - a.score); // Re-sort by combined score
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Filter search results by metadata
|
|
191
|
+
*/
|
|
192
|
+
export function filterSearchResultsByMetadata(results, filter) {
|
|
193
|
+
if (!filter || Object.keys(filter).length === 0) {
|
|
194
|
+
return results;
|
|
195
|
+
}
|
|
196
|
+
return results.filter(result => matchesMetadataFilter(result.metadata, filter));
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Filter nouns by metadata before search
|
|
200
|
+
*/
|
|
201
|
+
export function filterNounsByMetadata(nouns, filter) {
|
|
202
|
+
if (!filter || Object.keys(filter).length === 0) {
|
|
203
|
+
return nouns;
|
|
204
|
+
}
|
|
205
|
+
return nouns.filter(noun => matchesMetadataFilter(noun.metadata, filter));
|
|
206
|
+
}
|
|
207
|
+
export function aggregateSearchResults(results, facets) {
|
|
208
|
+
const facetResults = {};
|
|
209
|
+
for (const [facetName, config] of Object.entries(facets)) {
|
|
210
|
+
const counts = {};
|
|
211
|
+
for (const result of results) {
|
|
212
|
+
const value = getNestedValue(result.metadata, config.field);
|
|
213
|
+
if (value !== undefined) {
|
|
214
|
+
const key = String(value);
|
|
215
|
+
counts[key] = (counts[key] || 0) + 1;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
// Sort by count and apply limit
|
|
219
|
+
const sorted = Object.entries(counts)
|
|
220
|
+
.sort((a, b) => b[1] - a[1])
|
|
221
|
+
.slice(0, config.limit || 10);
|
|
222
|
+
facetResults[facetName] = Object.fromEntries(sorted);
|
|
223
|
+
}
|
|
224
|
+
return {
|
|
225
|
+
results,
|
|
226
|
+
facets: facetResults
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=metadataFilter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadataFilter.js","sourceRoot":"","sources":["../../src/utils/metadataFilter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metadata Index System
|
|
3
|
+
* Maintains inverted indexes for fast metadata filtering
|
|
4
|
+
* Automatically updates indexes when data changes
|
|
5
|
+
*/
|
|
6
|
+
import { StorageAdapter } from '../coreTypes.js';
|
|
7
|
+
export interface MetadataIndexEntry {
|
|
8
|
+
field: string;
|
|
9
|
+
value: string | number | boolean;
|
|
10
|
+
ids: Set<string>;
|
|
11
|
+
lastUpdated: number;
|
|
12
|
+
}
|
|
13
|
+
export interface FieldIndexData {
|
|
14
|
+
values: Record<string, number>;
|
|
15
|
+
lastUpdated: number;
|
|
16
|
+
}
|
|
17
|
+
export interface MetadataIndexStats {
|
|
18
|
+
totalEntries: number;
|
|
19
|
+
totalIds: number;
|
|
20
|
+
fieldsIndexed: string[];
|
|
21
|
+
lastRebuild: number;
|
|
22
|
+
indexSize: number;
|
|
23
|
+
}
|
|
24
|
+
export interface MetadataIndexConfig {
|
|
25
|
+
maxIndexSize?: number;
|
|
26
|
+
rebuildThreshold?: number;
|
|
27
|
+
autoOptimize?: boolean;
|
|
28
|
+
indexedFields?: string[];
|
|
29
|
+
excludeFields?: string[];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Manages metadata indexes for fast filtering
|
|
33
|
+
* Maintains inverted indexes: field+value -> list of IDs
|
|
34
|
+
*/
|
|
35
|
+
export declare class MetadataIndexManager {
|
|
36
|
+
private storage;
|
|
37
|
+
private config;
|
|
38
|
+
private indexCache;
|
|
39
|
+
private dirtyEntries;
|
|
40
|
+
private isRebuilding;
|
|
41
|
+
private metadataCache;
|
|
42
|
+
private fieldIndexes;
|
|
43
|
+
private dirtyFields;
|
|
44
|
+
private lastFlushTime;
|
|
45
|
+
private autoFlushThreshold;
|
|
46
|
+
constructor(storage: StorageAdapter, config?: MetadataIndexConfig);
|
|
47
|
+
/**
|
|
48
|
+
* Get index key for field and value
|
|
49
|
+
*/
|
|
50
|
+
private getIndexKey;
|
|
51
|
+
/**
|
|
52
|
+
* Generate field index filename for filter discovery
|
|
53
|
+
*/
|
|
54
|
+
private getFieldIndexFilename;
|
|
55
|
+
/**
|
|
56
|
+
* Generate value chunk filename for scalable storage
|
|
57
|
+
*/
|
|
58
|
+
private getValueChunkFilename;
|
|
59
|
+
/**
|
|
60
|
+
* Make a value safe for use in filenames
|
|
61
|
+
*/
|
|
62
|
+
private makeSafeFilename;
|
|
63
|
+
/**
|
|
64
|
+
* Normalize value for consistent indexing
|
|
65
|
+
*/
|
|
66
|
+
private normalizeValue;
|
|
67
|
+
/**
|
|
68
|
+
* Create a short hash for long values to avoid filesystem filename limits
|
|
69
|
+
*/
|
|
70
|
+
private hashValue;
|
|
71
|
+
/**
|
|
72
|
+
* Check if field should be indexed
|
|
73
|
+
*/
|
|
74
|
+
private shouldIndexField;
|
|
75
|
+
/**
|
|
76
|
+
* Extract indexable field-value pairs from metadata
|
|
77
|
+
*/
|
|
78
|
+
private extractIndexableFields;
|
|
79
|
+
/**
|
|
80
|
+
* Add item to metadata indexes
|
|
81
|
+
*/
|
|
82
|
+
addToIndex(id: string, metadata: any, skipFlush?: boolean): Promise<void>;
|
|
83
|
+
/**
|
|
84
|
+
* Update field index with value count
|
|
85
|
+
*/
|
|
86
|
+
private updateFieldIndex;
|
|
87
|
+
/**
|
|
88
|
+
* Remove item from metadata indexes
|
|
89
|
+
*/
|
|
90
|
+
removeFromIndex(id: string, metadata?: any): Promise<void>;
|
|
91
|
+
/**
|
|
92
|
+
* Get IDs for a specific field-value combination with caching
|
|
93
|
+
*/
|
|
94
|
+
getIds(field: string, value: any): Promise<string[]>;
|
|
95
|
+
/**
|
|
96
|
+
* Get all available values for a field (for filter discovery)
|
|
97
|
+
*/
|
|
98
|
+
getFilterValues(field: string): Promise<string[]>;
|
|
99
|
+
/**
|
|
100
|
+
* Get all indexed fields (for filter discovery)
|
|
101
|
+
*/
|
|
102
|
+
getFilterFields(): Promise<string[]>;
|
|
103
|
+
/**
|
|
104
|
+
* Convert MongoDB-style filter to simple field-value criteria for indexing
|
|
105
|
+
*/
|
|
106
|
+
private convertFilterToCriteria;
|
|
107
|
+
/**
|
|
108
|
+
* Get IDs matching MongoDB-style metadata filter using indexes where possible
|
|
109
|
+
*/
|
|
110
|
+
getIdsForFilter(filter: any): Promise<string[]>;
|
|
111
|
+
/**
|
|
112
|
+
* Get IDs matching multiple criteria (intersection) - LEGACY METHOD
|
|
113
|
+
* @deprecated Use getIdsForFilter instead
|
|
114
|
+
*/
|
|
115
|
+
getIdsForCriteria(criteria: Record<string, any>): Promise<string[]>;
|
|
116
|
+
/**
|
|
117
|
+
* Flush dirty entries to storage
|
|
118
|
+
*/
|
|
119
|
+
flush(): Promise<void>;
|
|
120
|
+
/**
|
|
121
|
+
* Load field index from storage
|
|
122
|
+
*/
|
|
123
|
+
private loadFieldIndex;
|
|
124
|
+
/**
|
|
125
|
+
* Save field index to storage
|
|
126
|
+
*/
|
|
127
|
+
private saveFieldIndex;
|
|
128
|
+
/**
|
|
129
|
+
* Get index statistics
|
|
130
|
+
*/
|
|
131
|
+
getStats(): Promise<MetadataIndexStats>;
|
|
132
|
+
/**
|
|
133
|
+
* Rebuild entire index from scratch using pagination
|
|
134
|
+
*/
|
|
135
|
+
rebuild(): Promise<void>;
|
|
136
|
+
/**
|
|
137
|
+
* Load index entry from storage using safe filenames
|
|
138
|
+
*/
|
|
139
|
+
private loadIndexEntry;
|
|
140
|
+
/**
|
|
141
|
+
* Save index entry to storage using safe filenames
|
|
142
|
+
*/
|
|
143
|
+
private saveIndexEntry;
|
|
144
|
+
/**
|
|
145
|
+
* Delete index entry from storage using safe filenames
|
|
146
|
+
*/
|
|
147
|
+
private deleteIndexEntry;
|
|
148
|
+
}
|