@faiss-node/native 0.1.4
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/.env.example +5 -0
- package/0.1.1 +0 -0
- package/API.md +416 -0
- package/DOCUMENTATION.md +203 -0
- package/LICENSE +21 -0
- package/QUICK_PUBLISH.md +48 -0
- package/README.md +551 -0
- package/binding.gyp +90 -0
- package/docs/README.md +31 -0
- package/package.json +69 -0
- package/src/cpp/faiss_index.cpp +300 -0
- package/src/cpp/faiss_index.h +99 -0
- package/src/cpp/napi_bindings.cpp +969 -0
- package/src/js/index.js +349 -0
- package/src/js/types.d.ts +36 -0
- package/tsconfig.json +25 -0
- package/typedoc.json +30 -0
package/README.md
ADDED
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
# @faiss-node/native
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@faiss-node/native)
|
|
4
|
+
[](https://nodejs.org/)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://anupammaurya6767.github.io/faiss-node-native/)
|
|
7
|
+
|
|
8
|
+
High-performance Node.js native bindings for [Facebook FAISS](https://github.com/facebookresearch/faiss) - the industry-standard vector similarity search library. Built for production-ready semantic search, RAG applications, and vector databases.
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- ๐ **Async Operations** - Non-blocking Promise-based API that never blocks the event loop
|
|
13
|
+
- ๐ **Thread-Safe** - Mutex-protected concurrent operations for production workloads
|
|
14
|
+
- ๐ฆ **Multiple Index Types** - FLAT_L2, IVF_FLAT, and HNSW with optimized defaults
|
|
15
|
+
- ๐พ **Persistence** - Save/load indexes to disk or serialize to buffers
|
|
16
|
+
- โก **High Performance** - Direct C++ bindings with zero-copy data transfer
|
|
17
|
+
- ๐งช **Well-Tested** - 1000+ comprehensive tests covering edge cases
|
|
18
|
+
- ๐ **TypeScript Support** - Full type definitions included
|
|
19
|
+
- ๐ง **Production-Ready** - Memory-safe, error-handled, and battle-tested
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
### Quick Install
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install @faiss-node/native
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Prerequisites
|
|
30
|
+
|
|
31
|
+
**macOS:**
|
|
32
|
+
```bash
|
|
33
|
+
brew install cmake libomp openblas faiss
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Linux (Ubuntu/Debian):**
|
|
37
|
+
```bash
|
|
38
|
+
sudo apt-get update
|
|
39
|
+
sudo apt-get install -y cmake libopenblas-dev libomp-dev
|
|
40
|
+
# Build FAISS from source (see below)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Building FAISS from Source (Linux):**
|
|
44
|
+
```bash
|
|
45
|
+
git clone https://github.com/facebookresearch/faiss.git
|
|
46
|
+
cd faiss
|
|
47
|
+
cmake -B build -DFAISS_ENABLE_GPU=OFF -DFAISS_ENABLE_PYTHON=OFF
|
|
48
|
+
cmake --build build -j$(nproc)
|
|
49
|
+
sudo cmake --install build
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Build Native Module
|
|
53
|
+
|
|
54
|
+
After installing prerequisites:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npm run build
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Quick Start
|
|
61
|
+
|
|
62
|
+
```javascript
|
|
63
|
+
const { FaissIndex } = require('@faiss-node/native');
|
|
64
|
+
|
|
65
|
+
// Create an index
|
|
66
|
+
const index = new FaissIndex({ type: 'FLAT_L2', dims: 128 });
|
|
67
|
+
|
|
68
|
+
// Add vectors (single or batch)
|
|
69
|
+
const vectors = new Float32Array([
|
|
70
|
+
1.0, 0.0, 0.0, 0.0, // Vector 1
|
|
71
|
+
0.0, 1.0, 0.0, 0.0, // Vector 2
|
|
72
|
+
0.0, 0.0, 1.0, 0.0 // Vector 3
|
|
73
|
+
]);
|
|
74
|
+
await index.add(vectors);
|
|
75
|
+
|
|
76
|
+
// Search for nearest neighbors
|
|
77
|
+
const query = new Float32Array([1.0, 0.0, 0.0, 0.0]);
|
|
78
|
+
const results = await index.search(query, 2);
|
|
79
|
+
|
|
80
|
+
console.log('Labels:', results.labels); // Int32Array: [0, 1]
|
|
81
|
+
console.log('Distances:', results.distances); // Float32Array: [0, 2]
|
|
82
|
+
|
|
83
|
+
// Cleanup
|
|
84
|
+
index.dispose();
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## API Reference
|
|
88
|
+
|
|
89
|
+
### Constructor
|
|
90
|
+
|
|
91
|
+
Create a new FAISS index with the specified configuration.
|
|
92
|
+
|
|
93
|
+
```javascript
|
|
94
|
+
const index = new FaissIndex(config);
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Parameters:**
|
|
98
|
+
- `config.type` (string, required): Index type - `'FLAT_L2'`, `'IVF_FLAT'`, or `'HNSW'`
|
|
99
|
+
- `config.dims` (number, required): Vector dimensions (must be positive integer)
|
|
100
|
+
- `config.nlist` (number, optional): Number of clusters for IVF_FLAT (default: 100)
|
|
101
|
+
- `config.nprobe` (number, optional): Clusters to search for IVF_FLAT (default: 10)
|
|
102
|
+
- `config.M` (number, optional): Connections per node for HNSW (default: 16)
|
|
103
|
+
- `config.efConstruction` (number, optional): HNSW construction parameter (default: 200)
|
|
104
|
+
- `config.efSearch` (number, optional): HNSW search parameter (default: 50)
|
|
105
|
+
|
|
106
|
+
**Examples:**
|
|
107
|
+
|
|
108
|
+
```javascript
|
|
109
|
+
// FLAT_L2 - Exact search (best for small datasets < 10k vectors)
|
|
110
|
+
const flatIndex = new FaissIndex({ type: 'FLAT_L2', dims: 128 });
|
|
111
|
+
|
|
112
|
+
// IVF_FLAT - Fast approximate search (best for 10k - 1M vectors)
|
|
113
|
+
const ivfIndex = new FaissIndex({
|
|
114
|
+
type: 'IVF_FLAT',
|
|
115
|
+
dims: 768,
|
|
116
|
+
nlist: 100, // Number of clusters
|
|
117
|
+
nprobe: 10 // Clusters to search (higher = more accurate, slower)
|
|
118
|
+
});
|
|
119
|
+
await ivfIndex.train(trainingVectors); // Must train before adding vectors!
|
|
120
|
+
|
|
121
|
+
// HNSW - State-of-the-art approximate search (best for large datasets)
|
|
122
|
+
const hnswIndex = new FaissIndex({
|
|
123
|
+
type: 'HNSW',
|
|
124
|
+
dims: 1536,
|
|
125
|
+
M: 16, // Connections per node (higher = more accurate, slower)
|
|
126
|
+
efConstruction: 200, // Construction parameter
|
|
127
|
+
efSearch: 50 // Search parameter (higher = more accurate, slower)
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Methods
|
|
132
|
+
|
|
133
|
+
#### `add(vectors: Float32Array): Promise<void>`
|
|
134
|
+
|
|
135
|
+
Add vectors to the index. Can add a single vector or a batch of vectors.
|
|
136
|
+
|
|
137
|
+
```javascript
|
|
138
|
+
// Single vector
|
|
139
|
+
await index.add(new Float32Array([1, 2, 3, 4]));
|
|
140
|
+
|
|
141
|
+
// Batch of vectors (4 vectors of 4 dimensions each)
|
|
142
|
+
await index.add(new Float32Array([
|
|
143
|
+
1, 0, 0, 0, // Vector 1
|
|
144
|
+
0, 1, 0, 0, // Vector 2
|
|
145
|
+
0, 0, 1, 0, // Vector 3
|
|
146
|
+
0, 0, 0, 1 // Vector 4
|
|
147
|
+
]));
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**Note:** For IVF_FLAT indexes, you must call `train()` before adding vectors.
|
|
151
|
+
|
|
152
|
+
#### `search(query: Float32Array, k: number): Promise<SearchResults>`
|
|
153
|
+
|
|
154
|
+
Search for k nearest neighbors.
|
|
155
|
+
|
|
156
|
+
```javascript
|
|
157
|
+
const query = new Float32Array([1, 0, 0, 0]);
|
|
158
|
+
const results = await index.search(query, 5);
|
|
159
|
+
|
|
160
|
+
// results.distances: Float32Array of L2 distances
|
|
161
|
+
// results.labels: Int32Array of vector indices
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**Returns:**
|
|
165
|
+
- `distances` (Float32Array): L2 distances to nearest neighbors
|
|
166
|
+
- `labels` (Int32Array): Indices of nearest neighbors
|
|
167
|
+
|
|
168
|
+
#### `searchBatch(queries: Float32Array, k: number): Promise<SearchResults>`
|
|
169
|
+
|
|
170
|
+
Perform batch search for multiple queries efficiently.
|
|
171
|
+
|
|
172
|
+
```javascript
|
|
173
|
+
// 3 queries of 4 dimensions each
|
|
174
|
+
const queries = new Float32Array([
|
|
175
|
+
1, 0, 0, 0, // Query 1
|
|
176
|
+
0, 1, 0, 0, // Query 2
|
|
177
|
+
0, 0, 1, 0 // Query 3
|
|
178
|
+
]);
|
|
179
|
+
const results = await index.searchBatch(queries, 5);
|
|
180
|
+
|
|
181
|
+
// results.distances: Float32Array of shape [3 * 5]
|
|
182
|
+
// results.labels: Int32Array of shape [3 * 5]
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
#### `train(vectors: Float32Array): Promise<void>`
|
|
186
|
+
|
|
187
|
+
Train an IVF_FLAT index. Required before adding vectors.
|
|
188
|
+
|
|
189
|
+
```javascript
|
|
190
|
+
// Training vectors (typically 10k-100k vectors)
|
|
191
|
+
const trainingVectors = new Float32Array(/* ... */);
|
|
192
|
+
await ivfIndex.train(trainingVectors);
|
|
193
|
+
await ivfIndex.add(dataVectors); // Now you can add vectors
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
#### `setNprobe(nprobe: number): Promise<void>`
|
|
197
|
+
|
|
198
|
+
Set the number of clusters to search for IVF_FLAT indexes.
|
|
199
|
+
|
|
200
|
+
```javascript
|
|
201
|
+
await ivfIndex.setNprobe(20); // Search more clusters (more accurate, slower)
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
#### `getStats(): IndexStats`
|
|
205
|
+
|
|
206
|
+
Get index statistics.
|
|
207
|
+
|
|
208
|
+
```javascript
|
|
209
|
+
const stats = index.getStats();
|
|
210
|
+
// {
|
|
211
|
+
// ntotal: number, // Total vectors in index
|
|
212
|
+
// dims: number, // Vector dimensions
|
|
213
|
+
// isTrained: boolean, // Whether index is trained (IVF only)
|
|
214
|
+
// type: string // Index type
|
|
215
|
+
// }
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
#### `save(filename: string): Promise<void>`
|
|
219
|
+
|
|
220
|
+
Save index to disk.
|
|
221
|
+
|
|
222
|
+
```javascript
|
|
223
|
+
await index.save('./my-index.faiss');
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
#### `static load(filename: string): Promise<FaissIndex>`
|
|
227
|
+
|
|
228
|
+
Load index from disk.
|
|
229
|
+
|
|
230
|
+
```javascript
|
|
231
|
+
const index = await FaissIndex.load('./my-index.faiss');
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
#### `toBuffer(): Promise<Buffer>`
|
|
235
|
+
|
|
236
|
+
Serialize index to a Node.js Buffer (useful for databases, network transfer, etc.).
|
|
237
|
+
|
|
238
|
+
```javascript
|
|
239
|
+
const buffer = await index.toBuffer();
|
|
240
|
+
// Store in database, send over network, etc.
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
#### `static fromBuffer(buffer: Buffer): Promise<FaissIndex>`
|
|
244
|
+
|
|
245
|
+
Deserialize index from Buffer.
|
|
246
|
+
|
|
247
|
+
```javascript
|
|
248
|
+
const index = await FaissIndex.fromBuffer(buffer);
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
#### `mergeFrom(otherIndex: FaissIndex): Promise<void>`
|
|
252
|
+
|
|
253
|
+
Merge vectors from another index into this index.
|
|
254
|
+
|
|
255
|
+
```javascript
|
|
256
|
+
const index1 = new FaissIndex({ type: 'FLAT_L2', dims: 128 });
|
|
257
|
+
const index2 = new FaissIndex({ type: 'FLAT_L2', dims: 128 });
|
|
258
|
+
|
|
259
|
+
await index1.add(vectors1);
|
|
260
|
+
await index2.add(vectors2);
|
|
261
|
+
|
|
262
|
+
await index1.mergeFrom(index2); // index1 now contains vectors from both
|
|
263
|
+
// Note: index2 is now empty (FAISS behavior)
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
#### `dispose(): void`
|
|
267
|
+
|
|
268
|
+
Explicitly dispose of the index and free resources. Optional - automatic on garbage collection.
|
|
269
|
+
|
|
270
|
+
```javascript
|
|
271
|
+
index.dispose();
|
|
272
|
+
// Index is now unusable - all operations will throw errors
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## Choosing the Right Index Type
|
|
276
|
+
|
|
277
|
+
### FLAT_L2 (IndexFlatL2)
|
|
278
|
+
- **Best for:** Small datasets (< 10k vectors), exact search required
|
|
279
|
+
- **Speed:** O(n) per query - linear scan
|
|
280
|
+
- **Accuracy:** 100% recall (exact results)
|
|
281
|
+
- **Memory:** 4 ร dims ร n bytes
|
|
282
|
+
- **Use case:** Prototyping, small production datasets, when accuracy is critical
|
|
283
|
+
|
|
284
|
+
### IVF_FLAT (IndexIVFFlat)
|
|
285
|
+
- **Best for:** Medium datasets (10k - 1M vectors), can tolerate ~90-95% recall
|
|
286
|
+
- **Speed:** O(nprobe ร n/nlist) per query - much faster than FLAT
|
|
287
|
+
- **Accuracy:** ~90-95% recall (configurable via nprobe)
|
|
288
|
+
- **Memory:** Similar to FLAT + cluster overhead
|
|
289
|
+
- **Requires:** Training on sample data before use
|
|
290
|
+
- **Use case:** Production systems with medium-sized datasets
|
|
291
|
+
|
|
292
|
+
### HNSW (IndexHNSW)
|
|
293
|
+
- **Best for:** Large datasets (> 100k vectors), best speed/accuracy tradeoff
|
|
294
|
+
- **Speed:** O(log n) per query - logarithmic search
|
|
295
|
+
- **Accuracy:** ~95-99% recall (configurable via efSearch)
|
|
296
|
+
- **Memory:** ~1.5-2ร more than FLAT
|
|
297
|
+
- **No training required**
|
|
298
|
+
- **Use case:** Large-scale production systems, best overall performance
|
|
299
|
+
|
|
300
|
+
## Examples
|
|
301
|
+
|
|
302
|
+
### Basic Semantic Search
|
|
303
|
+
|
|
304
|
+
```javascript
|
|
305
|
+
const { FaissIndex } = require('@faiss-node/native');
|
|
306
|
+
|
|
307
|
+
// Create index for 768-dimensional embeddings (e.g., OpenAI)
|
|
308
|
+
const index = new FaissIndex({ type: 'HNSW', dims: 768 });
|
|
309
|
+
|
|
310
|
+
// Add document embeddings
|
|
311
|
+
const documents = [
|
|
312
|
+
{ id: 0, text: "JavaScript is a programming language" },
|
|
313
|
+
{ id: 1, text: "Python is great for data science" },
|
|
314
|
+
{ id: 2, text: "Node.js runs JavaScript on the server" }
|
|
315
|
+
];
|
|
316
|
+
|
|
317
|
+
const embeddings = new Float32Array(/* ... your embeddings ... */);
|
|
318
|
+
await index.add(embeddings);
|
|
319
|
+
|
|
320
|
+
// Search for similar documents
|
|
321
|
+
const queryEmbedding = new Float32Array(/* ... query embedding ... */);
|
|
322
|
+
const results = await index.search(queryEmbedding, 3);
|
|
323
|
+
|
|
324
|
+
console.log('Most similar documents:', results.labels);
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### RAG Pipeline
|
|
328
|
+
|
|
329
|
+
```javascript
|
|
330
|
+
const { FaissIndex } = require('@faiss-node/native');
|
|
331
|
+
|
|
332
|
+
class RAGSystem {
|
|
333
|
+
constructor() {
|
|
334
|
+
this.index = new FaissIndex({ type: 'HNSW', dims: 1536 });
|
|
335
|
+
this.documents = [];
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
async addDocuments(docs, embeddings) {
|
|
339
|
+
this.documents.push(...docs);
|
|
340
|
+
await this.index.add(embeddings);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
async search(queryEmbedding, k = 5) {
|
|
344
|
+
const results = await this.index.search(queryEmbedding, k);
|
|
345
|
+
return results.labels.map(idx => this.documents[idx]);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
async save(path) {
|
|
349
|
+
await this.index.save(path);
|
|
350
|
+
// Also save documents mapping
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### Persistence
|
|
356
|
+
|
|
357
|
+
```javascript
|
|
358
|
+
const { FaissIndex } = require('@faiss-node/native');
|
|
359
|
+
|
|
360
|
+
// Save to disk
|
|
361
|
+
const index = new FaissIndex({ type: 'HNSW', dims: 128 });
|
|
362
|
+
await index.add(vectors);
|
|
363
|
+
await index.save('./index.faiss');
|
|
364
|
+
|
|
365
|
+
// Load from disk
|
|
366
|
+
const loadedIndex = await FaissIndex.load('./index.faiss');
|
|
367
|
+
|
|
368
|
+
// Or serialize to buffer (for databases)
|
|
369
|
+
const buffer = await index.toBuffer();
|
|
370
|
+
// Store in MongoDB, Redis, etc.
|
|
371
|
+
const restoredIndex = await FaissIndex.fromBuffer(buffer);
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
## Performance Tips
|
|
375
|
+
|
|
376
|
+
1. **Use HNSW for large datasets** - Best overall performance
|
|
377
|
+
2. **Batch operations** - Use `searchBatch()` for multiple queries
|
|
378
|
+
3. **Train IVF properly** - Use 10k-100k training vectors
|
|
379
|
+
4. **Tune parameters** - Increase `nprobe` (IVF) or `efSearch` (HNSW) for accuracy
|
|
380
|
+
5. **Reuse indexes** - Save/load instead of recreating
|
|
381
|
+
|
|
382
|
+
## Thread Safety
|
|
383
|
+
|
|
384
|
+
All operations are thread-safe and can be called concurrently:
|
|
385
|
+
|
|
386
|
+
```javascript
|
|
387
|
+
// Safe to call from multiple async operations
|
|
388
|
+
await Promise.all([
|
|
389
|
+
index.add(vectors1),
|
|
390
|
+
index.add(vectors2),
|
|
391
|
+
index.search(query1),
|
|
392
|
+
index.search(query2)
|
|
393
|
+
]);
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
The implementation uses mutex locks to ensure FAISS operations are serialized safely.
|
|
397
|
+
|
|
398
|
+
## Error Handling
|
|
399
|
+
|
|
400
|
+
All methods throw JavaScript errors (not C++ exceptions):
|
|
401
|
+
|
|
402
|
+
```javascript
|
|
403
|
+
try {
|
|
404
|
+
await index.add(vectors);
|
|
405
|
+
} catch (error) {
|
|
406
|
+
if (error.message.includes('disposed')) {
|
|
407
|
+
console.error('Index was disposed');
|
|
408
|
+
} else if (error.message.includes('dimensions')) {
|
|
409
|
+
console.error('Vector dimensions mismatch');
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
## TypeScript Support
|
|
415
|
+
|
|
416
|
+
Full TypeScript definitions are included:
|
|
417
|
+
|
|
418
|
+
```typescript
|
|
419
|
+
import { FaissIndex, FaissIndexConfig, SearchResults } from '@faiss-node/native';
|
|
420
|
+
|
|
421
|
+
const config: FaissIndexConfig = {
|
|
422
|
+
type: 'HNSW',
|
|
423
|
+
dims: 768
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
const index = new FaissIndex(config);
|
|
427
|
+
const results: SearchResults = await index.search(query, 10);
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
## Updating
|
|
431
|
+
|
|
432
|
+
To update to the latest version:
|
|
433
|
+
|
|
434
|
+
```bash
|
|
435
|
+
npm update @faiss-node/native
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
Or install a specific version:
|
|
439
|
+
|
|
440
|
+
```bash
|
|
441
|
+
npm install @faiss-node/native@0.1.2
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
## Development
|
|
445
|
+
|
|
446
|
+
### Building from Source
|
|
447
|
+
|
|
448
|
+
```bash
|
|
449
|
+
# Clone repository
|
|
450
|
+
git clone https://github.com/anupammaurya6767/faiss-node-native.git
|
|
451
|
+
cd faiss-node-native
|
|
452
|
+
|
|
453
|
+
# Install dependencies
|
|
454
|
+
npm install
|
|
455
|
+
|
|
456
|
+
# Build native module
|
|
457
|
+
npm run build
|
|
458
|
+
|
|
459
|
+
# Run tests
|
|
460
|
+
npm test
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
### Running Tests
|
|
464
|
+
|
|
465
|
+
```bash
|
|
466
|
+
npm test # All tests
|
|
467
|
+
npm run test:unit # Unit tests only
|
|
468
|
+
npm run test:integration # Integration tests only
|
|
469
|
+
npm run test:ci # CI tests (faster, no manual tests)
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### Generating Documentation
|
|
473
|
+
|
|
474
|
+
```bash
|
|
475
|
+
npm run docs # Generate Doxygen documentation
|
|
476
|
+
npm run docs:serve # Serve docs locally at http://localhost:8000
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
## Documentation
|
|
480
|
+
|
|
481
|
+
- **API Documentation**: [GitHub Pages](https://anupammaurya6767.github.io/faiss-node-native/)
|
|
482
|
+
- **Examples**: See `examples/` directory
|
|
483
|
+
- **Contributing**: See [CONTRIBUTING.md](./CONTRIBUTING.md)
|
|
484
|
+
|
|
485
|
+
## Comparison with Other Packages
|
|
486
|
+
|
|
487
|
+
### vs. `faiss-node` (ewfian)
|
|
488
|
+
|
|
489
|
+
| Feature | @faiss-node/native | faiss-node |
|
|
490
|
+
|---------|-------------------|------------|
|
|
491
|
+
| Async Operations | โ
Promise-based | โ Synchronous (blocks event loop) |
|
|
492
|
+
| Thread Safety | โ
Mutex-protected | โ Not thread-safe |
|
|
493
|
+
| API Design | โ
High-level wrapper | โ ๏ธ Low-level FAISS classes |
|
|
494
|
+
| TypeScript | โ
Full support | โ ๏ธ Partial |
|
|
495
|
+
| Testing | โ
1000+ tests | โ ๏ธ Minimal |
|
|
496
|
+
| Production Ready | โ
Yes | โ ๏ธ Early stage |
|
|
497
|
+
|
|
498
|
+
## Troubleshooting
|
|
499
|
+
|
|
500
|
+
### Build Errors
|
|
501
|
+
|
|
502
|
+
**macOS: "library not found"**
|
|
503
|
+
```bash
|
|
504
|
+
# Ensure FAISS is installed
|
|
505
|
+
brew install faiss
|
|
506
|
+
|
|
507
|
+
# Check installation
|
|
508
|
+
ls /usr/local/lib/libfaiss*
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
**Linux: "faiss/Index.h: No such file or directory"**
|
|
512
|
+
```bash
|
|
513
|
+
# Build and install FAISS from source (see Prerequisites)
|
|
514
|
+
# Ensure CMAKE_INSTALL_PREFIX=/usr/local
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
### Runtime Errors
|
|
518
|
+
|
|
519
|
+
**"Index has been disposed"**
|
|
520
|
+
- You called `dispose()` or the index was garbage collected
|
|
521
|
+
- Create a new index or don't dispose until done
|
|
522
|
+
|
|
523
|
+
**"Vector dimensions don't match"**
|
|
524
|
+
- Check that your vectors are the correct size
|
|
525
|
+
- For batch operations: `vectors.length % dims === 0`
|
|
526
|
+
|
|
527
|
+
## Contributing
|
|
528
|
+
|
|
529
|
+
Contributions are welcome! Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines.
|
|
530
|
+
|
|
531
|
+
## License
|
|
532
|
+
|
|
533
|
+
MIT License - see [LICENSE](./LICENSE) file for details.
|
|
534
|
+
|
|
535
|
+
## Author
|
|
536
|
+
|
|
537
|
+
**Anupam Maurya**
|
|
538
|
+
|
|
539
|
+
- GitHub: [@anupammaurya6767](https://github.com/anupammaurya6767)
|
|
540
|
+
- Email: anupammaurya6767@gmail.com
|
|
541
|
+
|
|
542
|
+
## Acknowledgments
|
|
543
|
+
|
|
544
|
+
- Built on [Facebook FAISS](https://github.com/facebookresearch/faiss) - the amazing vector similarity search library
|
|
545
|
+
- Inspired by the need for high-performance vector search in Node.js
|
|
546
|
+
- Thanks to the open-source community for feedback and contributions
|
|
547
|
+
|
|
548
|
+
---
|
|
549
|
+
|
|
550
|
+
Made with โค๏ธ for the Node.js community
|
|
551
|
+
|
package/binding.gyp
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
{
|
|
2
|
+
"targets": [
|
|
3
|
+
{
|
|
4
|
+
"target_name": "faiss_node",
|
|
5
|
+
"cflags!": [ "-fno-exceptions" ],
|
|
6
|
+
"cflags_cc!": [ "-fno-exceptions" ],
|
|
7
|
+
"sources": [
|
|
8
|
+
"src/cpp/faiss_index.cpp",
|
|
9
|
+
"src/cpp/napi_bindings.cpp"
|
|
10
|
+
],
|
|
11
|
+
"include_dirs": [
|
|
12
|
+
"<!@(node -p \"require('node-addon-api').include\")",
|
|
13
|
+
"src/cpp",
|
|
14
|
+
"/opt/homebrew/include",
|
|
15
|
+
"/usr/local/include",
|
|
16
|
+
"/usr/include"
|
|
17
|
+
],
|
|
18
|
+
"defines": [
|
|
19
|
+
"NAPI_VERSION=8"
|
|
20
|
+
],
|
|
21
|
+
"conditions": [
|
|
22
|
+
["OS=='mac'", {
|
|
23
|
+
"xcode_settings": {
|
|
24
|
+
"GCC_ENABLE_CPP_EXCEPTIONS": "YES",
|
|
25
|
+
"CLANG_CXX_LIBRARY": "libc++",
|
|
26
|
+
"MACOSX_DEPLOYMENT_TARGET": "11.0",
|
|
27
|
+
"OTHER_CPLUSPLUSFLAGS": [
|
|
28
|
+
"-std=c++17",
|
|
29
|
+
"-fexceptions",
|
|
30
|
+
"-frtti"
|
|
31
|
+
],
|
|
32
|
+
"OTHER_LDFLAGS": [
|
|
33
|
+
"-headerpad_max_install_names"
|
|
34
|
+
]
|
|
35
|
+
},
|
|
36
|
+
"libraries": [
|
|
37
|
+
"-L/opt/homebrew/lib",
|
|
38
|
+
"-L/usr/local/lib",
|
|
39
|
+
"-L/opt/homebrew/opt/libomp/lib",
|
|
40
|
+
"-L/usr/local/opt/libomp/lib",
|
|
41
|
+
"-L/opt/homebrew/Cellar/openblas/0.3.30/lib",
|
|
42
|
+
"-lfaiss",
|
|
43
|
+
"-lopenblas",
|
|
44
|
+
"-lomp"
|
|
45
|
+
],
|
|
46
|
+
"ldflags": [
|
|
47
|
+
"-L/opt/homebrew/lib",
|
|
48
|
+
"-L/usr/local/lib",
|
|
49
|
+
"-L/opt/homebrew/opt/libomp/lib",
|
|
50
|
+
"-L/usr/local/opt/libomp/lib",
|
|
51
|
+
"-L/opt/homebrew/Cellar/openblas/0.3.30/lib",
|
|
52
|
+
"-headerpad_max_install_names"
|
|
53
|
+
]
|
|
54
|
+
}],
|
|
55
|
+
["OS=='linux'", {
|
|
56
|
+
"include_dirs": [
|
|
57
|
+
"<!@(node -p \"require('node-addon-api').include\")",
|
|
58
|
+
"src/cpp",
|
|
59
|
+
"/usr/local/include",
|
|
60
|
+
"/usr/include"
|
|
61
|
+
],
|
|
62
|
+
"libraries": [
|
|
63
|
+
"-L/usr/local/lib",
|
|
64
|
+
"-L/usr/lib",
|
|
65
|
+
"-lfaiss",
|
|
66
|
+
"-lopenblas",
|
|
67
|
+
"-lgomp"
|
|
68
|
+
],
|
|
69
|
+
"ldflags": [
|
|
70
|
+
"-L/usr/local/lib",
|
|
71
|
+
"-L/usr/lib",
|
|
72
|
+
"-Wl,-rpath,/usr/local/lib:/usr/lib/x86_64-linux-gnu"
|
|
73
|
+
],
|
|
74
|
+
"cflags_cc": [
|
|
75
|
+
"-std=c++17",
|
|
76
|
+
"-fexceptions",
|
|
77
|
+
"-frtti",
|
|
78
|
+
"-fopenmp",
|
|
79
|
+
"-I/usr/local/include"
|
|
80
|
+
]
|
|
81
|
+
}]
|
|
82
|
+
],
|
|
83
|
+
"cflags_cc": [
|
|
84
|
+
"-std=c++17",
|
|
85
|
+
"-fexceptions",
|
|
86
|
+
"-frtti"
|
|
87
|
+
]
|
|
88
|
+
}
|
|
89
|
+
]
|
|
90
|
+
}
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Documentation
|
|
2
|
+
|
|
3
|
+
This directory contains the auto-generated API documentation that I set up using Doxygen.
|
|
4
|
+
|
|
5
|
+
## Viewing Documentation
|
|
6
|
+
|
|
7
|
+
- **Online**: Visit [GitHub Pages](https://anupammaurya6767.github.io/faiss-node-native/) (automatically deployed)
|
|
8
|
+
- **Local**: Run `npm run docs:serve` and visit http://localhost:8000
|
|
9
|
+
|
|
10
|
+
## Generating Documentation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm run docs
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
This generates HTML documentation in `docs/html/` using Doxygen.
|
|
17
|
+
|
|
18
|
+
## Documentation Structure
|
|
19
|
+
|
|
20
|
+
- **C++ API**: Native bindings and FAISS wrapper classes
|
|
21
|
+
- **JavaScript API**: High-level FaissIndex class
|
|
22
|
+
- **Examples**: Code examples from `examples/` directory
|
|
23
|
+
|
|
24
|
+
## Auto-Deployment
|
|
25
|
+
|
|
26
|
+
I've set it up so documentation automatically deploys to GitHub Pages when:
|
|
27
|
+
- Code is pushed to `main` branch
|
|
28
|
+
- Source files (`src/**`) or `Doxyfile` are modified
|
|
29
|
+
- I manually trigger it via workflow_dispatch
|
|
30
|
+
|
|
31
|
+
See `.github/workflows/docs.yml` for the deployment workflow I created.
|