Skip to Content

Java SDK Usage

This guide covers the core operations for working with vectors in Endee: upserting, querying, and deleting data.

Setting Up Your Domain

The Endee client allows you to configure a custom domain URL and port (default port is 8080):

import io.endee.client.Endee; // Initialize client Endee client = new Endee(); // Set custom base URL for non-default port client.setBaseUrl("http://0.0.0.0:8081/api/v1");

Use setBaseUrl() when running on a non-default port.

Upserting Vectors

The index.upsert() method adds or updates vectors in an existing index.

import io.endee.client.Endee; import io.endee.client.Index; import io.endee.client.types.VectorItem; import java.util.List; import java.util.Map; Endee client = new Endee(); Index index = client.getIndex("my_index"); List<VectorItem> vectors = List.of( VectorItem.builder("vec1", new double[] {0.1, 0.2, 0.3 /* ... */}) .meta(Map.of("title", "First document", "group", 10)) .filter(Map.of("category", "tech", "group", 10)) .build(), VectorItem.builder("vec2", new double[] {0.3, 0.4, 0.5 /* ... */}) .meta(Map.of("title", "Second document")) .filter(Map.of("category", "science")) .build() ); index.upsert(vectors);

Vector Object Fields: (see VectorItem)

FieldRequiredDescription
idYesUnique identifier for the vector (non-empty string)
vectorYesArray of doubles representing the embedding
metaNoArbitrary metadata map
filterNoKey-value pairs for filtering during queries

Maximum 1,000 vectors per upsert call. Vector dimension must match the index dimension. IDs must be unique within a single upsert batch.

Querying the Index

The index.query() method performs a similarity search using a query vector.

import io.endee.client.types.QueryOptions; import io.endee.client.types.QueryResult; List<QueryResult> results = index.query( QueryOptions.builder() .vector(new double[] {0.15, 0.25 /* ... */}) .topK(5) .ef(128) .includeVectors(true) .build() ); for (QueryResult item : results) { System.out.println("ID: " + item.getId()); System.out.println("Similarity: " + item.getSimilarity()); System.out.println("Distance: " + item.getDistance()); System.out.println("Meta: " + item.getMeta()); }

Query Parameters: (see QueryOptions)

ParameterDescription
vectorQuery vector (must match index dimension)
topKNumber of results to return (default: 10, max: 512)
efSearch quality parameter (default: 128, max: 1024)
includeVectorsInclude vector data in results (default: false)

Results are returned as a list of QueryResult objects.

Filtered Querying

Use the filter parameter to restrict results based on filter conditions. All filters are combined with logical AND.

List<QueryResult> results = index.query( QueryOptions.builder() .vector(new double[] {0.15, 0.25 /* ... */}) .topK(5) .filter(List.of( Map.of("category", Map.of("$eq", "tech")), Map.of("score", Map.of("$range", List.of(80, 100))) )) .build() );

Filtering Operators

OperatorDescriptionExample
$eqExact matchMap.of("status", Map.of("$eq", "published"))
$inMatch any in listMap.of("tags", Map.of("$in", List.of("ai", "ml")))
$rangeNumeric range (inclusive)Map.of("score", Map.of("$range", List.of(70, 95)))

The $range operator supports values within [0 – 999]. Normalize larger values before upserting.

Hybrid indexes combine dense and sparse vector search. Create a hybrid index by specifying sparseDimension:

CreateIndexOptions options = CreateIndexOptions.builder("hybrid_index", 384) .sparseDimension(30000) .spaceType(SpaceType.COSINE) .build(); client.createIndex(options);

Upserting Hybrid Vectors

Provide both dense vectors and sparse vector representations using sparseIndices and sparseValues:

