-
Notifications
You must be signed in to change notification settings - Fork 126
/
FaissService.java
461 lines (421 loc) · 18.2 KB
/
FaissService.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
* Modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*/
package org.opensearch.knn.jni;
import org.opensearch.knn.common.KNNConstants;
import org.opensearch.knn.index.engine.KNNEngine;
import org.opensearch.knn.index.query.KNNQueryResult;
import org.opensearch.knn.index.store.IndexInputWithBuffer;
import org.opensearch.knn.index.store.IndexOutputWithBuffer;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Map;
import static org.opensearch.knn.index.KNNSettings.isFaissAVX2Disabled;
import static org.opensearch.knn.index.KNNSettings.isFaissAVX512Disabled;
import static org.opensearch.knn.jni.PlatformUtils.isAVX2SupportedBySystem;
import static org.opensearch.knn.jni.PlatformUtils.isAVX512SupportedBySystem;
/**
* Service to interact with faiss jni layer. Class dependencies should be minimal
* <p>
* In order to compile C++ header file, run:
* javac -h jni/include src/main/java/org/opensearch/knn/jni/FaissService.java
* src/main/java/org/opensearch/knn/index/query/KNNQueryResult.java
* src/main/java/org/opensearch/knn/common/KNNConstants.java
*/
class FaissService {
static {
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
// Even if the underlying system supports AVX512 and AVX2, users can override and disable it by setting
// 'knn.faiss.avx2.disabled' or 'knn.faiss.avx512.disabled' to true in the opensearch.yml configuration
if (!isFaissAVX512Disabled() && isAVX512SupportedBySystem()) {
System.loadLibrary(KNNConstants.FAISS_AVX512_JNI_LIBRARY_NAME);
} else if (!isFaissAVX2Disabled() && isAVX2SupportedBySystem()) {
System.loadLibrary(KNNConstants.FAISS_AVX2_JNI_LIBRARY_NAME);
} else {
System.loadLibrary(KNNConstants.FAISS_JNI_LIBRARY_NAME);
}
initLibrary();
KNNEngine.FAISS.setInitialized(true);
return null;
});
}
/**
* Initialize an index for the native library. Takes in numDocs to
* allocate the correct amount of memory.
*
* @param numDocs number of documents to be added
* @param dim dimension of the vector to be indexed
* @param parameters parameters to build index
*/
public static native long initIndex(long numDocs, int dim, Map<String, Object> parameters);
/**
* Initialize an index for the native library. Takes in numDocs to
* allocate the correct amount of memory.
*
* @param numDocs number of documents to be added
* @param dim dimension of the vector to be indexed
* @param parameters parameters to build index
*/
public static native long initBinaryIndex(long numDocs, int dim, Map<String, Object> parameters);
/**
* Initialize a byte index for the native library. Takes in numDocs to
* allocate the correct amount of memory.
*
* @param numDocs number of documents to be added
* @param dim dimension of the vector to be indexed
* @param parameters parameters to build index
*/
public static native long initByteIndex(long numDocs, int dim, Map<String, Object> parameters);
/**
* Inserts to a faiss index. The memory occupied by the vectorsAddress will be freed up during the
* function call. So Java layer doesn't need to free up the memory. This is not an ideal behavior because Java layer
* created the memory address and that should only free up the memory.
*
* @param ids ids of documents
* @param vectorsAddress address of native memory where vectors are stored
* @param dim dimension of the vector to be indexed
* @param indexAddress address of native memory where index is stored
* @param threadCount number of threads to use for insertion
*/
public static native void insertToIndex(int[] ids, long vectorsAddress, int dim, long indexAddress, int threadCount);
/**
* Inserts to a faiss index. The memory occupied by the vectorsAddress will be freed up during the
* function call. So Java layer doesn't need to free up the memory. This is not an ideal behavior because Java layer
* created the memory address and that should only free up the memory.
*
* @param ids ids of documents
* @param vectorsAddress address of native memory where vectors are stored
* @param dim dimension of the vector to be indexed
* @param indexAddress address of native memory where index is stored
* @param threadCount number of threads to use for insertion
*/
public static native void insertToBinaryIndex(int[] ids, long vectorsAddress, int dim, long indexAddress, int threadCount);
/**
* Inserts to a faiss index. The memory occupied by the vectorsAddress will be freed up during the
* function call. So Java layer doesn't need to free up the memory. This is not an ideal behavior because Java layer
* created the memory address and that should only free up the memory.
*
* @param ids ids of documents
* @param vectorsAddress address of native memory where vectors are stored
* @param dim dimension of the vector to be indexed
* @param indexAddress address of native memory where index is stored
* @param threadCount number of threads to use for insertion
*/
public static native void insertToByteIndex(int[] ids, long vectorsAddress, int dim, long indexAddress, int threadCount);
/**
* Writes a faiss index.
*
* NOTE: This will always free the index. Do not call free after this.
*
* @param indexAddress address of native memory where index is stored
* @param output Index output wrapper having Lucene's IndexOutput to be used to flush bytes in native engines.
*/
public static native void writeIndex(long indexAddress, IndexOutputWithBuffer output);
/**
* Writes a faiss index.
*
* NOTE: This will always free the index. Do not call free after this.
*
* @param indexAddress address of native memory where index is stored
* @param output Index output wrapper having Lucene's IndexOutput to be used to flush bytes in native engines.
*/
public static native void writeBinaryIndex(long indexAddress, IndexOutputWithBuffer output);
/**
* Writes a faiss index.
*
* NOTE: This will always free the index. Do not call free after this.
*
* @param indexAddress address of native memory where index is stored
* @param output Index output wrapper having Lucene's IndexOutput to be used to flush bytes in native engines.
*/
public static native void writeByteIndex(long indexAddress, IndexOutputWithBuffer output);
/**
* Create an index for the native library with a provided template index
*
* @param ids array of ids mapping to the data passed in
* @param vectorsAddress address of native memory where vectors are stored
* @param dim dimension of the vector to be indexed
* @param output Index output wrapper having Lucene's IndexOutput to be used to flush bytes in native engines.
* @param templateIndex empty template index
* @param parameters additional build time parameters
*/
public static native void createIndexFromTemplate(
int[] ids,
long vectorsAddress,
int dim,
IndexOutputWithBuffer output,
byte[] templateIndex,
Map<String, Object> parameters
);
/**
* Create a binary index for the native library with a provided template index
*
* @param ids array of ids mapping to the data passed in
* @param vectorsAddress address of native memory where vectors are stored
* @param dim dimension of the vector to be indexed
* @param output Index output wrapper having Lucene's IndexOutput to be used to flush bytes in native engines.
* @param templateIndex empty template index
* @param parameters additional build time parameters
*/
public static native void createBinaryIndexFromTemplate(
int[] ids,
long vectorsAddress,
int dim,
IndexOutputWithBuffer output,
byte[] templateIndex,
Map<String, Object> parameters
);
/**
* Create a byte index for the native library with a provided template index
*
* @param ids array of ids mapping to the data passed in
* @param vectorsAddress address of native memory where vectors are stored
* @param dim dimension of the vector to be indexed
* @param output Index output wrapper having Lucene's IndexOutput to be used to flush bytes in native engines.
* @param templateIndex empty template index
* @param parameters additional build time parameters
*/
public static native void createByteIndexFromTemplate(
int[] ids,
long vectorsAddress,
int dim,
IndexOutputWithBuffer output,
byte[] templateIndex,
Map<String, Object> parameters
);
/**
* Load an index into memory
*
* @param indexPath path to index file
* @return pointer to location in memory the index resides in
*/
public static native long loadIndex(String indexPath);
/**
* Load an index into memory via a wrapping having Lucene's IndexInput.
* Instead of directly accessing an index path, this will make Faiss delegate IndexInput to load bytes.
*
* @param readStream IndexInput wrapper having a Lucene's IndexInput reference.
* @return pointer to location in memory the index resides in
*/
public static native long loadIndexWithStream(IndexInputWithBuffer readStream);
/**
* Load a binary index into memory
*
* @param indexPath path to index file
* @return pointer to location in memory the index resides in
*/
public static native long loadBinaryIndex(String indexPath);
/**
* Load a binary index into memory with a wrapping having Lucene's IndexInput.
* Instead of directly accessing an index path, this will make Faiss delegate IndexInput to load bytes.
*
* @param readStream IndexInput wrapper having a Lucene's IndexInput reference.
* @return pointer to location in memory the index resides in
*/
public static native long loadBinaryIndexWithStream(IndexInputWithBuffer readStream);
/**
* Determine if index contains shared state.
*
* @param indexAddr address of index to be checked.
* @return true if index requires shared index state; false otherwise
*/
public static native boolean isSharedIndexStateRequired(long indexAddr);
/**
* Initialize the shared state for an index
*
* @param indexAddr address of the index to initialize from
* @return Address of shared index state address
*/
public static native long initSharedIndexState(long indexAddr);
/**
* Set the index state for an index
*
* @param indexAddr address of index to set state for
* @param shareIndexStateAddr address of shared state to be set
*/
public static native void setSharedIndexState(long indexAddr, long shareIndexStateAddr);
/**
* Query an index without filter
*
* If the "knn" field is a nested field, each vector value within that nested field will be assigned its
* own document ID. In this situation, the term "parent ID" corresponds to the original document ID.
* The arrangement of parent IDs and nested field IDs is assured to have all nested field IDs appearing first,
* followed by the parent ID, in consecutive order without any gaps. Because of this ID pattern,
* we can determine the parent ID of a specific nested field ID using only an array of parent IDs.
*
* @param indexPointer pointer to index in memory
* @param queryVector vector to be used for query
* @param k neighbors to be returned
* @param methodParameters method parameter
* @param parentIds list of parent doc ids when the knn field is a nested field
* @return KNNQueryResult array of k neighbors
*/
public static native KNNQueryResult[] queryIndex(
long indexPointer,
float[] queryVector,
int k,
Map<String, ?> methodParameters,
int[] parentIds
);
/**
* Query an index with filter
*
* @param indexPointer pointer to index in memory
* @param queryVector vector to be used for query
* @param k neighbors to be returned
* @param methodParameters method parameter
* @param filterIds list of doc ids to include in the query result
* @param parentIds list of parent doc ids when the knn field is a nested field
* @return KNNQueryResult array of k neighbors
*/
public static native KNNQueryResult[] queryIndexWithFilter(
long indexPointer,
float[] queryVector,
int k,
Map<String, ?> methodParameters,
long[] filterIds,
int filterIdsType,
int[] parentIds
);
/**
* Query a binary index with filter
*
* @param indexPointer pointer to index in memory
* @param queryVector vector to be used for query
* @param k neighbors to be returned
* @param methodParameters method parameter
* @param filterIds list of doc ids to include in the query result
* @param parentIds list of parent doc ids when the knn field is a nested field
* @return KNNQueryResult array of k neighbors
*/
public static native KNNQueryResult[] queryBinaryIndexWithFilter(
long indexPointer,
byte[] queryVector,
int k,
Map<String, ?> methodParameters,
long[] filterIds,
int filterIdsType,
int[] parentIds
);
/**
* Query a binary index with filter
*
* @param indexPointer pointer to index in memory
* @param queryVector vector to be used for query
* @param k neighbors to be returned
* @param filterIds list of doc ids to include in the query result
* @param parentIds list of parent doc ids when the knn field is a nested field
* @return KNNQueryResult array of k neighbors
*/
public static native KNNQueryResult[] queryBinaryIndexWithFilter(
long indexPointer,
byte[] queryVector,
int k,
long[] filterIds,
int filterIdsType,
int[] parentIds
);
/**
* Free native memory pointer
*/
public static native void free(long indexPointer, boolean isBinary);
/**
* Deallocate memory of the shared index state
*
* @param shareIndexStateAddr address of shared state
*/
public static native void freeSharedIndexState(long shareIndexStateAddr);
/**
* Initialize library
*
*/
public static native void initLibrary();
/**
* Train an empty index
*
* @param indexParameters parameters used to build index
* @param dimension dimension for the index
* @param trainVectorsPointer pointer to where training vectors are stored in native memory
* @return bytes array of trained template index
*/
public static native byte[] trainIndex(Map<String, Object> indexParameters, int dimension, long trainVectorsPointer);
/**
* Train an empty binary index
*
* @param indexParameters parameters used to build index
* @param dimension dimension for the index
* @param trainVectorsPointer pointer to where training vectors are stored in native memory
* @return bytes array of trained template index
*/
public static native byte[] trainBinaryIndex(Map<String, Object> indexParameters, int dimension, long trainVectorsPointer);
/**
* Train an empty byte index
*
* @param indexParameters parameters used to build index
* @param dimension dimension for the index
* @param trainVectorsPointer pointer to where training vectors are stored in native memory
* @return bytes array of trained template index
*/
public static native byte[] trainByteIndex(Map<String, Object> indexParameters, int dimension, long trainVectorsPointer);
/**
* <p>
* The function is deprecated. Use {@link JNICommons#storeVectorData(long, float[][], long)}
* </p>
* Transfer vectors from Java to native
*
* @param vectorsPointer pointer to vectors in native memory. Should be 0 to create vector as well
* @param trainingData data to be transferred
* @return pointer to native memory location of training data
*/
@Deprecated(since = "2.14.0", forRemoval = true)
public static native long transferVectors(long vectorsPointer, float[][] trainingData);
/**
* Range search index with filter
*
* @param indexPointer pointer to index in memory
* @param queryVector vector to be used for query
* @param radius search within radius threshold
* @param methodParameters parameters to be used for the query
* @param indexMaxResultWindow maximum number of results to return
* @param filteredIds list of doc ids to include in the query result
* @param filterIdsType type of filter ids
* @param parentIds list of parent doc ids when the knn field is a nested field
* @return KNNQueryResult array of neighbors within radius
*/
public static native KNNQueryResult[] rangeSearchIndexWithFilter(
long indexPointer,
float[] queryVector,
float radius,
Map<String, ?> methodParameters,
int indexMaxResultWindow,
long[] filteredIds,
int filterIdsType,
int[] parentIds
);
/**
* Range search index
*
* @param indexPointer pointer to index in memory
* @param queryVector vector to be used for query
* @param radius search within radius threshold
* @param methodParameters parameters to be used for the query
* @param indexMaxResultWindow maximum number of results to return
* @param parentIds list of parent doc ids when the knn field is a nested field
* @return KNNQueryResult array of neighbors within radius
*/
public static native KNNQueryResult[] rangeSearchIndex(
long indexPointer,
float[] queryVector,
float radius,
Map<String, ?> methodParameters,
int indexMaxResultWindow,
int[] parentIds
);
}