n8n-nodes-minimemory 0.2.0 → 0.3.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.
Files changed (29) hide show
  1. package/README.md +14 -4
  2. package/dist/index.d.ts +0 -1
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +1 -3
  5. package/dist/index.js.map +1 -1
  6. package/dist/nodes/Minimemory/BM25Index.d.ts +108 -0
  7. package/dist/nodes/Minimemory/BM25Index.d.ts.map +1 -0
  8. package/dist/nodes/Minimemory/BM25Index.js +259 -0
  9. package/dist/nodes/Minimemory/BM25Index.js.map +1 -0
  10. package/dist/nodes/Minimemory/HybridSearch.d.ts +59 -0
  11. package/dist/nodes/Minimemory/HybridSearch.d.ts.map +1 -0
  12. package/dist/nodes/Minimemory/HybridSearch.js +158 -0
  13. package/dist/nodes/Minimemory/HybridSearch.js.map +1 -0
  14. package/dist/nodes/Minimemory/Minimemory.node.d.ts.map +1 -1
  15. package/dist/nodes/Minimemory/Minimemory.node.js +190 -12
  16. package/dist/nodes/Minimemory/Minimemory.node.js.map +1 -1
  17. package/dist/nodes/Minimemory/TextUtils.d.ts +22 -0
  18. package/dist/nodes/Minimemory/TextUtils.d.ts.map +1 -0
  19. package/dist/nodes/Minimemory/TextUtils.js +92 -0
  20. package/dist/nodes/Minimemory/TextUtils.js.map +1 -0
  21. package/dist/nodes/Minimemory/VectorDB.d.ts +55 -0
  22. package/dist/nodes/Minimemory/VectorDB.d.ts.map +1 -1
  23. package/dist/nodes/Minimemory/VectorDB.js +158 -3
  24. package/dist/nodes/Minimemory/VectorDB.js.map +1 -1
  25. package/package.json +3 -6
  26. package/dist/credentials/MinimemoryConfig.credentials.d.ts +0 -8
  27. package/dist/credentials/MinimemoryConfig.credentials.d.ts.map +0 -1
  28. package/dist/credentials/MinimemoryConfig.credentials.js +0 -40
  29. package/dist/credentials/MinimemoryConfig.credentials.js.map +0 -1
package/README.md CHANGED
@@ -12,8 +12,10 @@ Perform vector similarity search directly within n8n without any external server
12
12
 
13
13
  - **No server required** - Everything runs locally within n8n
14
14
  - **Similarity search** - Find the k most similar vectors
15
+ - **Hybrid search** - Combine vector + keyword (BM25) search
15
16
  - **Multiple metrics** - Cosine, Euclidean, Dot Product
16
17
  - **Metadata support** - Associate additional information with each vector
18
+ - **Metadata filtering** - MongoDB-style query operators
17
19
  - **Persistence** - Save/load from JSON files
18
20
  - **Bulk insert** - Insert multiple vectors from previous nodes
19
21
 
@@ -73,25 +75,33 @@ Bulk insert vectors from input items.
73
75
  ```
74
76
 
75
77
  ### Search
76
- Search for the k nearest neighbors with optional metadata filtering.
78
+ Search for the k nearest neighbors using vector, keyword, or hybrid search.
77
79
 
78
80
  | Parameter | Description | Default |
79
81
  |-----------|-------------|---------|
80
- | Query Vector | Query vector | |
82
+ | Search Mode | `vector`, `keyword`, or `hybrid` | `vector` |
83
+ | Query Vector | Vector for similarity search | (required for vector/hybrid) |
84
+ | Keywords | Text for BM25 keyword search | (required for keyword/hybrid) |
85
+ | Text Fields | Metadata fields to search | `content,text,title,description` |
81
86
  | Number of Results (K) | Number of results | `10` |
82
87
  | Include Vectors | Include vectors in result | `false` |
83
88
  | Minimum Similarity | Filter by minimum similarity | `0` |
84
89
  | Use Metadata Filter | Enable metadata filtering | `false` |
85
90
  | Metadata Filter | JSON filter (see below) | `{}` |
91
+ | Hybrid Alpha | Vector(1) vs Keyword(0) balance | `0.5` |
92
+ | Fusion Method | `rrf` or `weighted` | `rrf` |
93
+ | BM25 K1 | Term saturation parameter | `1.2` |
94
+ | BM25 B | Length normalization | `0.75` |
86
95
 
87
96
  **Output:**
88
97
  ```json
