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)
| Field | Required | Description |
|---|---|---|
id | Yes | Unique identifier for the vector (non-empty string) |
vector | Yes | Array of doubles representing the embedding |
meta | No | Arbitrary metadata map |
filter | No | Key-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)
| Parameter | Description |
|---|---|
vector | Query vector (must match index dimension) |
topK | Number of results to return (default: 10, max: 512) |
ef | Search quality parameter (default: 128, max: 1024) |
includeVectors | Include 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
| Operator | Description | Example |
|---|---|---|
$eq | Exact match | Map.of("status", Map.of("$eq", "published")) |
$in | Match any in list | Map.of("tags", Map.of("$in", List.of("ai", "ml"))) |
$range | Numeric 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 Search
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)
| Field | Required | Description |
|---|---|---|
id | Yes | Unique identifier |
vector | Yes | Dense embedding vector |
sparseIndices | Yes (hybrid) | Non-zero term positions in sparse vector |
sparseValues | Yes (hybrid) | Weights for each sparse index |
meta | No | Metadata map |
filter | No | Filter 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
sparseIndicesandsparseValues - 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 precisionChoosing Precision:
BINARY: Best for very large datasets where speed and storage are criticalINT8D(default): Recommended for most use cases - good balance of accuracy and performanceINT16D: When you need better accuracy than INT8D but less storage than FLOAT32FLOAT16: Good compromise between precision and storage for embeddingsFLOAT32: 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:
| Code | Description |
|---|---|
| 400 | Bad Request - Invalid parameters |
| 401 | Unauthorized - Invalid or missing authentication |
| 403 | Forbidden - Insufficient permissions |
| 404 | Not Found - Index or vector doesn’t exist |
| 409 | Conflict - Index already exists |
| 500 | Internal Server Error |
See EndeeApiException and EndeeException for details.
API Reference
Endee Class
| Method | Description |
|---|---|
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
| Method | Description |
|---|---|
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 |