Skip to content

Commit 66fc6f1

Browse files
committed
Add: Overloaded Java APIs
1 parent 1408e2f commit 66fc6f1

File tree

7 files changed

+798
-61
lines changed

7 files changed

+798
-61
lines changed

CONTRIBUTING.md

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -427,32 +427,29 @@ java -cp "$(pwd)/build/classes/java/main" -Djava.library.path="$(pwd)/build/libs
427427
Or step by-step:
428428

429429
```sh
430-
cd java/cloud/unum/usearch
431-
javac -h . Index.java NativeUtils.java
430+
javac -cp java -h java/cloud/unum/usearch/ java/cloud/unum/usearch/Index.java
432431

433432
# Ensure JAVA_HOME system environment variable has been set
434433
# e.g. export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
435434

436435
# Ubuntu:
437-
g++ -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux -I../../../../include cloud_unum_usearch_Index.cpp -o cloud_unum_usearch_Index.o
438-
g++ -shared -fPIC -o libusearch.so cloud_unum_usearch_Index.o -lc
436+
g++ -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux -Iinclude java/cloud/unum/usearch/cloud_unum_usearch_Index.cpp -o java/cloud/unum/usearch/cloud_unum_usearch_Index.o
437+
g++ -shared -fPIC -o java/cloud/unum/usearch/libusearch.so java/cloud/unum/usearch/cloud_unum_usearch_Index.o -lc
439438

440439
# Windows
441-
g++ -c -I%JAVA_HOME%\include -I%JAVA_HOME%\include\win32 cloud_unum_usearch_Index.cpp -I..\..\..\..\include -o cloud_unum_usearch_Index.o
442-
g++ -shared -o USearchJNI.dll cloud_unum_usearch_Index.o -Wl,--add-stdcall-alias
440+
g++ -c -I%JAVA_HOME%\include -I%JAVA_HOME%\include\win32 java\cloud\unum\usearch\cloud_unum_usearch_Index.cpp -Iinclude -o java\cloud\unum\usearch\cloud_unum_usearch_Index.o
441+
g++ -shared -o java\cloud\unum\usearch\USearchJNI.dll java\cloud\unum\usearch\cloud_unum_usearch_Index.o -Wl,--add-stdcall-alias
443442

444443
# MacOS
445444
g++ -std=c++11 -c -fPIC \
446-
-I../../../../include \
447-
-I../../../../fp16/include \
448-
-I../../../../simsimd/include \
449-
-I${JAVA_HOME}/include -I${JAVA_HOME}/include/darwin cloud_unum_usearch_Index.cpp -o cloud_unum_usearch_Index.o
450-
g++ -dynamiclib -o libusearch.dylib cloud_unum_usearch_Index.o -lc
451-
452-
# Run linking to that directory
453-
cd ../../../..
454-
cp cloud/unum/usearch/libusearch.* .
455-
java -cp . -Djava.library.path="$(pwd)" cloud.unum.usearch.Index
445+
-Iinclude \
446+
-Ifp16/include \
447+
-Isimsimd/include \
448+
-I${JAVA_HOME}/include -I${JAVA_HOME}/include/darwin java/cloud/unum/usearch/cloud_unum_usearch_Index.cpp -o java/cloud/unum/usearch/cloud_unum_usearch_Index.o
449+
g++ -dynamiclib -o java/cloud/unum/usearch/libusearch.dylib java/cloud/unum/usearch/cloud_unum_usearch_Index.o -lc
450+
451+
# Run from project root
452+
java -cp java -Djava.library.path="java/cloud/unum/usearch" cloud.unum.usearch.Index
456453
```
457454

458455
Or using CMake:

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ In some cases, like Batch operations, feature parity is meaningless, as the host
357357
| Add, search, remove |||||||||
358358
| Save, load, view |||||||||
359359
| User-defined metrics |||||||||
360-
| Batch operations |||| |||||
360+
| Batch operations |||| |||||
361361
| Filter predicates |||||||||
362362
| Joins |||||||||
363363
| Variable-length vectors |||||||||