89
98
  {
90
99
  "success": true,
100
+ "searchMode": "hybrid",
91
101
  "filterApplied": true,
92
102
  "results": [
93
- {"id": "doc1", "distance": 0.1, "similarity": 0.9, "metadata": {...}},
94
- {"id": "doc2", "distance": 0.2, "similarity": 0.8, "metadata": {...}}
103
+ {"id": "doc1", "score": 0.032, "vectorSimilarity": 0.9, "keywordScore": 12.4, "metadata": {...}},
104
+ {"id": "doc2", "score": 0.028, "vectorSimilarity": 0.8, "keywordScore": 8.2, "metadata": {...}}
95
105
  ]
96
106
  }
97
107
  ```
package/dist/index.d.ts CHANGED
@@ -1,3 +1,2 @@
1
1
  export { Minimemory } from './nodes/Minimemory/Minimemory.node';
2
- export { MinimemoryConfig } from './credentials/MinimemoryConfig.credentials';
3
2
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,4CAA4C,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC"}
package/dist/index.js CHANGED
@@ -1,8 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MinimemoryConfig = exports.Minimemory = void 0;
3
+ exports.Minimemory = void 0;
4
4
  var Minimemory_node_1 = require("./nodes/Minimemory/Minimemory.node");
5
5
  Object.defineProperty(exports, "Minimemory", { enumerable: true, get: function () { return Minimemory_node_1.Minimemory; } });
6
- var MinimemoryConfig_credentials_1 = require("./credentials/MinimemoryConfig.credentials");
7
- Object.defineProperty(exports, "MinimemoryConfig", { enumerable: true, get: function () { return MinimemoryConfig_credentials_1.MinimemoryConfig; } });
8
6
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";;;AAAA,sEAAgE;AAAvD,6GAAA,UAAU,OAAA;AACnB,2FAA8E;AAArE,gIAAA,gBAAgB,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";;;AAAA,sEAAgE;AAAvD,6GAAA,UAAU,OAAA"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * BM25 (Best Matching 25) keyword search implementation
3
+ * Pure TypeScript with zero external dependencies
4
+ */
5
+ import { TokenizerOptions } from './TextUtils';
6
+ export interface BM25Options {
7
+ k1?: number;
8
+ b?: number;
9
+ textFields: string[];
10
+ tokenizerOptions?: TokenizerOptions;
11
+ }
12
+ export interface BM25SearchResult {
13
+ id: string;
14
+ score: number;
15
+ metadata?: Record<string, unknown>;
16
+ }
17
+ export interface SerializedBM25Index {
18
+ version: string;
19
+ k1: number;
20
+ b: number;
21
+ textFields: string[];
22
+ avgDocLength: number;
23
+ documentCount: number;
24
+ documents: Array<{
25
+ id: string;
26
+ length: number;
27
+ termFrequencies: Record<string, number>;
28
+ }>;
29
+ documentFrequencies: Record<string, number>;
30
+ }
31
+ /**
32
+ * BM25 Index for full-text keyword search
33
+ */
34
+ export declare class BM25Index {
35
+ private k1;
36
+ private b;
37
+ private textFields;
38
+ private tokenizerOptions;
39
+ private documents;
40
+ private documentFrequencies;
41
+ private totalDocLength;
42
+ constructor(options: BM25Options);
43
+ /**
44
+ * Gets the text fields being indexed
45
+ */
46
+ get indexedFields(): string[];
47
+ /**
48
+ * Gets the number of documents in the index
49
+ */
50
+ get documentCount(): number;
51
+ /**
52
+ * Gets the average document length
53
+ */
54
+ get avgDocLength(): number;
55
+ /**
56
+ * Gets the vocabulary size (unique terms)
57
+ */
58
+ get vocabularySize(): number;
59
+ /**
60
+ * Adds a document to the index
61
+ */
62
+ addDocument(id: string, metadata: Record<string, unknown> | null): void;
63
+ /**
64
+ * Updates a document in the index
65
+ */
66
+ updateDocument(id: string, metadata: Record<string, unknown> | null): void;
67
+ /**
68
+ * Removes a document from the index
69
+ */
70
+ removeDocument(id: string): boolean;
71
+ /**
72
+ * Calculates the IDF (Inverse Document Frequency) for a term
73
+ * Using the BM25 IDF formula: ln((N - n + 0.5) / (n + 0.5) + 1)
74
+ */
75
+ private calculateIDF;
76
+ /**
77
+ * Calculates the BM25 score for a document given query terms
78
+ */
79
+ private calculateScore;
80
+ /**
81
+ * Searches the index and returns k most relevant documents
82
+ */
83
+ search(query: string, k: number): BM25SearchResult[];
84
+ /**
85
+ * Gets statistics about the index
86
+ */
87
+ getStats(): {
88
+ documentCount: number;
89
+ avgDocLength: number;
90
+ vocabularySize: number;
91
+ k1: number;
92
+ b: number;
93
+ textFields: string[];
94
+ };
95
+ /**
96
+ * Serializes the index to a plain object
97
+ */
98
+ serialize(): SerializedBM25Index;
99
+ /**
100
+ * Deserializes an index from a plain object
101
+ */
102
+ static deserialize(data: SerializedBM25Index): BM25Index;
103
+ /**
104
+ * Clears the entire index
105
+ */
106
+ clear(): void;
107
+ }
108
+ //# sourceMappingURL=BM25Index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BM25Index.d.ts","sourceRoot":"","sources":["../../../nodes/Minimemory/BM25Index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAyD,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEtG,MAAM,WAAW,WAAW;IAC3B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACpC;AAED,MAAM,WAAW,gBAAgB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,mBAAmB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,EAAE,MAAM,CAAC;IACV,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,KAAK,CAAC;QAChB,EAAE,EAAE,MAAM,CAAC;QACX,MAAM,EAAE,MAAM,CAAC;QACf,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACxC,CAAC,CAAC;IACH,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5C;AAQD;;GAEG;AACH,qBAAa,SAAS;IACrB,OAAO,CAAC,EAAE,CAAS;IACnB,OAAO,CAAC,CAAC,CAAS;IAClB,OAAO,CAAC,UAAU,CAAW;IAC7B,OAAO,CAAC,gBAAgB,CAAmB;IAG3C,OAAO,CAAC,SAAS,CAAwC;IAGzD,OAAO,CAAC,mBAAmB,CAAkC;IAG7D,OAAO,CAAC,cAAc,CAAa;gBAEvB,OAAO,EAAE,WAAW;IAOhC;;OAEG;IACH,IAAI,aAAa,IAAI,MAAM,EAAE,CAE5B;IAED;;OAEG;IACH,IAAI,aAAa,IAAI,MAAM,CAE1B;IAED;;OAEG;IACH,IAAI,YAAY,IAAI,MAAM,CAGzB;IAED;;OAEG;IACH,IAAI,cAAc,IAAI,MAAM,CAE3B;IAED;;OAEG;IACH,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,IAAI;IAgCvE;;OAEG;IACH,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,IAAI;IAI1E;;OAEG;IACH,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAuBnC;;;OAGG;IACH,OAAO,CAAC,YAAY;IAUpB;;OAEG;IACH,OAAO,CAAC,cAAc;IAyBtB;;OAEG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,gBAAgB,EAAE;IAoCpD;;OAEG;IACH,QAAQ,IAAI;QACX,aAAa,EAAE,MAAM,CAAC;QACtB,YAAY,EAAE,MAAM,CAAC;QACrB,cAAc,EAAE,MAAM,CAAC;QACvB,EAAE,EAAE,MAAM,CAAC;QACX,CAAC,EAAE,MAAM,CAAC;QACV,UAAU,EAAE,MAAM,EAAE,CAAC;KACrB;IAWD;;OAEG;IACH,SAAS,IAAI,mBAAmB;IAgChC;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,mBAAmB,GAAG,SAAS;IA8BxD;;OAEG;IACH,KAAK,IAAI,IAAI;CAKb"}
@@ -0,0 +1,259 @@
1
+ "use strict";
2
+ /**
3
+ * BM25 (Best Matching 25) keyword search implementation
4
+ * Pure TypeScript with zero external dependencies
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.BM25Index = void 0;
8
+ const TextUtils_1 = require("./TextUtils");
9
+ /**
10
+ * BM25 Index for full-text keyword search
11
+ */
12
+ class BM25Index {
13
+ constructor(options) {
14
+ var _a, _b, _c;
15
+ // Document storage: id -> document data
16
+ this.documents = new Map();
17
+ // Inverted index: term -> count of documents containing this term
18
+ this.documentFrequencies = new Map();
19
+ // Statistics
20
+ this.totalDocLength = 0;
21
+ this.k1 = (_a = options.k1) !== null && _a !== void 0 ? _a : 1.2;
22
+ this.b = (_b = options.b) !== null && _b !== void 0 ? _b : 0.75;
23
+ this.textFields = options.textFields;
24
+ this.tokenizerOptions = (_c = options.tokenizerOptions) !== null && _c !== void 0 ? _c : {};
25
+ }
26
+ /**
27
+ * Gets the text fields being indexed
28
+ */
29
+ get indexedFields() {
30
+ return [...this.textFields];
31
+ }
32
+ /**
33
+ * Gets the number of documents in the index
34
+ */
35
+ get documentCount() {
36
+ return this.documents.size;
37
+ }
38
+ /**
39
+ * Gets the average document length
40
+ */
41
+ get avgDocLength() {
42
+ if (this.documents.size === 0)
43
+ return 0;
44
+ return this.totalDocLength / this.documents.size;
45
+ }
46
+ /**
47
+ * Gets the vocabulary size (unique terms)
48
+ */
49
+ get vocabularySize() {
50
+ return this.documentFrequencies.size;
51
+ }
52
+ /**
53
+ * Adds a document to the index
54
+ */
55
+ addDocument(id, metadata) {
56
+ // Remove existing document if present
57
+ if (this.documents.has(id)) {
58
+ this.removeDocument(id);
59
+ }
60
+ // Extract and tokenize text
61
+ const text = (0, TextUtils_1.extractTextFromMetadata)(metadata, this.textFields);
62
+ const tokens = (0, TextUtils_1.tokenize)(text, this.tokenizerOptions);
63
+ const termFrequencies = (0, TextUtils_1.getTermFrequencies)(tokens);
64
+ const docLength = tokens.length;
65
+ // Update document frequencies (IDF)
66
+ const seenTerms = new Set();
67
+ for (const term of tokens) {
68
+ if (!seenTerms.has(term)) {
69
+ seenTerms.add(term);
70
+ const current = this.documentFrequencies.get(term) || 0;
71
+ this.documentFrequencies.set(term, current + 1);
72
+ }
73
+ }
74
+ // Store document
75
+ this.documents.set(id, {
76
+ length: docLength,
77
+ termFrequencies,
78
+ metadata: metadata || undefined,
79
+ });
80
+ this.totalDocLength += docLength;
81
+ }
82
+ /**
83
+ * Updates a document in the index
84
+ */
85
+ updateDocument(id, metadata) {
86
+ this.addDocument(id, metadata);
87
+ }
88
+ /**
89
+ * Removes a document from the index
90
+ */
91
+ removeDocument(id) {
92
+ const doc = this.documents.get(id);
93
+ if (!doc)
94
+ return false;
95
+ // Update document frequencies
96
+ for (const [term] of doc.termFrequencies) {
97
+ const current = this.documentFrequencies.get(term) || 0;
98
+ if (current <= 1) {
99
+ this.documentFrequencies.delete(term);
100
+ }
101
+ else {
102
+ this.documentFrequencies.set(term, current - 1);
103
+ }
104
+ }
105
+ // Update total length
106
+ this.totalDocLength -= doc.length;
107
+ // Remove document
108
+ this.documents.delete(id);
109
+ return true;
110
+ }
111
+ /**
112
+ * Calculates the IDF (Inverse Document Frequency) for a term
113
+ * Using the BM25 IDF formula: ln((N - n + 0.5) / (n + 0.5) + 1)
114
+ */
115
+ calculateIDF(term) {
116
+ const n = this.documentFrequencies.get(term) || 0;
117
+ const N = this.documents.size;
118
+ if (n === 0)
119
+ return 0;
120
+ // BM25 IDF formula (Robertson-Walker IDF)
121
+ return Math.log(((N - n + 0.5) / (n + 0.5)) + 1);
122
+ }
123
+ /**
124
+ * Calculates the BM25 score for a document given query terms
125
+ */
126
+ calculateScore(docId, queryTerms) {
127
+ const doc = this.documents.get(docId);
128
+ if (!doc)
129
+ return 0;
130
+ const avgdl = this.avgDocLength;
131
+ if (avgdl === 0)
132
+ return 0;
133
+ let score = 0;
134
+ for (const term of queryTerms) {
135
+ const idf = this.calculateIDF(term);
136
+ const tf = doc.termFrequencies.get(term) || 0;
137
+ if (tf === 0)
138
+ continue;
139
+ // BM25 scoring formula
140
+ const numerator = tf * (this.k1 + 1);
141
+ const denominator = tf + this.k1 * (1 - this.b + this.b * (doc.length / avgdl));
142
+ score += idf * (numerator / denominator);
143
+ }
144
+ return score;
145
+ }
146
+ /**
147
+ * Searches the index and returns k most relevant documents
148
+ */
149
+ search(query, k) {
150
+ if (this.documents.size === 0 || !query.trim()) {
151
+ return [];
152
+ }
153
+ // Tokenize query
154
+ const queryTerms = (0, TextUtils_1.tokenize)(query, this.tokenizerOptions);
155
+ if (queryTerms.length === 0) {
156
+ return [];
157
+ }
158
+ // Calculate scores for all documents
159
+ const scores = [];
160
+ for (const [docId] of this.documents) {
161
+ const score = this.calculateScore(docId, queryTerms);
162
+ if (score > 0) {
163
+ scores.push({ id: docId, score });
164
+ }
165
+ }
166
+ // Sort by score (descending)
167
+ scores.sort((a, b) => b.score - a.score);
168
+ // Return top k results with metadata
169
+ return scores.slice(0, k).map(({ id, score }) => {
170
+ const doc = this.documents.get(id);
171
+ return {
172
+ id,
173
+ score,
174
+ metadata: doc === null || doc === void 0 ? void 0 : doc.metadata,
175
+ };
176
+ });
177
+ }
178
+ /**
179
+ * Gets statistics about the index
180
+ */
181
+ getStats() {
182
+ return {
183
+ documentCount: this.documentCount,
184
+ avgDocLength: this.avgDocLength,
185
+ vocabularySize: this.vocabularySize,
186
+ k1: this.k1,
187
+ b: this.b,
188
+ textFields: this.textFields,
189
+ };
190
+ }
191
+ /**
192
+ * Serializes the index to a plain object
193
+ */
194
+ serialize() {
195
+ const documents = [];
196
+ for (const [id, doc] of this.documents) {
197
+ const termFrequencies = {};
198
+ for (const [term, freq] of doc.termFrequencies) {
199
+ termFrequencies[term] = freq;
200
+ }
201
+ documents.push({
202
+ id,
203
+ length: doc.length,
204
+ termFrequencies,
205
+ });
206
+ }
207
+ const documentFrequencies = {};
208
+ for (const [term, freq] of this.documentFrequencies) {
209
+ documentFrequencies[term] = freq;
210
+ }
211
+ return {
212
+ version: '1.0.0',
213
+ k1: this.k1,
214
+ b: this.b,
215
+ textFields: this.textFields,
216
+ avgDocLength: this.avgDocLength,
217
+ documentCount: this.documentCount,
218
+ documents,
219
+ documentFrequencies,
220
+ };
221
+ }
222
+ /**
223
+ * Deserializes an index from a plain object
224
+ */
225
+ static deserialize(data) {
226
+ const index = new BM25Index({
227
+ k1: data.k1,
228
+ b: data.b,
229
+ textFields: data.textFields,
230
+ });
231
+ // Restore documents
232
+ for (const doc of data.documents) {
233
+ const termFrequencies = new Map();
234
+ for (const [term, freq] of Object.entries(doc.termFrequencies)) {
235
+ termFrequencies.set(term, freq);
236
+ }
237
+ index.documents.set(doc.id, {
238
+ length: doc.length,
239
+ termFrequencies,
240
+ });
241
+ index.totalDocLength += doc.length;
242
+ }
243
+ // Restore document frequencies
244
+ for (const [term, freq] of Object.entries(data.documentFrequencies)) {
245
+ index.documentFrequencies.set(term, freq);
246
+ }
247
+ return index;
248
+ }
249
+ /**
250
+ * Clears the entire index
251
+ */
252
+ clear() {
253
+ this.documents.clear();
254
+ this.documentFrequencies.clear();
255
+ this.totalDocLength = 0;
256
+ }
257
+ }
258
+ exports.BM25Index = BM25Index;
259
+ //# sourceMappingURL=BM25Index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BM25Index.js","sourceRoot":"","sources":["../../../nodes/Minimemory/BM25Index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,2CAAsG;AAoCtG;;GAEG;AACH,MAAa,SAAS;IAerB,YAAY,OAAoB;;QAThC,wCAAwC;QAChC,cAAS,GAA8B,IAAI,GAAG,EAAE,CAAC;QAEzD,kEAAkE;QAC1D,wBAAmB,GAAwB,IAAI,GAAG,EAAE,CAAC;QAE7D,aAAa;QACL,mBAAc,GAAW,CAAC,CAAC;QAGlC,IAAI,CAAC,EAAE,GAAG,MAAA,OAAO,CAAC,EAAE,mCAAI,GAAG,CAAC;QAC5B,IAAI,CAAC,CAAC,GAAG,MAAA,OAAO,CAAC,CAAC,mCAAI,IAAI,CAAC;QAC3B,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;QACrC,IAAI,CAAC,gBAAgB,GAAG,MAAA,OAAO,CAAC,gBAAgB,mCAAI,EAAE,CAAC;IACxD,CAAC;IAED;;OAEG;IACH,IAAI,aAAa;QAChB,OAAO,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;IAC7B,CAAC;IAED;;OAEG;IACH,IAAI,aAAa;QAChB,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;IAC5B,CAAC;IAED;;OAEG;IACH,IAAI,YAAY;QACf,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO,CAAC,CAAC;QACxC,OAAO,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;IAClD,CAAC;IAED;;OAEG;IACH,IAAI,cAAc;QACjB,OAAO,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC;IACtC,CAAC;IAED;;OAEG;IACH,WAAW,CAAC,EAAU,EAAE,QAAwC;QAC/D,sCAAsC;QACtC,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YAC5B,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;QACzB,CAAC;QAED,4BAA4B;QAC5B,MAAM,IAAI,GAAG,IAAA,mCAAuB,EAAC,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QAChE,MAAM,MAAM,GAAG,IAAA,oBAAQ,EAAC,IAAI,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC;QACrD,MAAM,eAAe,GAAG,IAAA,8BAAkB,EAAC,MAAM,CAAC,CAAC;QACnD,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC;QAEhC,oCAAoC;QACpC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;QACpC,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;YAC3B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC1B,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBACpB,MAAM,OAAO,GAAG,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACxD,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC;YACjD,CAAC;QACF,CAAC;QAED,iBAAiB;QACjB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE;YACtB,MAAM,EAAE,SAAS;YACjB,eAAe;YACf,QAAQ,EAAE,QAAQ,IAAI,SAAS;SAC/B,CAAC,CAAC;QAEH,IAAI,CAAC,cAAc,IAAI,SAAS,CAAC;IAClC,CAAC;IAED;;OAEG;IACH,cAAc,CAAC,EAAU,EAAE,QAAwC;QAClE,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;IAChC,CAAC;IAED;;OAEG;IACH,cAAc,CAAC,EAAU;QACxB,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACnC,IAAI,CAAC,GAAG;YAAE,OAAO,KAAK,CAAC;QAEvB,8BAA8B;QAC9B,KAAK,MAAM,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,eAAe,EAAE,CAAC;YAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACxD,IAAI,OAAO,IAAI,CAAC,EAAE,CAAC;gBAClB,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACvC,CAAC;iBAAM,CAAC;gBACP,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC;YACjD,CAAC;QACF,CAAC;QAED,sBAAsB;QACtB,IAAI,CAAC,cAAc,IAAI,GAAG,CAAC,MAAM,CAAC;QAElC,kBAAkB;QAClB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAE1B,OAAO,IAAI,CAAC;IACb,CAAC;IAED;;;OAGG;IACK,YAAY,CAAC,IAAY;QAChC,MAAM,CAAC,GAAG,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClD,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;QAE9B,IAAI,CAAC,KAAK,CAAC;YAAE,OAAO,CAAC,CAAC;QAEtB,0CAA0C;QAC1C,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAClD,CAAC;IAED;;OAEG;IACK,cAAc,CAAC,KAAa,EAAE,UAAoB;QACzD,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,CAAC,GAAG;YAAE,OAAO,CAAC,CAAC;QAEnB,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC;QAChC,IAAI,KAAK,KAAK,CAAC;YAAE,OAAO,CAAC,CAAC;QAE1B,IAAI,KAAK,GAAG,CAAC,CAAC;QAEd,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;YAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;YACpC,MAAM,EAAE,GAAG,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAE9C,IAAI,EAAE,KAAK,CAAC;gBAAE,SAAS;YAEvB,uBAAuB;YACvB,MAAM,SAAS,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;YACrC,MAAM,WAAW,GAAG,EAAE,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC;YAEhF,KAAK,IAAI,GAAG,GAAG,CAAC,SAAS,GAAG,WAAW,CAAC,CAAC;QAC1C,CAAC;QAED,OAAO,KAAK,CAAC;IACd,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,KAAa,EAAE,CAAS;QAC9B,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;YAChD,OAAO,EAAE,CAAC;QACX,CAAC;QAED,iBAAiB;QACjB,MAAM,UAAU,GAAG,IAAA,oBAAQ,EAAC,KAAK,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAE1D,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO,EAAE,CAAC;QACX,CAAC;QAED,qCAAqC;QACrC,MAAM,MAAM,GAAyC,EAAE,CAAC;QAExD,KAAK,MAAM,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACtC,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;YACrD,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;gBACf,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;YACnC,CAAC;QACF,CAAC;QAED,6BAA6B;QAC7B,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;QAEzC,qCAAqC;QACrC,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;YAC/C,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACnC,OAAO;gBACN,EAAE;gBACF,KAAK;gBACL,QAAQ,EAAE,GAAG,aAAH,GAAG,uBAAH,GAAG,CAAE,QAAQ;aACvB,CAAC;QACH,CAAC,CAAC,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,QAAQ;QAQP,OAAO;YACN,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,CAAC,EAAE,IAAI,CAAC,CAAC;YACT,UAAU,EAAE,IAAI,CAAC,UAAU;SAC3B,CAAC;IACH,CAAC;IAED;;OAEG;IACH,SAAS;QACR,MAAM,SAAS,GAAqC,EAAE,CAAC;QAEvD,KAAK,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACxC,MAAM,eAAe,GAA2B,EAAE,CAAC;YACnD,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,GAAG,CAAC,eAAe,EAAE,CAAC;gBAChD,eAAe,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;YAC9B,CAAC;YACD,SAAS,CAAC,IAAI,CAAC;gBACd,EAAE;gBACF,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,eAAe;aACf,CAAC,CAAC;QACJ,CAAC;QAED,MAAM,mBAAmB,GAA2B,EAAE,CAAC;QACvD,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,mBAAmB,EAAE,CAAC;YACrD,mBAAmB,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;QAClC,CAAC;QAED,OAAO;YACN,OAAO,EAAE,OAAO;YAChB,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,CAAC,EAAE,IAAI,CAAC,CAAC;YACT,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,SAAS;YACT,mBAAmB;SACnB,CAAC;IACH,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,IAAyB;QAC3C,MAAM,KAAK,GAAG,IAAI,SAAS,CAAC;YAC3B,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,CAAC,EAAE,IAAI,CAAC,CAAC;YACT,UAAU,EAAE,IAAI,CAAC,UAAU;SAC3B,CAAC,CAAC;QAEH,oBAAoB;QACpB,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YAClC,MAAM,eAAe,GAAG,IAAI,GAAG,EAAkB,CAAC;YAClD,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC;gBAChE,eAAe,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YACjC,CAAC;YAED,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE;gBAC3B,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,eAAe;aACf,CAAC,CAAC;YAEH,KAAK,CAAC,cAAc,IAAI,GAAG,CAAC,MAAM,CAAC;QACpC,CAAC;QAED,+BAA+B;QAC/B,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,EAAE,CAAC;YACrE,KAAK,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC3C,CAAC;QAED,OAAO,KAAK,CAAC;IACd,CAAC;IAED;;OAEG;IACH,KAAK;QACJ,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;QACvB,IAAI,CAAC,mBAAmB,CAAC,KAAK,EAAE,CAAC;QACjC,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC;IACzB,CAAC;CACD;AAzSD,8BAySC"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Hybrid Search - Combines vector similarity and keyword (BM25) search
3
+ */
4
+ import { BM25SearchResult } from './BM25Index';
5
+ export type SearchMode = 'vector' | 'keyword' | 'hybrid';
6
+ export type FusionMethod = 'rrf' | 'weighted';
7
+ export interface VectorSearchResult {
8
+ id: string;
9
+ distance: number;
10
+ similarity: number;
11
+ metadata?: Record<string, unknown>;
12
+ }
13
+ export interface HybridSearchResult {
14
+ id: string;
15
+ score: number;
16
+ vectorRank?: number;
17
+ keywordRank?: number;
18
+ vectorSimilarity?: number;
19
+ keywordScore?: number;
20
+ metadata?: Record<string, unknown>;
21
+ }
22
+ /**
23
+ * Performs Reciprocal Rank Fusion (RRF) on two result sets
24
+ *
25
+ * RRF is preferred for hybrid search because:
26
+ * 1. It does not require score normalization
27
+ * 2. It is robust to score distribution differences
28
+ * 3. It handles missing documents gracefully
29
+ *
30
+ * Formula: RRF_score(d) = 1/(k + rank_vector(d)) + 1/(k + rank_keyword(d))
31
+ *
32
+ * @param vectorResults - Results from vector similarity search
33
+ * @param keywordResults - Results from BM25 keyword search
34
+ * @param k - Number of results to return
35
+ * @param rrfConstant - RRF constant (default: 60, higher = less emphasis on top ranks)
36
+ */
37
+ export declare function reciprocalRankFusion(vectorResults: VectorSearchResult[], keywordResults: BM25SearchResult[], k: number, rrfConstant?: number): HybridSearchResult[];
38
+ /**
39
+ * Performs weighted score combination
40
+ *
41
+ * This method normalizes scores from both search types to [0, 1] range
42
+ * and combines them using the alpha parameter.
43
+ *
44
+ * Formula: combined_score = alpha * vector_score + (1 - alpha) * keyword_score
45
+ *
46
+ * @param vectorResults - Results from vector similarity search
47
+ * @param keywordResults - Results from BM25 keyword search
48
+ * @param k - Number of results to return
49
+ * @param alpha - Balance weight: 0 = pure keyword, 1 = pure vector (default: 0.5)
50
+ */
51
+ export declare function weightedCombination(vectorResults: VectorSearchResult[], keywordResults: BM25SearchResult[], k: number, alpha?: number): HybridSearchResult[];
52
+ /**
53
+ * Performs hybrid search using the specified fusion method
54
+ */
55
+ export declare function hybridFusion(vectorResults: VectorSearchResult[], keywordResults: BM25SearchResult[], k: number, method?: FusionMethod, options?: {
56
+ alpha?: number;
57
+ rrfConstant?: number;
58
+ }): HybridSearchResult[];
59
+ //# sourceMappingURL=HybridSearch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HybridSearch.d.ts","sourceRoot":"","sources":["../../../nodes/Minimemory/HybridSearch.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;AACzD,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,UAAU,CAAC;AAE9C,MAAM,WAAW,kBAAkB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,kBAAkB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CACnC,aAAa,EAAE,kBAAkB,EAAE,EACnC,cAAc,EAAE,gBAAgB,EAAE,EAClC,CAAC,EAAE,MAAM,EACT,WAAW,GAAE,MAAW,GACtB,kBAAkB,EAAE,CAuDtB;AA2BD;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAClC,aAAa,EAAE,kBAAkB,EAAE,EACnC,cAAc,EAAE,gBAAgB,EAAE,EAClC,CAAC,EAAE,MAAM,EACT,KAAK,GAAE,MAAY,GACjB,kBAAkB,EAAE,CAwDtB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC3B,aAAa,EAAE,kBAAkB,EAAE,EACnC,cAAc,EAAE,gBAAgB,EAAE,EAClC,CAAC,EAAE,MAAM,EACT,MAAM,GAAE,YAAoB,EAC5B,OAAO,CAAC,EAAE;IACT,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB,GACC,kBAAkB,EAAE,CAgBtB"}