Getting Started with NoriKV Client SDKs¶
Quick start guide for all NoriKV client SDKs.
Installation¶
Choose your preferred language and follow the installation instructions:
Java¶
<!-- Maven -->
<dependency>
<groupId>com.norikv</groupId>
<artifactId>norikv-client</artifactId>
<version>0.1.0</version>
</dependency>
Go¶
TypeScript¶
Python¶
Quick Start Examples¶
Java¶
import com.norikv.client.*;
public class Example {
public static void main(String[] args) {
ClientConfig config = ClientConfig.builder()
.nodes(List.of("localhost:9001", "localhost:9002"))
.totalShards(1024)
.timeout(5000)
.build();
try (NoriKVClient client = new NoriKVClient(config)) {
// Connect
client.connect();
// Put a value
byte[] key = "user:alice".getBytes(StandardCharsets.UTF_8);
byte[] value = "Alice".getBytes(StandardCharsets.UTF_8);
Version version = client.put(key, value, null);
System.out.println("Written at version: " + version);
// Get the value
GetResult result = client.get(key, null);
String retrieved = new String(result.getValue(), StandardCharsets.UTF_8);
System.out.println("Value: " + retrieved);
// Delete
boolean deleted = client.delete(key, null);
System.out.println("Deleted: " + deleted);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Go¶
package main
import (
"context"
"fmt"
"log"
"time"
norikv "github.com/norikv/norikv-go"
)
func main() {
config := norikv.ClientConfig{
Nodes: []string{"localhost:9001", "localhost:9002"},
TotalShards: 1024,
Timeout: 5 * time.Second,
}
client, err := norikv.NewClient(config)
if err != nil {
log.Fatal(err)
}
defer client.Close()
ctx := context.Background()
// Put a value
key := []byte("user:alice")
value := []byte("Alice")
version, err := client.Put(ctx, key, value, nil)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Written at version: %v\n", version)
// Get the value
result, err := client.Get(ctx, key, nil)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Value: %s\n", result.Value)
// Delete
deleted, err := client.Delete(ctx, key, nil)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Deleted: %v\n", deleted)
}
TypeScript¶
import { NoriKVClient, bytesToString } from '@norikv/client';
async function main() {
const client = new NoriKVClient({
nodes: ['localhost:9001', 'localhost:9002'],
totalShards: 1024,
timeout: 5000,
});
await client.connect();
try {
// Put a value
const version = await client.put('user:alice', 'Alice');
console.log(`Written at version: ${version}`);
// Get the value
const result = await client.get('user:alice');
console.log(`Value: ${bytesToString(result.value)}`);
// Delete
const deleted = await client.delete('user:alice');
console.log(`Deleted: ${deleted}`);
} finally {
await client.close();
}
}
main().catch(console.error);
Python¶
import asyncio
from norikv import NoriKVClient, ClientConfig
async def main():
config = ClientConfig(
nodes=["localhost:9001", "localhost:9002"],
total_shards=1024,
timeout=5000,
)
async with NoriKVClient(config) as client:
# Put a value
version = await client.put("user:alice", b"Alice")
print(f"Written at version: {version}")
# Get the value
result = await client.get("user:alice")
print(f"Value: {result.value.decode()}")
# Delete
deleted = await client.delete("user:alice")
print(f"Deleted: {deleted}")
if __name__ == "__main__":
asyncio.run(main())
Core Concepts¶
Client Configuration¶
All SDKs require: - nodes: List of cluster node addresses (host:port) - totalShards: Total number of virtual shards (must match cluster config, typically 1024) - timeout: Request timeout in milliseconds (default: 5000)
Optional: - retry: Retry policy configuration for transient failures
Operations¶
All SDKs support three core operations:
- PUT: Write a key-value pair
- Returns a
Versionfor the written value -
Supports optional TTL, idempotency keys, and CAS
-
GET: Read a value by key
- Returns the value and its version
-
Supports consistency level selection
-
DELETE: Remove a key
- Returns boolean indicating if key was deleted
- Supports idempotency keys and CAS
Resource Management¶
| Language | Pattern | Example |
|---|---|---|
| Java | try-with-resources | try (NoriKVClient client = ...) { } |
| Go | defer | defer client.Close() |
| TypeScript | async close | await client.close() or context manager |
| Python | async with | async with NoriKVClient(...) as client: |
Configuration Examples¶
With Retry Policy¶
Java¶
ClientConfig config = ClientConfig.builder()
.nodes(List.of("localhost:9001"))
.totalShards(1024)
.retry(RetryConfig.builder()
.maxAttempts(10)
.initialDelayMs(100)
.maxDelayMs(5000)
.build())
.build();
Go¶
config := norikv.ClientConfig{
Nodes: []string{"localhost:9001"},
TotalShards: 1024,
Retry: &norikv.RetryConfig{
MaxAttempts: 10,
InitialDelayMs: 100,
MaxDelayMs: 5000,
},
}
TypeScript¶
const client = new NoriKVClient({
nodes: ['localhost:9001'],
totalShards: 1024,
retry: {
maxAttempts: 10,
initialDelayMs: 100,
maxDelayMs: 5000,
},
});
Python¶
from norikv import RetryConfig
config = ClientConfig(
nodes=["localhost:9001"],
total_shards=1024,
retry=RetryConfig(
max_attempts=10,
initial_delay_ms=100,
max_delay_ms=5000,
),
)
Advanced Operations¶
Compare-And-Swap (CAS)¶
Optimistic concurrency control using version matching:
Java¶
GetResult current = client.get(key, null);
PutOptions options = PutOptions.builder()
.ifMatchVersion(current.getVersion())
.build();
client.put(key, newValue, options);
Go¶
result, _ := client.Get(ctx, key, nil)
options := &norikv.PutOptions{
IfMatchVersion: result.Version,
}
client.Put(ctx, key, newValue, options)
TypeScript¶
const result = await client.get(key);
await client.put(key, newValue, {
ifMatchVersion: result.version,
});
Python¶
result = await client.get(key)
await client.put(key, new_value, PutOptions(
if_match_version=result.version,
))
Time-To-Live (TTL)¶
Automatic expiration:
Java¶
PutOptions options = PutOptions.builder()
.ttlMs(60000) // 60 seconds
.build();
client.put(key, value, options);
Go¶
TypeScript¶
Python¶
Idempotency Keys¶
Safe retries:
Java¶
PutOptions options = PutOptions.builder()
.idempotencyKey("order-12345")
.build();
client.put(key, value, options);
Go¶
options := &norikv.PutOptions{
IdempotencyKey: "order-12345",
}
client.Put(ctx, key, value, options)
TypeScript¶
Python¶
Consistency Levels¶
All SDKs support three consistency levels for reads:
| Level | Description | Use Case |
|---|---|---|
| LEASE (default) | Fast lease-based read | Most operations |
| LINEARIZABLE | Strictest consistency | Critical reads |
| STALE_OK | May return stale data | High-throughput reads |
Java¶
GetOptions options = GetOptions.builder()
.consistency(ConsistencyLevel.LINEARIZABLE)
.build();
client.get(key, options);
Go¶
options := &norikv.GetOptions{
Consistency: norikv.ConsistencyLinearizable,
}
client.Get(ctx, key, options)
TypeScript¶
Python¶
Vector Search¶
NoriKV supports vector similarity search for building AI/ML applications, recommendation systems, and semantic search.
Creating a Vector Index¶
Before inserting vectors, create an index with your desired configuration:
Java¶
boolean created = client.vectorCreateIndex(
"embeddings", // namespace
1536, // dimensions
DistanceFunction.COSINE,
VectorIndexType.HNSW,
null // options
);
Go¶
created, err := client.VectorCreateIndex(
ctx,
"embeddings", // namespace
1536, // dimensions
norikv.DistanceCosine,
norikv.VectorIndexHNSW,
nil, // options
)
TypeScript¶
const created = await client.vectorCreateIndex(
'embeddings', // namespace
1536, // dimensions
'cosine', // distance function
'hnsw' // index type
);
Python¶
created = await client.vector_create_index(
"embeddings", # namespace
1536, # dimensions
DistanceFunction.COSINE,
VectorIndexType.HNSW,
)
Inserting Vectors¶
Java¶
float[] embedding = getEmbedding("Hello world");
Version version = client.vectorInsert(
"embeddings",
"doc-123",
embedding,
null
);
Go¶
embedding := getEmbedding("Hello world")
version, err := client.VectorInsert(
ctx,
"embeddings",
"doc-123",
embedding,
nil,
)
TypeScript¶
const embedding = await getEmbedding('Hello world');
const version = await client.vectorInsert(
'embeddings',
'doc-123',
embedding
);
Python¶
embedding = await get_embedding("Hello world")
version = await client.vector_insert(
"embeddings",
"doc-123",
embedding,
)
Searching for Similar Vectors¶
Java¶
float[] query = getEmbedding("Find similar documents");
VectorSearchResult result = client.vectorSearch(
"embeddings",
query,
10, // k nearest neighbors
VectorSearchOptions.builder()
.includeVectors(true)
.build()
);
for (VectorMatch match : result.getMatches()) {
System.out.printf("ID: %s, Distance: %.4f%n",
match.getId(), match.getDistance());
}
Go¶
query := getEmbedding("Find similar documents")
result, err := client.VectorSearch(
ctx,
"embeddings",
query,
10, // k nearest neighbors
&norikv.VectorSearchOptions{
IncludeVectors: true,
},
)
for _, match := range result.Matches {
fmt.Printf("ID: %s, Distance: %.4f\n", match.ID, match.Distance)
}
TypeScript¶
const query = await getEmbedding('Find similar documents');
const result = await client.vectorSearch(
'embeddings',
query,
10, // k nearest neighbors
{ includeVectors: true }
);
for (const match of result.matches) {
console.log(`ID: ${match.id}, Distance: ${match.distance}`);
}
Python¶
query = await get_embedding("Find similar documents")
result = await client.vector_search(
"embeddings",
query,
10, # k nearest neighbors
VectorSearchOptions(include_vectors=True),
)
for match in result.matches:
print(f"ID: {match.id}, Distance: {match.distance}")
Getting a Vector by ID¶
Java¶
float[] vector = client.vectorGet("embeddings", "doc-123");
if (vector != null) {
System.out.printf("Vector has %d dimensions%n", vector.length);
}
Go¶
vector, err := client.VectorGet(ctx, "embeddings", "doc-123")
if err == nil && vector != nil {
fmt.Printf("Vector has %d dimensions\n", len(vector))
}
TypeScript¶
const vector = await client.vectorGet('embeddings', 'doc-123');
if (vector) {
console.log(`Vector has ${vector.length} dimensions`);
}
Python¶
vector = await client.vector_get("embeddings", "doc-123")
if vector:
print(f"Vector has {len(vector)} dimensions")
Deleting Vectors¶
Java¶
Go¶
TypeScript¶
Python¶
Distance Functions¶
| Function | Description | Use Case |
|---|---|---|
| EUCLIDEAN | L2 distance | General purpose |
| COSINE | Cosine similarity (1 - cos) | Text embeddings, normalized vectors |
| INNER_PRODUCT | Negative inner product | Maximum inner product search |
Index Types¶
| Type | Description | Trade-off |
|---|---|---|
| BRUTE_FORCE | Exact linear scan | Exact results, O(n) complexity |
| HNSW | Hierarchical Navigable Small World | Approximate, O(log n) complexity |
Error Handling¶
All SDKs provide typed errors:
Java¶
try {
GetResult result = client.get(key, null);
} catch (KeyNotFoundException e) {
// Key not found
} catch (VersionMismatchException e) {
// CAS conflict
} catch (ConnectionException e) {
// Connection error
}
Go¶
result, err := client.Get(ctx, key, nil)
if errors.Is(err, norikv.ErrKeyNotFound) {
// Key not found
} else if errors.Is(err, norikv.ErrVersionMismatch) {
// CAS conflict
} else if errors.Is(err, norikv.ErrConnection) {
// Connection error
}
TypeScript¶
try {
const result = await client.get(key);
} catch (err) {
if (err instanceof KeyNotFoundError) {
// Key not found
} else if (err instanceof VersionMismatchError) {
// CAS conflict
} else if (err instanceof ConnectionError) {
// Connection error
}
}
Python¶
try:
result = await client.get(key)
except KeyNotFoundError:
# Key not found
except VersionMismatchError:
# CAS conflict
except ConnectionError:
# Connection error
Next Steps¶
SDK-Specific Documentation¶
Cross-SDK Topics¶
- Hash Compatibility - Cross-SDK hash validation
- Error Reference - Unified error codes
- SDK Comparison - Feature comparison
Common Patterns¶
All SDKs have comprehensive Advanced Patterns guides covering: - Distributed Counter - Session Management - Inventory Management - Caching Layer - Rate Limiting - Leader Election - Event Sourcing - Multi-Tenancy
See each SDK's ADVANCED_PATTERNS guide for language-specific implementations.