Get Started
Vald is a highly scalable distributed fast approximate nearest neighbor dense vector search engine.
Vald is designed and implemented based on Cloud-Native architecture.
This article will show you how to deploy and run the Vald components on your kubernetes cluster. Fashion-mnist is used as an example of a dataset.
Requirements
- kubernetes: v1.19 ~
- go: v1.15 ~
- helm: v3 ~
- libhdf5 (only required for this tutorial.)
Helm and hdf5 is required for this tutorial. If helm or hdf5 is not installed, please install helm and hdf5.
[Optional] Install helm
curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash
[Optional] Install hdf5
# yum
yum install -y hdf5-devel
# apt
apt-get install libhdf5-serial-dev
# homebrew
brew install hdf5
Deploy and Run Vald on kubernetes
Deploy
This chapter will show you how to deploy using Helm and run Vald on your kubernetes cluster.
This chapter uses Scylla DB as a backend data store for indexing and data backup.
If you want to learn about Scylla, please refer to the official website.
Clone the vdaas/vald repository
git clone https://github.com/vdaas/vald.git cd vald
Confirm which cluster to deploy
kubectl cluster-info
In the sense of trying to “Get-Started”, k3d or kind are easy kubernetes tools to use.
Prepare Scylla DB and kubernetes metrics-server
Deploy Scylla as a backup database.
make k8s/external/scylla/deploy
In this make command, we are deploying a lightweight Cassandra-compatible scylladb using Operator.
If you're interested in this make command, take a look here for more detail of make command
- Deploy cert-manager for ScyllaDB
kubectl apply -f https://github.com/jetstack/cert-manager/releases/latest/download/cert-manager.yaml kubectl wait -n cert-manager --for=condition=ready pod -l app=cert-manager --timeout=60s kubectl wait -n cert-manager --for=condition=ready pod -l app=cainjector --timeout=60s kubectl wait -n cert-manager --for=condition=ready pod -l app=webhook --timeout=60s
- Deploy ScyllaDB Operator
kubectl apply -f https://raw.githubusercontent.com/scylladb/scylla-operator/master/examples/common/operator.yaml kubectl wait -n scylla-operator-system --for=condition=ready pod -l statefulset.kubernetes.io/pod-name=scylla-operator-controller-manager-0 --timeout=600s
- Deploy ScyllaDB
kubectl apply -f k8s/external/scylla/scyllacluster.yaml kubectl wait -n scylla --for=condition=ready pod -l statefulset.kubernetes.io/pod-name=vald-scylla-cluster-dc0-rack0-0 --timeout=600s kubectl -n scylla get pods
- Configure ScyllaDB
kubectl apply -f example/manifest/scylla kubectl wait --for=condition=complete job/scylla-init --timeout=60s
For documentation on scylladb operator, please refer to here
Apply kubernetes metrics-server
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml kubectl wait -n kube-system --for=condition=ready pod -l k8s-app=metrics-server --timeout=600s
Deploy Vald using helm
helm repo add vald https://vald.vdaas.org/charts helm install vald vald/vald --values example/helm/values-scylla.yaml
Verify
kubectl get pods
Example output
If the deployment is successful, all Vald components should be running.NAME READY STATUS RESTARTS AGE scylla-init-vhdp5 0/1 Completed 0 7m12s vald-agent-ngt-0 1/1 Running 0 7m12s vald-agent-ngt-1 1/1 Running 0 7m12s vald-agent-ngt-2 1/1 Running 0 7m12s vald-agent-ngt-3 1/1 Running 0 7m12s vald-agent-ngt-4 1/1 Running 0 7m12s vald-agent-ngt-5 1/1 Running 0 7m12s vald-backup-gateway-68c8b4ffd4-df8zp 1/1 Running 0 6m56s vald-backup-gateway-68c8b4ffd4-dmwrd 1/1 Running 0 6m56s vald-backup-gateway-68c8b4ffd4-nm8f7 1/1 Running 0 7m12s vald-discoverer-7f9f697dbb-q44qh 1/1 Running 0 7m11s vald-lb-gateway-6b7b9f6948-4z5md 1/1 Running 0 7m12s vald-lb-gateway-6b7b9f6948-68g94 1/1 Running 0 6m56s vald-lb-gateway-6b7b9f6948-cvspq 1/1 Running 0 6m56s vald-manager-backup-5fb5f8dc7-h22sv 1/1 Running 0 7m12s vald-manager-backup-5fb5f8dc7-ncrw4 1/1 Running 0 6m56s vald-manager-backup-5fb5f8dc7-nzbkh 1/1 Running 0 6m56s vald-manager-compressor-78bf64459f-27ckg 1/1 Running 0 6m56s vald-manager-compressor-78bf64459f-9kl9b 1/1 Running 0 7m12s vald-manager-compressor-78bf64459f-dkx24 1/1 Running 0 6m56s vald-manager-index-74c7b5ddd6-jrnlw 1/1 Running 0 7m12s vald-meta-747f757bbb-9v5xz 1/1 Running 0 7m12s vald-meta-747f757bbb-mpwqp 1/1 Running 0 6m56s vald-meta-gateway-8c5f55dd-8fsch 1/1 Running 0 6m56s vald-meta-gateway-8c5f55dd-sdd5q 1/1 Running 0 7m12s vald-meta-gateway-8c5f55dd-vfkn6 1/1 Running 0 6m56s
Run using example code
This chapter shows how to perform a search action in Vald with fashion-mnist dataset.
Port Forward
kubectl port-forward deployment/vald-meta-gateway 8081:8081
Download dataset
In this tutorial. we use fashion-mnist as a dataset for indexing and search query.
# move to working directory cd example/client # download fashion-mnist testing dataset wget http://ann-benchmarks.com/fashion-mnist-784-euclidean.hdf5
Running example
Vald provides multiple language client libraries such as Go, Java, Node.js, Python, and so on.
In this example, the fashion-mnist dataset will insert into the Vald cluster and perform a search using vald-client-go.We use
example/client/main.go
to run the example. This will execute 4 steps.init
Import packages
example code
package main import ( "context" "encoding/json" "flag" "time" "github.com/kpango/fuid" "github.com/kpango/glg" "github.com/vdaas/vald-client-go/v1/payload" "github.com/vdaas/vald-client-go/v1/vald" "gonum.org/v1/hdf5" "google.golang.org/grpc" )
Set variables
The constant number of training datasets and test datasets.
example code
const ( insertCount = 400 testCount = 20 )
The variables for configuration.
example code
const ( datasetPath string grpcServerAddr string indexingWaitSeconds uint )
Recognition parameters.
example code
func init() { flag.StringVar(&datasetPath, "path", "fashion-mnist-784-euclidean.hdf5", "set dataset path") flag.StringVar(&grpcServerAddr, "addr", "127.0.0.1:8081", "set gRPC server address") flag.UintVar(&indexingWaitSeconds, "wait", 60, "set indexing wait seconds") flag.Parse() }
load
Loading from fashion-mnist dataset and set id for each vector that is loaded. This step will return the training dataset, test dataset, and ids list of ids when loading is completed with success.
example code
ids, train, test, err := load(datasetPath) if err != nil { glg.Fatal(err) }
Create the gRPC connection and Vald client with gRPC connection.
example code
ctx := context.Background() conn, err := grpc.DialContext(ctx, grpcServerAddr, grpc.WithInsecure()) if err != nil { glg.Fatal(err) } client := vald.NewValdClient(conn)
Insert and Index
Insert and Indexing 400 training datasets to the Vald agent.
example code
for i := range ids [:insertCount] { _, err := client.Insert(ctx, &payload.Insert_Request{ Vector: &payload.Object_Vector{ Id: ids[i], Vector: train[i], }, Config: &payload.Insert_Config{ SkipStrictExistCheck: true, }, }) if err != nil { glg.Fatal(err) } if i%10 == 0 { glg.Infof("Inserted %d", i) } }
Wait until indexing finish.
example code
wt := time.Duration(indexingWaitSeconds) * time.Second glg.Infof("Wait %s for indexing to finish", wt) time.Sleep(wt)
Search
Search 10 neighbor vectors for each 20 test datasets and return list of neighbor vector.
When getting approximate vectors, the Vald client sends search config and vector to the server via gRPC.
example code
glg.Infof("Start search %d times", testCount) for i, vec := range test[:testCount] { res, err := client.Search(ctx, &payload.Search_Request){ Vector: vec, Config: &payload.Search_Config{ Num: 10, Radius: -1, Epsilon: 0.01, } } if err != nil { glg.Fatal(err) } b, _ := json.MarshalIndent(res.GetResults(), "", " ") glg.Infof("%d - Results : %s\n\n", i+1, string(b)) time.Sleep(1 * time.Second) }
Remove
Remove 400 indexed training datasets from the Vald agent.
example code
for i := range ids [:insertCount] { _, err := client.Remove(ctx, &payload.Remove_Request{ Id: &payload.Object_ID{ Id: ids[i], }, }) if err != nil { glg.Fatal(err) } if i%10 == 0 { glg.Infof("Removed %d", i) } }
# run example go run main.go
Cleanup
Remove the Vald pods by executing:
helm uninstall vald
Deploy and Run standalone Vald Agent on kubernetes
Deploy
This chapter will show you how to deploy a standalone Vald Agent using Helm and run it on your kubernetes cluster.
This chapter uses NGT as Vald Agent to perform vector insertion operation, indexing and searching operations.
Clone the vdaas/vald repository
git clone https://github.com/vdaas/vald.git cd vald
Confirm which cluster to deploy
kubectl cluster-info
In the sense of trying to “Get-Started”, k3d or kind are easy kubernetes tools to use.
Deploy Vald Agent using helm
There is the values.yaml to deploy standalone Vald Agent. Each component can be disabled by setting the value
false
to the[component].enabled
field. This is useful for deploying standalone Vald Agent NGT pods.helm repo add vald https://vald.vdaas.org/charts helm install vald-agent-ngt vald/vald --values example/helm/values-standalone-agent-ngt.yaml
Verify
kubectl get pods
Example output
If the deployment is successful, Vald Agent component should be running.NAME READY STATUS RESTARTS AGE vald-agent-ngt-0 1/1 Running 0 20m vald-agent-ngt-1 1/1 Running 0 20m vald-agent-ngt-2 1/1 Running 0 20m vald-agent-ngt-3 1/1 Running 0 20m
Run using example code
Port Forward
kubectl port-forward service/vald-agent-ngt 8081:8081
Download dataset
In this tutorial. we use fashion-mnist as a dataset for indexing and search query.
# move to working directory cd example/client/agent # download fashion-mnist testing dataset wget http://ann-benchmarks.com/fashion-mnist-784-euclidean.hdf5
Running example
Vald provides multiple languages client library such as Go, Java, Node.js, Python and so on.
In this example, the fashion-mnist dataset will insert into the Vald and search using vald-client-go.We use
example/client/agent/main.go
to run the example. This will execute 4 steps.init
Import packages
example code
package main import ( "context" "encoding/json" "flag" "time" "github.com/kpango/fuid" "github.com/kpango/glg" agent "github.com/vdaas/vald-client-go/v1/agent/core" "github.com/vdaas/vald-client-go/v1/vald" "github.com/vdaas/vald-client-go/v1/payload" "gonum.org/v1/hdf5" "google.golang.org/grpc" )
Set variables
The constant number of training datasets and test datasets.
example code
const ( insertCount = 400 testCount = 20 )
The variables for configuration.
example code
const ( datasetPath string grpcServerAddr string indexingWaitSeconds uint )
Recognition parameters.
example code
func init() { flag.StringVar(&datasetPath, "path", "fashion-mnist-784-euclidean.hdf5", "set dataset path") flag.StringVar(&grpcServerAddr, "addr", "127.0.0.1:8081", "set gRPC server address") flag.UintVar(&indexingWaitSeconds, "wait", 60, "set indexing wait seconds") flag.Parse() }
load
Loading from fashion-mnist dataset and set id for each vector that is loaded. This step will return the training dataset, test dataset, and ids list of ids when loading is completed with success.
example code
ids, train, test, err := load(datasetPath) if err != nil { glg.Fatal(err) }
Create the gRPC connection and Vald client with gRPC connection.
example code
ctx := context.Background() conn, err := grpc.DialContext(ctx, grpcServerAddr, grpc.WithInsecure()) if err != nil { glg.Fatal(err) } client := agent.NewAgentClient(conn)
Insert and Index
Insert and Indexing 400 training datasets to the Vald agent.
example code
for i := range ids [:insertCount] { if i%10 == 0 { glg.Infof("Inserted %d", i) } _, err := client.Insert(ctx, &payload.Insert_Request{ Vector: &payload.Object_Vector{ Id: ids[i], Vector: train[i], }, Config: &payload.Insert_Config{ SkipStrictExistCheck: true, }, }) if err != nil { glg.Fatal(err) } }
Wait until indexing finish.
example code
wt := time.Duration(indexingWaitSeconds) * time.Second glg.Infof("Wait %s for indexing to finish", wt) time.Sleep(wt)
[Optional] Indexing manually instead of waiting for auto indexing You can set Agent NGT configuration
auto_index_duration_limit
andauto_index_check_duration
for auto indexing. In this example, you can create index manually usingCreateAndSaveIndex()
mthod in the client library.example code _, err = client.CreateAndSaveIndex(ctx, &payload.Control_CreateIndexRequest{ PoolSize: uint32(insertCount), }) if err != nil { glg.Fatal(err) }
Search
Search 10 neighbor vectors for each 20 test datasets and return list of neighbor vector.
When getting approximate vectors, the Vald client sends search config and vector to the server via gRPC.
example code
glg.Infof("Start search %d times", testCount) for i, vec := range test[:testCount] { res, err := client.Search(ctx, &payload.Search_Request){ Vector: vec, Config: &payload.Search_Config{ Num: 10, Radius: -1, Epsilon: 0.01, } } if err != nil { glg.Fatal(err) } b, _ := json.MarshalIndent(res.GetResults(), "", " ") glg.Infof("%d - Results : %s\n\n", i+1, string(b)) time.Sleep(1 * time.Second) }
Remove
Remove indexed 400 training datasets from the Vald agent.
example code
for i := range ids [:insertCount] { _, err := client.Remove(ctx, &payload.Remove_Request{ Id: &payload.Object_ID{ Id: ids[i], }, }) if err != nil { glg.Fatal(err) } if i%10 == 0 { glg.Infof("Removed %d", i) } }
Remove from the index manually instead of waiting for auto indexing. The removed vectors are still exist in the NGT graph index before the SaveIndex (or CreateAndSaveIndex) API is called. If you run the below code, the indexes will be removed completely from the Vald Agent NGT graph and the Backup file.
example code _, err = client.SaveIndex(ctx, &payload.Empty{}) if err != nil { glg.Fatal(err) }
# run example go run main.go
Cleanup
Remove the Vald Agent pods by executing:
helm uninstall vald-agent-ngt