Index index = client.getIndex("hybrid_index"); List<VectorItem> vectors = List.of( VectorItem.builder("doc1", new double[] {0.1, 0.2 /* ... */}) .sparseIndices(new int[] {10, 50, 200}) // Non-zero term positions .sparseValues(new double[] {0.8, 0.5, 0.3}) // Weights for each position .meta(Map.of("title", "Document 1")) .build(), VectorItem.builder("doc2", new double[] {0.3, 0.4 /* ... */}) .sparseIndices(new int[] {15, 100, 500}) .sparseValues(new double[] {0.9, 0.4, 0.6}) .meta(Map.of("title", "Document 2")) .build() ); index.upsert(vectors);

Hybrid Vector Fields: (see VectorItem)

FieldRequiredDescription
idYesUnique identifier
vectorYesDense embedding vector
sparseIndicesYes (hybrid)Non-zero term positions in sparse vector
sparseValuesYes (hybrid)Weights for each sparse index
metaNoMetadata map
filterNoFilter fields

sparseIndices and sparseValues must have the same length. Values in sparseIndices must be within [0, sparseDimension).

Querying Hybrid Index

Provide both dense and sparse query vectors:

List<QueryResult> results = index.query( QueryOptions.builder() .vector(new double[] {0.15, 0.25 /* ... */}) // Dense query .sparseIndices(new int[] {10, 100, 300}) // Sparse query positions .sparseValues(new double[] {0.7, 0.5, 0.4}) // Sparse query weights .topK(5) .build() ); for (QueryResult item : results) { System.out.println("ID: " + item.getId() + ", Similarity: " + item.getSimilarity()); }

You can also query with:

  • Dense only: Provide only vector
  • Sparse only: Provide only sparseIndices and sparseValues
  • Hybrid: Provide all three for combined results

Deletion Methods

Delete by ID

index.deleteVector("vec1");

Delete by Filter

Delete all vectors matching specific filters:

index.deleteWithFilter(List.of( Map.of("category", Map.of("$eq", "tech")) ));

Delete Index

client.deleteIndex("my_index");

Deletion operations are irreversible.

Additional Operations

Get Vector by ID

Returns a VectorInfo object:

import io.endee.client.types.VectorInfo; VectorInfo vector = index.getVector("vec1"); System.out.println("ID: " + vector.getId()); System.out.println("Vector: " + Arrays.toString(vector.getVector())); System.out.println("Meta: " + vector.getMeta()); System.out.println("Norm: " + vector.getNorm());

Describe Index

Returns an IndexDescription object:

import io.endee.client.types.IndexDescription; IndexDescription info = index.describe(); System.out.println(info); // IndexDescription{name='my_index', spaceType=COSINE, dimension=384, // sparseDimension=0, isHybrid=false, count=1000, // precision=INT8D, m=16}

Check if Index is Hybrid

boolean isHybrid = index.isHybrid();

Precision Options

Endee supports different quantization precision levels via the Precision enum:

import io.endee.client.types.Precision; Precision.BINARY; // Binary quantization (1-bit) - smallest storage, fastest search Precision.INT8D; // 8-bit integer quantization (default) - balanced performance Precision.INT16D; // 16-bit integer quantization - higher precision Precision.FLOAT16; // 16-bit floating point - good balance Precision.FLOAT32; // 32-bit floating point - highest precision

Choosing Precision:

  • BINARY: Best for very large datasets where speed and storage are critical
  • INT8D (default): Recommended for most use cases - good balance of accuracy and performance
  • INT16D: When you need better accuracy than INT8D but less storage than FLOAT32
  • FLOAT16: Good compromise between precision and storage for embeddings
  • FLOAT32: When you need maximum precision and storage is not a concern

See the Types Reference for complete details.

Error Handling

The Java SDK uses specific exception classes for error handling:

import io.endee.client.exception.EndeeException; import io.endee.client.exception.EndeeApiException; try { client.createIndex(options); } catch (EndeeApiException e) { // API-specific errors (e.g., 400, 401, 404, 409, 500) System.err.println("Status Code: " + e.getStatusCode()); System.err.println("Error Body: " + e.getErrorBody()); } catch (EndeeException e) { // Client errors (network, serialization, etc.) System.err.println("Client Error: " + e.getMessage()); } catch (IllegalArgumentException e) { // Validation errors (invalid parameters) System.err.println("Validation Error: " + e.getMessage()); }

HTTP Status Codes:

CodeDescription
400Bad Request - Invalid parameters
401Unauthorized - Invalid or missing authentication
403Forbidden - Insufficient permissions
404Not Found - Index or vector doesn’t exist
409Conflict - Index already exists
500Internal Server Error

See EndeeApiException and EndeeException for details.

API Reference

Endee Class

MethodDescription
Endee()Create client without auth (connects to localhost:8080)
Endee(String token)Create client with auth token
setBaseUrl(String url)Set a custom base URL
createIndex(CreateIndexOptions)Create a new index - accepts CreateIndexOptions
listIndexes()List all indexes (returns JSON string)
deleteIndex(String name)Delete an index
getIndex(String name)Get reference to an index - returns Index

Index Class

MethodDescription
upsert(List<VectorItem>)Insert or update vectors - accepts VectorItem list
query(QueryOptions)Search for similar vectors - accepts QueryOptions, returns QueryResult list
deleteVector(String id)Delete a vector by ID
deleteWithFilter(List<Map>)Delete vectors by filter
getVector(String id)Get a vector by ID - returns VectorInfo
describe()Get index info - returns IndexDescription
isHybrid()Check if index supports hybrid search - returns boolean