java/README.md

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,113 @@ long capacity = index.capacity();
7171
long dimensions = index.dimensions();
7272
long connectivity = index.connectivity();
7373
```
74+
75+
## Multiple Data Types and Quantization
76+
77+
USearch supports hardware-agnostic `f64`, `f32`, and `i8` quantization for memory efficiency and performance optimization.
78+
79+
```java
80+
// Double precision (f64) for highest accuracy
81+
try (Index doubleIndex = new Index.Config()
82+
.metric("cos")
83+
.dimensions(3)
84+
.quantization("f64")
85+
.build()) {
86+
87+
double[] vector = {0.1, 0.2, 0.3};
88+
doubleIndex.add(42L, vector);
89+
90+
double[] buffer = new double[3];
91+
doubleIndex.getInto(42L, buffer); // Memory-efficient retrieval
92+
}
93+
94+
// Byte precision (i8) for memory efficiency
95+
try (Index byteIndex = new Index.Config()
96+
.metric("cos")
97+
.dimensions(3)
98+
.quantization("i8")
99+
.build()) {
100+
101+
byte[] vector = {10, 20, 30};
102+
byteIndex.add(42L, vector);
103+
104+
byte[] buffer = new byte[3];
105+
byteIndex.getInto(42L, buffer); // Memory-efficient retrieval
106+
}
107+
```
108+
109+
## Batch Operations
110+
111+
USearch automatically detects batch operations when vector arrays contain multiple concatenated vectors:
112+
113+
```java
114+
try (Index index = new Index.Config()
115+
.metric("cos")
116+
.dimensions(2)
117+
.build()) {
118+
119+
// Batch add: 3 vectors in one call
120+
float[] batchVectors = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f};
121+
index.add(100L, batchVectors); // Adds vectors at keys 100, 101, 102
122+
123+
// Verify batch was added correctly
124+
System.out.println("Index size: " + index.size()); // Output: 3
125+
}
126+
```
127+
128+
## Concurrent Operations
129+
130+
The USearch index is thread-safe and supports high-performance concurrent operations:
131+
132+
```java
133+
import java.util.concurrent.*;
134+
135+
try (Index index = new Index.Config()
136+
.metric("cos")
137+
.dimensions(4)
138+
.capacity(10000)
139+
.build()) {
140+
141+
ExecutorService executor = Executors.newFixedThreadPool(8);
142+
143+
// Concurrent additions from multiple threads
144+
CompletableFuture<Void>[] addTasks = new CompletableFuture[4];
145+
for (int t = 0; t < 4; t++) {
146+
final int threadId = t;
147+
addTasks[t] = CompletableFuture.runAsync(() -> {
148+
for (int i = 0; i < 1000; i++) {
149+
long key = threadId * 1000L + i;
150+
float[] vector = generateRandomVector(4);
151+
index.add(key, vector);
152+
}
153+
}, executor);
154+
}
155+
156+
// Concurrent searches while adding
157+
CompletableFuture<Void>[] searchTasks = new CompletableFuture[4];
158+
for (int t = 0; t < 4; t++) {
159+
searchTasks[t] = CompletableFuture.runAsync(() -> {
160+
for (int i = 0; i < 100; i++) {
161+
float[] query = generateRandomVector(4);
162+
long[] results = index.search(query, 10);
163+
processResults(results);
164+
}
165+
}, executor);
166+
}
167+
168+
// Wait for all operations to complete
169+
CompletableFuture.allOf(addTasks).join();
170+
CompletableFuture.allOf(searchTasks).join();
171+
executor.shutdown();
172+
173+
System.out.println("Final index size: " + index.size());
174+
}
175+
176+
private static float[] generateRandomVector(int dimensions) {
177+
float[] vector = new float[dimensions];
178+
for (int i = 0; i < dimensions; i++) {
179+
vector[i] = (float) Math.random();
180+
}
181+
return vector;
182+
}
183+
```

java/cloud/unum/usearch/Index.java

Lines changed: 126 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ public void add(long key, float vector[]) {
241241
if (c_ptr == 0) {
242242
throw new IllegalStateException("Index already closed");
243243
}
244-
c_add(c_ptr, key, vector);
244+
c_add_f32(c_ptr, key, vector);
245245
}
246246

247247
/**
@@ -255,7 +255,7 @@ public long[] search(float vector[], long count) {
255255
if (c_ptr == 0) {
256256
throw new IllegalStateException("Index already closed");
257257
}
258-
return c_search(c_ptr, vector, count);
258+
return c_search_f32(c_ptr, vector, count);
259259
}
260260

261261
/**
@@ -272,6 +272,108 @@ public float[] get(long key) {
272272
return c_get(c_ptr, key);
273273
}
274274

275+
/**
276+
* Adds a double precision vector with a specified key to the index.
277+
*
278+
* @param key the key associated with the vector
279+
* @param vector the double precision vector data
280+
*/
281+
public void add(long key, double vector[]) {
282+
if (c_ptr == 0) {
283+
throw new IllegalStateException("Index already closed");
284+
}
285+
c_add_f64(c_ptr, key, vector);
286+
}
287+
288+
/**
289+
* Searches for closest vectors to the specified double precision query vector.
290+
*
291+
* @param vector the double precision query vector data
292+
* @param count the number of nearest neighbors to search
293+
* @return an array of keys of the nearest neighbors
294+
*/
295+
public long[] search(double vector[], long count) {
296+
if (c_ptr == 0) {
297+
throw new IllegalStateException("Index already closed");
298+
}
299+
return c_search_f64(c_ptr, vector, count);
300+
}
301+
302+
/**
303+
* Adds an int8 quantized vector with a specified key to the index.
304+
*
305+
* @param key the key associated with the vector
306+
* @param vector the int8 quantized vector data
307+
*/
308+
public void add(long key, byte vector[]) {
309+
if (c_ptr == 0) {
310+
throw new IllegalStateException("Index already closed");
311+
}
312+
c_add_i8(c_ptr, key, vector);
313+
}
314+
315+
/**
316+
* Searches for closest vectors to the specified int8 quantized query vector.
317+
*
318+
* @param vector the int8 quantized query vector data
319+
* @param count the number of nearest neighbors to search
320+
* @return an array of keys of the nearest neighbors
321+
*/
322+
public long[] search(byte vector[], long count) {
323+
if (c_ptr == 0) {
324+
throw new IllegalStateException("Index already closed");
325+
}
326+
return c_search_i8(c_ptr, vector, count);
327+
}
328+
329+
/**
330+
* Retrieves the vector at the specified key and populates the provided float
331+
* buffer.
332+
*
333+
* @param key key to lookup.
334+
* @param buffer buffer to populate with vector data.
335+
* @throws IllegalArgumentException if key is not available or buffer size is
336+
* incorrect.
337+
*/
338+
public void getInto(long key, float[] buffer) {
339+
if (c_ptr == 0) {
340+
throw new IllegalStateException("Index already closed");
341+
}
342+
c_get_into_f32(c_ptr, key, buffer);
343+
}
344+
345+
/**
346+
* Retrieves the vector at the specified key and populates the provided double
347+
* buffer.
348+
*
349+
* @param key key to lookup.
350+
* @param buffer buffer to populate with vector data.
351+
* @throws IllegalArgumentException if key is not available or buffer size is
352+
* incorrect.
353+
*/
354+
public void getInto(long key, double[] buffer) {
355+
if (c_ptr == 0) {
356+
throw new IllegalStateException("Index already closed");
357+
}
358+
c_get_into_f64(c_ptr, key, buffer);
359+
}
360+
361+
/**
362+
* Retrieves the vector at the specified key and populates the provided byte
363+
* buffer.
364+
*
365+
* @param key key to lookup.
366+
* @param buffer buffer to populate with vector data.
367+
* @throws IllegalArgumentException if key is not available or buffer size is
368+
* incorrect.
369+
*/
370+
public void getInto(long key, byte[] buffer) {
371+
if (c_ptr == 0) {
372+
throw new IllegalStateException("Index already closed");
373+
}
374+
c_get_into_i8(c_ptr, key, buffer);
375+
}
376+
275377
/**
276378
* Saves the index to a file.
277379
*
@@ -573,12 +675,6 @@ private static native long c_create(
573675

574676
private static native void c_reserve(long ptr, long capacity);
575677

576-
private static native void c_add(long ptr, long key, float vector[]);
577-
578-
private static native long[] c_search(long ptr, float vector[], long count);
579-
580-
private static native float[] c_get(long ptr, long key);
581-
582678
private static native void c_save(long ptr, String path);
583679

584680
private static native void c_load(long ptr, String path);
@@ -588,4 +684,26 @@ private static native long c_create(
588684
private static native boolean c_remove(long ptr, long key);
589685

590686
private static native boolean c_rename(long ptr, long from, long to);
687+
688+
private static native float[] c_get(long ptr, long key);
689+
690+
// Overloaded methods:
691+
private static native void c_add_f32(long ptr, long key, float vector[]);
692+
693+
private static native void c_add_f64(long ptr, long key, double vector[]);
694+
695+
private static native void c_add_i8(long ptr, long key, byte vector[]);
696+
697+
private static native long[] c_search_f32(long ptr, float vector[], long count);
698+
699+
private static native long[] c_search_f64(long ptr, double vector[], long count);
700+
701+
private static native long[] c_search_i8(long ptr, byte vector[], long count);
702+
703+
private static native void c_get_into_f32(long ptr, long key, float buffer[]);
704+
705+
private static native void c_get_into_f64(long ptr, long key, double buffer[]);
706+
707+
private static native void c_get_into_i8(long ptr, long key, byte buffer[]);
708+
591709
}

0 commit comments

Comments
 (0)