Using Go modules:
go get github.com/deven96/ahnlich/sdk/ahnlich-client-go@vX.Y.Zor add to your go.mod:
require (
github.com/deven96/ahnlich/sdk/ahnlich-client-go vX.Y.Z
)This module provides:
- gRPC service stubs for DB and AI
- Pipeline utilities for batching RPC calls
All DB query/response types live under:
import "github.com/deven96/ahnlich/sdk/ahnlich-client-go/grpc/db"All AI query/response types live under:
import "github.com/deven96/ahnlich/sdk/ahnlich-client-go/grpc/ai"package example
import (
"context"
"fmt"
"log"
"time"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
algorithm "github.com/deven96/ahnlich/sdk/ahnlich-client-go/grpc/algorithm/algorithms"
dbsvc "github.com/deven96/ahnlich/sdk/ahnlich-client-go/grpc/services/db_service"
dbquery "github.com/deven96/ahnlich/sdk/ahnlich-client-go/grpc/db/query"
keyval "github.com/deven96/ahnlich/sdk/ahnlich-client-go/grpc/keyval"
metadata "github.com/deven96/ahnlich/sdk/ahnlich-client-go/grpc/metadata"
predicates "github.com/deven96/ahnlich/sdk/ahnlich-client-go/grpc/predicates"
)
const ServerAddr = "127.0.0.1:1369"
// ExampleDBClient holds the gRPC connection and client.
type ExampleDBClient struct {
conn *grpc.ClientConn
client dbsvc.DBServiceClient
}
// NewDBClient connects to the Ahnlich DB server.
func NewDBClient(ctx context.Context) (*ExampleDBClient, error) {
conn, err := grpc.DialContext(
ctx,
ServerAddr,
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithBlock(),
)
if err != nil {
return nil, fmt.Errorf("failed to dial DB server %q: %w", ServerAddr, err)
}
client := dbsvc.NewDBServiceClient(conn)
return &ExampleDBClient{conn: conn, client: client}, nil
}
// Close closes the gRPC connection.
func (c *ExampleDBClient) Close() error {
return c.conn.Close()
}import (
"context"
"fmt"
"time"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
algorithm "github.com/deven96/ahnlich/sdk/ahnlich-client-go/grpc/algorithm/algorithms"
aisvc "github.com/deven96/ahnlich/sdk/ahnlich-client-go/grpc/services/ai_service"
aiquery "github.com/deven96/ahnlich/sdk/ahnlich-client-go/grpc/ai/query"
aimodel "github.com/deven96/ahnlich/sdk/ahnlich-client-go/grpc/ai/models"
keyval "github.com/deven96/ahnlich/sdk/ahnlich-client-go/grpc/keyval"
metadata "github.com/deven96/ahnlich/sdk/ahnlich-client-go/grpc/metadata"
preprocess "github.com/deven96/ahnlich/sdk/ahnlich-client-go/grpc/ai/preprocess"
predicates "github.com/deven96/ahnlich/sdk/ahnlich-client-go/grpc/predicates"
)
const AIAddr = "127.0.0.1:1370"
// ExampleAIClient holds the gRPC connection and AI client.
type ExampleAIClient struct {
conn *grpc.ClientConn
client aisvc.AIServiceClient
}
// NewAIClient connects to the Ahnlich AI server.
func NewAIClient(ctx context.Context) (*ExampleAIClient, error) {
conn, err := grpc.DialContext(
ctx,
AIAddr,
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithBlock(),
)
if err != nil {
return nil, fmt.Errorf("failed to dial AI server %q: %w", AIAddr, err)
}
client := aisvc.NewAIServiceClient(conn)
return &ExampleAIClient{conn: conn, client: client}, nil
}
// Close closes the gRPC connection.
func (c *ExampleAIClient) Close() error {
return c.conn.Close()
}Go’s gRPC client reuses connections under the hood. For advanced pooling, wrap the
*grpc.ClientConnaccordingly.
func (c *ExampleDBClient) examplePingDB() error {
resp, err := c.client.Ping(c.ctx, &dbquery.Ping{})
if err != nil { return err }
fmt.Println("Ping:", resp)
return nil
}func (c *ExampleDBClient) exampleInfoServer() error {
resp, err := c.client.InfoServer(c.ctx, &dbquery.InfoServer{})
fmt.Println("InfoServer:", resp)
return err
}func (c *ExampleDBClient) exampleListStores() error {
resp, err := c.client.ListStores(c.ctx, &dbquery.ListStores{})
if err != nil { return err }
for _, s := range resp.Stores {
// Each StoreInfo includes Name, Len, SizeInBytes, NonLinearIndices,
// PredicateIndices ([]string), and Dimension (uint32).
fmt.Printf("Store: %s, Dimension: %d, PredicateIndices: %v\n",
s.Name, s.Dimension, s.PredicateIndices)
}
return nil
}func (c *ExampleDBClient) exampleGetStore() error {
resp, err := c.client.GetStore(c.ctx, &dbquery.GetStore{Store: "my_store"})
if err != nil { return err }
// resp is a *StoreInfo with Name, Len, SizeInBytes, NonLinearIndices,
// PredicateIndices ([]string), and Dimension (uint32).
fmt.Printf("Store: %s, Dimension: %d, PredicateIndices: %v\n",
resp.Name, resp.Dimension, resp.PredicateIndices)
return nil
}func (c *ExampleDBClient) exampleCreateStore() error {
_, err := c.client.CreateStore(c.ctx, &dbquery.CreateStore{Store:"my_store", Dimension:4})
return err
}func (c *ExampleDBClient) exampleSet() error {
entries := []*keyval.DbStoreEntry{{Key:&keyval.StoreKey{Key:[]float32{1,2,3,4}},Value:&keyval.StoreValue{Value:map[string]*metadata.MetadataValue{"label":{Value:&metadata.MetadataValue_RawString{RawString:"A"}}}}}}
_, err := c.client.Set(c.ctx, &dbquery.Set{Store:"my_store", Inputs:entries})
return err
}func (c *ExampleDBClient) exampleGetSimN() error {
resp, err := c.client.GetSimN(c.ctx, &dbquery.GetSimN{Store:"my_store", SearchInput:&keyval.StoreKey{Key:[]float32{1,2,3,4}}, ClosestN:3})
fmt.Println("GetSimN:", resp.Entries)
return err
}func (c *ExampleDBClient) exampleGetKey() error {
resp, err := c.client.GetKey(c.ctx, &dbquery.GetKey{Store:"my_store", Keys:[]*keyval.StoreKey{{Key:[]float32{1,2,3,4}}}})
fmt.Println("GetKey:", resp.Entries)
return err
}func (c *ExampleDBClient) exampleGetByPredicate() error {
cond := &predicates.PredicateCondition{Kind:&predicates.PredicateCondition_Value{Value:&predicates.Predicate{Kind:&predicates.Predicate_Equals{Equals:&predicates.Equals{Key:"label",Value:&metadata.MetadataValue{Value:&metadata.MetadataValue_RawString{RawString:"A"}}}}}}}
resp, err := c.client.GetByPredicate(c.ctx, &dbquery.GetByPredicate{Store:"my_store", Condition:cond})
fmt.Println("GetByPredicate:", resp.Entries)
return err
}func (c *ExampleDBClient) exampleCreatePredicateIndex() error {
_, err := c.client.CreatePredicateIndex(c.ctx, &dbquery.CreatePredIndex{Store:"my_store", Predicates:[]string{"label"}})
return err
} func (c *ExampleDBClient) exampleDropPredicateIndex() error {
_, err := c.client.DropPredicateIndex(c.ctx, &dbquery.DropPredIndex{Store:"my_store", Predicates:[]string{"label"}, ErrorIfNotExists:true})
return err
}func (c *ExampleDBClient) exampleDeleteKey() error {
_, err := c.client.DelKey(c.ctx, &dbquery.DelKey{Store:"my_store", Keys:[]*keyval.StoreKey{{Key:[]float32{1,2,3,4}}}})
return err
}func (c *ExampleDBClient) exampleDropStore() error {
_, err := c.client.DropStore(c.ctx, &dbquery.DropStore{Store: "my_store"})
return err
}func (c *ExampleDBClient) exampleListConnectedClients() error {
resp, err := c.client.ListClients(c.ctx, &dbquery.ListClients{})
if err != nil {
return err
}
fmt.Println("Connected Clients:", resp.Clients)
return nil
}import (
nonlinear "github.com/deven96/ahnlich/sdk/ahnlich-client-go/grpc/algorithm/nonlinear"
)
func (c *ExampleDBClient) exampleCreateNonLinearAlgoIndex() error {
// Create a KDTree index
_, err := c.client.CreateNonLinearAlgorithmIndex(c.ctx, &dbquery.CreateNonLinearAlgorithmIndex{
Store: "my_store",
NonLinearIndices: []*nonlinear.NonLinearIndex{
{Index: &nonlinear.NonLinearIndex_Kdtree{Kdtree: &nonlinear.KDTreeConfig{}}},
},
})
if err != nil { return err }
// Or create an HNSW index (with optional config)
_, err = c.client.CreateNonLinearAlgorithmIndex(c.ctx, &dbquery.CreateNonLinearAlgorithmIndex{
Store: "my_store",
NonLinearIndices: []*nonlinear.NonLinearIndex{
{Index: &nonlinear.NonLinearIndex_Hnsw{Hnsw: &nonlinear.HNSWConfig{}}},
},
})
return err
}func (c *ExampleDBClient) exampleDropNonLinearAlgoIndex() error {
_, err := c.client.DropNonLinearAlgorithmIndex(c.ctx, &dbquery.DropNonLinearAlgorithmIndex{
Store: "my_store",
NonLinearIndices: []nonlinear.NonLinearAlgorithm{nonlinear.NonLinearAlgorithm_KDTree},
ErrorIfNotExists: true,
})
return err
}func (c *ExampleDBClient) exampleDeletePredicate() error {
cond := &predicates.PredicateCondition{
Kind: &predicates.PredicateCondition_Value{Value: &predicates.Predicate{
Kind: &predicates.Predicate_Equals{Equals: &predicates.Equals{
Key: "label",
Value: &metadata.MetadataValue{Value: &metadata.MetadataValue_RawString{RawString: "A"}},
}},
}},
}
_, err := c.client.DelPred(c.ctx, &dbquery.DelPred{
Store: "my_store",
Condition: cond,
})
return err
}func (c *ExampleAIClient) examplePingAI(ctx context.Context) error {
resp, err := c.client.Ping(c.ctx, &aiquery.Ping{})
if err != nil {
return err
}
fmt.Println("AI Ping:", resp)
return nil
}func (c *ExampleAIClient) exampleInfoServerAI(ctx context.Context) error {
resp, err := c.client.InfoServer(c.ctx, &aiquery.InfoServer{})
if err != nil {
return err
}
fmt.Println("AI InfoServer:", resp)
return nil
}func (c *ExampleAIClient) exampleListStoresAI(ctx context.Context) error {
resp, err := c.client.ListStores(c.ctx, &aiquery.ListStores{})
if err != nil {
return err
}
for _, s := range resp.Stores {
// Each AIStoreInfo includes Name, QueryModel, IndexModel, EmbeddingSize,
// PredicateIndices ([]string), Dimension (uint32), and optional DbInfo (*db.server.StoreInfo).
fmt.Printf("Store: %s, QueryModel: %v, IndexModel: %v, EmbeddingSize: %d, Dimension: %d, PredicateIndices: %v, DbInfo: %v\n",
s.Name, s.QueryModel, s.IndexModel, s.EmbeddingSize, s.Dimension, s.PredicateIndices, s.DbInfo)
}
return nil
}func (c *ExampleAIClient) exampleGetStoreAI(ctx context.Context) error {
resp, err := c.client.GetStore(c.ctx, &aiquery.GetStore{Store: "ai_store"})
if err != nil { return err }
// resp is a *AIStoreInfo with Name, QueryModel, IndexModel, EmbeddingSize,
// PredicateIndices ([]string), Dimension (uint32), and optional DbInfo (*db.server.StoreInfo).
fmt.Printf("Store: %s, QueryModel: %v, IndexModel: %v, EmbeddingSize: %d, Dimension: %d, PredicateIndices: %v, DbInfo: %v\n",
resp.Name, resp.QueryModel, resp.IndexModel, resp.EmbeddingSize, resp.Dimension, resp.PredicateIndices, resp.DbInfo)
return nil
}func (c *ExampleAIClient) exampleCreateStoreAI(ctx context.Context) error {
_, err := c.client.CreateStore(c.ctx, &aiquery.CreateStore{
Store: "ai_store",
QueryModel: aimodel.AIModel_ALL_MINI_LM_L6_V2,
IndexModel: aimodel.AIModel_ALL_MINI_LM_L6_V2,
})
return err
}func (c *ExampleAIClient) exampleSetAI(ctx context.Context) error {
inputs := []*keyval.AiStoreEntry{
{
Key: &keyval.StoreInput{Value: &keyval.StoreInput_RawString{RawString: "X"}},
Value: &keyval.StoreValue{Value: map[string]*metadata.MetadataValue{
"f": {Value: &metadata.MetadataValue_RawString{RawString: "v"}},
}},
},
}
_, err := c.client.Set(c.ctx, &aiquery.Set{
Store: "ai_store",
Inputs: inputs,
PreprocessAction: preprocess.PreprocessAction_NoPreprocessing,
})
return err
}func (c *ExampleAIClient) exampleGetSimNAI(ctx context.Context) error {
resp, err := c.client.GetSimN(c.ctx, &aiquery.GetSimN{
Store: "ai_store",
SearchInput: &keyval.StoreInput{Value: &keyval.StoreInput_RawString{RawString: "X"}},
ClosestN: 3,
})
if err != nil {
return err
}
fmt.Println("AI GetSimN:", resp.Entries)
return nil
}func (c *ExampleAIClient) exampleGetByPredicateAI(ctx context.Context) error {
cond := &predicates.PredicateCondition{
Kind: &predicates.PredicateCondition_Value{Value: &predicates.Predicate{
Kind: &predicates.Predicate_Equals{Equals: &predicates.Equals{
Key: "f",
Value: &metadata.MetadataValue{Value: &metadata.MetadataValue_RawString{RawString: "v"}},
}},
}},
}
resp, err := c.client.GetByPredicate(c.ctx, &aiquery.GetByPredicate{
Store: "ai_store",
Condition: cond,
})
if err != nil {
return err
}
fmt.Println("AI GetByPredicate:", resp.Entries)
return nil
}func (c *ExampleAIClient) exampleCreatePredicateIndexAI(ctx context.Context) error {
_, err := c.client.CreatePredicateIndex(c.ctx, &aiquery.CreatePredicateIndex{
Store: "ai_store",
Predicates: []string{"f"},
})
return err
}func (c *ExampleAIClient) exampleDropPredicateIndexAI(ctx context.Context) error {
_, err := c.client.DropPredicateIndex(c.ctx, &aiquery.DropPredicateIndex{
Store: "ai_store",
Predicates: []string{"f"},
ErrorIfNotExists: true,
})
return err
}func (c *ExampleAIClient) exampleDeleteKeyAI(ctx context.Context) error {
_, err := c.client.DeleteKey(c.ctx, &aiquery.DeleteKey{
Store: "ai_store",
Keys: []*keyval.StoreInput{{Value: &keyval.StoreInput_RawString{RawString: "X"}}},
})
return err
}func (c *ExampleAIClient) exampleDropStoreAI(ctx context.Context) error {
_, err := c.client.DropStore(c.ctx, &aiquery.DropStore{
Store: "ai_store",
ErrorIfNotExists: true,
})
return err
}import (
nonlinear "github.com/deven96/ahnlich/sdk/ahnlich-client-go/grpc/algorithm/nonlinear"
)
func (c *ExampleAIClient) exampleCreateNonLinearIndexAI(ctx context.Context) error {
// Create a KDTree index
_, err := c.client.CreateNonLinearAlgorithmIndex(c.ctx, &aiquery.CreateNonLinearAlgorithmIndex{
Store: "ai_store",
NonLinearIndices: []*nonlinear.NonLinearIndex{
{Index: &nonlinear.NonLinearIndex_Kdtree{Kdtree: &nonlinear.KDTreeConfig{}}},
},
})
if err != nil { return err }
// Or create an HNSW index (with optional config)
_, err = c.client.CreateNonLinearAlgorithmIndex(c.ctx, &aiquery.CreateNonLinearAlgorithmIndex{
Store: "ai_store",
NonLinearIndices: []*nonlinear.NonLinearIndex{
{Index: &nonlinear.NonLinearIndex_Hnsw{Hnsw: &nonlinear.HNSWConfig{}}},
},
})
return err
}func (c *ExampleAIClient) exampleDropNonLinearIndexAI(ctx context.Context) error {
_, err := c.client.DropNonLinearAlgorithmIndex(c.ctx, &aiquery.DropNonLinearAlgorithmIndex{
Store: "ai_store",
NonLinearIndices: []nonlinear.NonLinearAlgorithm{nonlinear.NonLinearAlgorithm_KDTree},
ErrorIfNotExists: true,
})
return err
}Use pipeline to combine multiple calls:
import (
"context"
"fmt"
"time"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc"
pipeline "github.com/deven96/ahnlich/sdk/ahnlich-client-go/grpc/db/pipeline"
dbquery "github.com/deven96/ahnlich/sdk/ahnlich-client-go/grpc/db/query"
dbsvc "github.com/deven96/ahnlich/sdk/ahnlich-client-go/grpc/services/db_service"
keyval "github.com/deven96/ahnlich/sdk/ahnlich-client-go/grpc/keyval"
)
const ServerAddr = "127.0.0.1:1369"
func examplePipelineDB() error {
c.ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
conn, err := grpc.DialContext(c.ctx, proc.ServerAddr, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithBlock())
if err != nil {
return fmt.Errorf("failed to dial DB server %q: %w", ServerAddr, err)
}
defer conn.Close()
client := dbsvc.NewDBServiceClient(conn)
// Build pipeline queries
setQ := &pipeline.DBQuery{Query: &pipeline.DBQuery_Set{Set: &dbquery.Set{
Store: "my_store",
Inputs: []*keyval.DbStoreEntry{/* ... */},
}}}
getQ := &pipeline.DBQuery{Query: &pipeline.DBQuery_GetKey{GetKey: &dbquery.GetKey{
Store: "my_store",
Keys: []*keyval.StoreKey{/* ... */},
}}}
// Execute pipeline
req := &pipeline.DBRequestPipeline{Queries: []*pipeline.DBQuery{setQ, getQ}}
resp, err := client.Pipeline(c.ctx, req)
if err != nil {
return err
}
fmt.Println("Pipeline responses:", resp.Responses)
return nil
}import (
"context"
"fmt"
"time"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc"
pipeline "github.com/deven96/ahnlich/sdk/ahnlich-client-go/grpc/ai/pipeline"
aisvc "github.com/deven96/ahnlich/sdk/ahnlich-client-go/grpc/services/ai_service"
aiquery "github.com/deven96/ahnlich/sdk/ahnlich-client-go/grpc/ai/query"
keyval "github.com/deven96/ahnlich/sdk/ahnlich-client-go/grpc/keyval"
)
const ServerAddr = "127.0.0.1:1370"
func examplePipelineAI() error {
c.ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
conn, err := grpc.DialContext(c.ctx, proc.ServerAddr, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithBlock())
if err != nil {
return fmt.Errorf("failed to dial AI server %q: %w", ServerAddr, err)
}
defer conn.Close()
client := aisvc.NewAIServiceClient(conn)
// Build pipeline queries
setQ := &pipeline.AIQuery{Query: &pipeline.AIQuery_Set{Set: &aiquery.Set{
Store: "ai_store",
Inputs: []*keyval.AiStoreEntry{/* ... */},
}}}
simQ := &pipeline.AIQuery{Query: &pipeline.AIQuery_GetSimN{GetSimN: &aiquery.GetSimN{
Store: "ai_store",
SearchInput: &keyval.StoreInput{Value: &keyval.StoreInput_RawString{RawString: "X"}},
ClosestN: 3,
}}}
// Execute pipeline
req := &pipeline.AIRequestPipeline{Queries: []*pipeline.AIQuery{setQ, simQ}}
resp, err := client.Pipeline(c.ctx, req)
if err != nil {
return err
}
fmt.Println("AI pipeline responses:", resp.Responses)
return nil
}make install-dependencies
make generate # regenerate Go protobuf code from proto definitions (requires buf)
make format
make test # sequential
make lint-check- Bump version in go.mod
- Create a git tag
vX.Y.Z - Push tag to trigger CI/CD release
- StoreKey:
[]float32for DB,StoreInputfor AI - StoreValue: map of metadata fields
- Predicates: filter conditions for stored values
- Pipeline: batch RPC builder
| Version | Description |
|---|---|
| 0.1.0 | Initial Go SDK release |
| 0.2.0 | HNSW + AI Model Support |