Java SDK#

USearch for Java#

Installation#

Installation via Maven Central is not supported due to Continuous Delivery complexity and poor support for native builds. Gradle installation is the recommended approach. For the most up-to-date version, the following Groovy script will download a “fat JAR” containing builds for Linux, Windows, macOS, and Android, compatible with all common hardware platforms:

repositories {
    mavenCentral()

    // Custom repository for USearch JAR
    flatDir {
        dirs 'lib'
    }
}

// Task to download USearch JAR from GitHub releases
task downloadUSearchJar {
    doLast {
        def usearchVersion = '2.20.8'
        def usearchUrl = "https://github.com/unum-cloud/usearch/releases/download/v${usearchVersion}/usearch-${usearchVersion}.jar"
        def usearchFile = file("lib/usearch-${usearchVersion}.jar")

        usearchFile.parentFile.mkdirs()
        if (!usearchFile.exists()) {
            new URL(usearchUrl).withInputStream { i ->
                usearchFile.withOutputStream { it << i }
            }
            println "Downloaded USearch JAR: ${usearchFile.name}"
        }
    }
}

// Make compilation depend on downloading USearch
compileJava.dependsOn downloadUSearchJar

dependencies {
    // USearch JAR from local lib directory (downloaded automatically)
    implementation name: 'usearch', version: '2.20.8', ext: 'jar'
}

Quickstart#

import cloud.unum.usearch.Index;

public class Main {
    public static void main(String[] args) {
        try (Index index = new Index.Config()
                .metric(Index.Metric.COSINE)              // Or "cos"
                .quantization(Index.Quantization.FLOAT32) // Or "f32"
                .dimensions(3)
                .capacity(100)
                .build()) {

            // Add to Index
            float[] vector = {0.1f, 0.2f, 0.3f};
            index.add(42L, vector);

            // Search
            long[] keys = index.search(new float[]{0.1f, 0.2f, 0.3f}, 10);
            for (long key : keys) {
                System.out.println("Found key: " + key);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Serialization#

To save and load the index from disk, use the following methods:

index.save("index.usearch");
index.load("index.usearch");
index.view("index.usearch");

Extracting, Updating, and Removing Values#

It is generally not recommended to use HNSW indexes in case of frequent removals or major distribution shifts. For small updates, you can use the following methods:

float[] vector = index.get(42L);
boolean removed = index.remove(42L);
boolean renamed = index.rename(43L, 42L);

To obtain metadata:

long size = index.size();
long capacity = index.capacity();
long dimensions = index.dimensions();
long connectivity = index.connectivity();

Multiple Data Types and Quantization#

USearch supports hardware-agnostic f64, f32, and i8 quantization for memory efficiency and performance optimization.

// Double precision (f64) for highest accuracy
try (Index doubleIndex = new Index.Config()
        .metric("cos")
        .dimensions(3)
        .quantization("f64")
        .build()) {

    double[] vector = {0.1, 0.2, 0.3};
    doubleIndex.add(42L, vector);

    double[] buffer = new double[3];
    doubleIndex.getInto(42L, buffer); // Memory-efficient retrieval
}

// Byte precision (i8) for memory efficiency
try (Index byteIndex = new Index.Config()
        .metric("cos")
        .dimensions(3)
        .quantization("i8")
        .build()) {

    byte[] vector = {10, 20, 30};
    byteIndex.add(42L, vector);

    byte[] buffer = new byte[3];
    byteIndex.getInto(42L, buffer); // Memory-efficient retrieval
}

Batch Operations#

USearch automatically detects batch operations when vector arrays contain multiple concatenated vectors:

try (Index index = new Index.Config()
        .metric("cos")
        .dimensions(2)
        .build()) {

    // Batch add: 3 vectors in one call
    float[] batchVectors = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f};
    index.add(100L, batchVectors); // Adds vectors at keys 100, 101, 102

    // Verify batch was added correctly
    System.out.println("Index size: " + index.size()); // Output: 3
}

Concurrent Operations#

The USearch index is thread-safe and supports high-performance concurrent operations:

import java.util.concurrent.*;

try (Index index = new Index.Config()
        .metric("cos")
        .dimensions(4)
        .capacity(10000)
        .build()) {

    ExecutorService executor = Executors.newFixedThreadPool(8);

    // Concurrent additions from multiple threads
    CompletableFuture<Void>[] addTasks = new CompletableFuture[4];
    for (int t = 0; t < 4; t++) {
        final int threadId = t;
        addTasks[t] = CompletableFuture.runAsync(() -> {
            for (int i = 0; i < 1000; i++) {
                long key = threadId * 1000L + i;
                float[] vector = generateRandomVector(4);
                index.add(key, vector);
            }
        }, executor);
    }

    // Concurrent searches while adding
    CompletableFuture<Void>[] searchTasks = new CompletableFuture[4];
    for (int t = 0; t < 4; t++) {
        searchTasks[t] = CompletableFuture.runAsync(() -> {
            for (int i = 0; i < 100; i++) {
                float[] query = generateRandomVector(4);
                long[] results = index.search(query, 10);
                processResults(results);
            }
        }, executor);
    }

    // Wait for all operations to complete
    CompletableFuture.allOf(addTasks).join();
    CompletableFuture.allOf(searchTasks).join();
    executor.shutdown();

    System.out.println("Final index size: " + index.size());
}

private static float[] generateRandomVector(int dimensions) {
    float[] vector = new float[dimensions];
    for (int i = 0; i < dimensions; i++) {
        vector[i] = (float) Math.random();
    }
    return vector;
}