Skip to content

Commit dd1e197

Browse files
committed
Improve: Zero-copy USearch APIs
1 parent 89b1432 commit dd1e197

File tree

4 files changed

+1008
-52
lines changed

4 files changed

+1008
-52
lines changed

java/cloud/unum/usearch/Index.java

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,23 @@ public void add(long key, float vector[]) {
242242
c_add_f32(c_ptr, key, vector);
243243
}
244244

245+
/**
246+
* Adds a vector with a specified key to the index using ByteBuffer (zero-copy).
247+
*
248+
* @param key the key associated with the vector
249+
* @param vector the vector data as FloatBuffer
250+
*/
251+
public void add(long key, java.nio.FloatBuffer vector) {
252+
if (c_ptr == 0) {
253+
throw new IllegalStateException("Index already closed");
254+
}
255+
if (vector.remaining() != dimensions()) {
256+
throw new IllegalArgumentException(String.format(
257+
"Vector dimensions mismatch: expected %d but got %d", dimensions(), vector.remaining()));
258+
}
259+
c_add_f32_buffer(c_ptr, key, vector);
260+
}
261+
245262
/**
246263
* Searches for closest vectors to the specified query vector.
247264
*
@@ -256,6 +273,55 @@ public long[] search(float vector[], long count) {
256273
return c_search_f32(c_ptr, vector, count);
257274
}
258275

276+
/**
277+
* Searches for closest vectors to the specified query vector using ByteBuffer
278+
* (zero-copy).
279+
*
280+
* @param vector the query vector data as FloatBuffer
281+
* @param count the number of nearest neighbors to search
282+
* @return an array of keys of the nearest neighbors
283+
*/
284+
public long[] search(java.nio.FloatBuffer vector, long count) {
285+
if (c_ptr == 0) {
286+
throw new IllegalStateException("Index already closed");
287+
}
288+
if (vector.remaining() != dimensions()) {
289+
throw new IllegalArgumentException(String.format(
290+
"Vector dimensions mismatch: expected %d but got %d", dimensions(), vector.remaining()));
291+
}
292+
return c_search_f32_buffer(c_ptr, vector, count);
293+
}
294+
295+
/**
296+
* Searches for closest vectors using zero-copy input and zero-allocation
297+
* output.
298+
*
299+
* @param query the query vector data as FloatBuffer
300+
* @param results the output buffer for result keys
301+
* @param maxCount maximum number of results to find
302+
* @return actual number of results found
303+
*/
304+
public int searchInto(java.nio.FloatBuffer query, java.nio.LongBuffer results, long maxCount) {
305+
if (c_ptr == 0) {
306+
throw new IllegalStateException("Index already closed");
307+
}
308+
if (query.remaining() != dimensions()) {
309+
throw new IllegalArgumentException(String.format(
310+
"Query vector dimensions mismatch: expected %d but got %d", dimensions(), query.remaining()));
311+
}
312+
if (results.remaining() < maxCount) {
313+
throw new IllegalArgumentException(String.format(
314+
"Results buffer too small: need %d but only %d remaining", maxCount, results.remaining()));
315+
}
316+
int found = c_search_into_f32_buffer(c_ptr, query, results, maxCount);
317+
// Advance position by the actual number of results, but don't exceed the
318+
// buffer's remaining capacity
319+
int currentPosition = results.position();
320+
int newPosition = Math.min(currentPosition + found, results.limit());
321+
results.position(newPosition);
322+
return found;
323+
}
324+
259325
/**
260326
* Return the contents of the vector at key.
261327
*
@@ -283,6 +349,24 @@ public void add(long key, double vector[]) {
283349
c_add_f64(c_ptr, key, vector);
284350
}
285351

352+
/**
353+
* Adds a double precision vector with a specified key to the index using
354+
* ByteBuffer (zero-copy).
355+
*
356+
* @param key the key associated with the vector
357+
* @param vector the double precision vector data as DoubleBuffer
358+
*/
359+
public void add(long key, java.nio.DoubleBuffer vector) {
360+
if (c_ptr == 0) {
361+
throw new IllegalStateException("Index already closed");
362+
}
363+
if (vector.remaining() != dimensions()) {
364+
throw new IllegalArgumentException(String.format(
365+
"Vector dimensions mismatch: expected %d but got %d", dimensions(), vector.remaining()));
366+
}
367+
c_add_f64_buffer(c_ptr, key, vector);
368+
}
369+
286370
/**
287371
* Searches for closest vectors to the specified double precision query vector.
288372
*
@@ -297,6 +381,55 @@ public long[] search(double vector[], long count) {
297381
return c_search_f64(c_ptr, vector, count);
298382
}
299383

384+
/**
385+
* Searches for closest vectors to the specified double precision query vector
386+
* using ByteBuffer (zero-copy).
387+
*
388+
* @param vector the double precision query vector data as DoubleBuffer
389+
* @param count the number of nearest neighbors to search
390+
* @return an array of keys of the nearest neighbors
391+
*/
392+
public long[] search(java.nio.DoubleBuffer vector, long count) {
393+
if (c_ptr == 0) {
394+
throw new IllegalStateException("Index already closed");
395+
}
396+
if (vector.remaining() != dimensions()) {
397+
throw new IllegalArgumentException(String.format(
398+
"Vector dimensions mismatch: expected %d but got %d", dimensions(), vector.remaining()));
399+
}
400+
return c_search_f64_buffer(c_ptr, vector, count);
401+
}
402+
403+
/**
404+
* Searches for closest vectors using zero-copy input and zero-allocation
405+
* output.
406+
*
407+
* @param query the query vector data as DoubleBuffer
408+
* @param results the output buffer for result keys
409+
* @param maxCount maximum number of results to find
410+
* @return actual number of results found
411+
*/
412+
public int searchInto(java.nio.DoubleBuffer query, java.nio.LongBuffer results, long maxCount) {
413+
if (c_ptr == 0) {
414+
throw new IllegalStateException("Index already closed");
415+
}
416+
if (query.remaining() != dimensions()) {
417+
throw new IllegalArgumentException(String.format(
418+
"Query vector dimensions mismatch: expected %d but got %d", dimensions(), query.remaining()));
419+
}
420+
if (results.remaining() < maxCount) {
421+
throw new IllegalArgumentException(String.format(
422+
"Results buffer too small: need %d but only %d remaining", maxCount, results.remaining()));
423+
}
424+
int found = c_search_into_f64_buffer(c_ptr, query, results, maxCount);
425+
// Advance position by the actual number of results, but don't exceed the
426+
// buffer's remaining capacity
427+
int currentPosition = results.position();
428+
int newPosition = Math.min(currentPosition + found, results.limit());
429+
results.position(newPosition);
430+
return found;
431+
}
432+
300433
/**
301434
* Adds an int8 quantized vector with a specified key to the index.
302435
*
@@ -310,6 +443,24 @@ public void add(long key, byte vector[]) {
310443
c_add_i8(c_ptr, key, vector);
311444
}
312445

446+
/**
447+
* Adds an int8 quantized vector with a specified key to the index using
448+
* ByteBuffer (zero-copy).
449+
*
450+
* @param key the key associated with the vector
451+
* @param vector the int8 quantized vector data as ByteBuffer
452+
*/
453+
public void add(long key, java.nio.ByteBuffer vector) {
454+
if (c_ptr == 0) {
455+
throw new IllegalStateException("Index already closed");
456+
}
457+
if (vector.remaining() != dimensions()) {
458+
throw new IllegalArgumentException(String.format(
459+
"Vector dimensions mismatch: expected %d but got %d", dimensions(), vector.remaining()));
460+
}
461+
c_add_i8_buffer(c_ptr, key, vector);
462+
}
463+
313464
/**
314465
* Searches for closest vectors to the specified int8 quantized query vector.
315466
*
@@ -324,6 +475,55 @@ public long[] search(byte vector[], long count) {
324475
return c_search_i8(c_ptr, vector, count);
325476
}
326477

478+
/**
479+
* Searches for closest vectors to the specified int8 quantized query vector
480+
* using ByteBuffer (zero-copy).
481+
*
482+
* @param vector the int8 quantized query vector data as ByteBuffer
483+
* @param count the number of nearest neighbors to search
484+
* @return an array of keys of the nearest neighbors
485+
*/
486+
public long[] search(java.nio.ByteBuffer vector, long count) {
487+
if (c_ptr == 0) {
488+
throw new IllegalStateException("Index already closed");
489+
}
490+
if (vector.remaining() != dimensions()) {
491+
throw new IllegalArgumentException(String.format(
492+
"Vector dimensions mismatch: expected %d but got %d", dimensions(), vector.remaining()));
493+
}
494+
return c_search_i8_buffer(c_ptr, vector, count);
495+
}
496+
497+
/**
498+
* Searches for closest vectors using zero-copy input and zero-allocation
499+
* output.
500+
*
501+
* @param query the query vector data as ByteBuffer
502+
* @param results the output buffer for result keys
503+
* @param maxCount maximum number of results to find
504+
* @return actual number of results found
505+
*/
506+
public int searchInto(java.nio.ByteBuffer query, java.nio.LongBuffer results, long maxCount) {
507+
if (c_ptr == 0) {
508+
throw new IllegalStateException("Index already closed");
509+
}
510+
if (query.remaining() != dimensions()) {
511+
throw new IllegalArgumentException(String.format(
512+
"Query vector dimensions mismatch: expected %d but got %d", dimensions(), query.remaining()));
513+
}
514+
if (results.remaining() < maxCount) {
515+
throw new IllegalArgumentException(String.format(
516+
"Results buffer too small: need %d but only %d remaining", maxCount, results.remaining()));
517+
}
518+
int found = c_search_into_i8_buffer(c_ptr, query, results, maxCount);
519+
// Advance position by the actual number of results, but don't exceed the
520+
// buffer's remaining capacity
521+
int currentPosition = results.position();
522+
int newPosition = Math.min(currentPosition + found, results.limit());
523+
results.position(newPosition);
524+
return found;
525+
}
526+
327527
/**
328528
* Retrieves the vector at the specified key and populates the provided float
329529
* buffer.
@@ -696,6 +896,8 @@ private static native long c_create(
696896

697897
private static native boolean c_rename(long ptr, long from, long to);
698898

899+
private static native long c_memory_usage(long ptr);
900+
699901
private static native float[] c_get(long ptr, long key);
700902

701903
// Overloaded methods:
@@ -717,4 +919,27 @@ private static native long c_create(
717919

718920
private static native void c_get_into_i8(long ptr, long key, byte buffer[]);
719921

922+
// ByteBuffer overloads for zero-copy operations:
923+
private static native void c_add_f32_buffer(long ptr, long key, java.nio.FloatBuffer vector);
924+
925+
private static native void c_add_f64_buffer(long ptr, long key, java.nio.DoubleBuffer vector);
926+
927+
private static native void c_add_i8_buffer(long ptr, long key, java.nio.ByteBuffer vector);
928+
929+
private static native long[] c_search_f32_buffer(long ptr, java.nio.FloatBuffer vector, long count);
930+
931+
private static native long[] c_search_f64_buffer(long ptr, java.nio.DoubleBuffer vector, long count);
932+
933+
private static native long[] c_search_i8_buffer(long ptr, java.nio.ByteBuffer vector, long count);
934+
935+
// Zero-allocation searchInto methods:
936+
private static native int c_search_into_f32_buffer(long ptr, java.nio.FloatBuffer query, java.nio.LongBuffer results,
937+
long maxCount);
938+
939+
private static native int c_search_into_f64_buffer(long ptr, java.nio.DoubleBuffer query, java.nio.LongBuffer results,
940+
long maxCount);
941+
942+
private static native int c_search_into_i8_buffer(long ptr, java.nio.ByteBuffer query, java.nio.LongBuffer results,
943+
long maxCount);
944+
720945
}

0 commit comments

Comments
 (0)