From 3c0580201d35a699fbbd03eb43c230b88ed052a1 Mon Sep 17 00:00:00 2001 From: Rodrigo Lopez Date: Thu, 18 Jun 2026 10:24:34 +0200 Subject: [PATCH] Make namedVector compose with multivector in ann-benchmark Passing --namedVector together with -m (multivector/Colbert) failed with "inconsistent vector lengths" because the namedVector branches in both the ingestion and query paths unconditionally overwrote the multivector payload with a single flat vector. The schema branch likewise omitted the multivector/muvera config. - writeChunk: emit MULTI_FP32 under cfg.NamedVector when both flags set - createSchema: inject multivector/muvera block into named vector config - nearVectorQueryGrpc: target the named vector with the multi payload - enableCompression: check NamedVector before MultiVectorDimensions so config updates land on the right VectorConfig key --- benchmarker/cmd/ann_benchmark.go | 56 ++++++++++++---------- benchmarker/cmd/random_vectors.go | 78 +++++++++++++++---------------- 2 files changed, 70 insertions(+), 64 deletions(-) diff --git a/benchmarker/cmd/ann_benchmark.go b/benchmarker/cmd/ann_benchmark.go index f19476f..0ed6c41 100644 --- a/benchmarker/cmd/ann_benchmark.go +++ b/benchmarker/cmd/ann_benchmark.go @@ -121,22 +121,23 @@ func writeChunk(chunk *Batch, client *weaviategrpc.WeaviateClient, cfg *Config) end := start + cfg.MultiVectorDimensions multiVec[i] = vector[start:end] } + name := "multivector" + if cfg.NamedVector != "" { + name = cfg.NamedVector + } objects[i].Vectors = []*weaviategrpc.Vectors{{ - Name: "multivector", + Name: name, VectorBytes: byteops.Fp32SliceOfSlicesToBytes(multiVec), Type: weaviategrpc.Vectors_VECTOR_TYPE_MULTI_FP32, }} + } else if cfg.NamedVector != "" { + objects[i].Vectors = []*weaviategrpc.Vectors{{ + Name: cfg.NamedVector, + VectorBytes: encodeVector(vector), + }} } else { objects[i].VectorBytes = encodeVector(vector) } - if cfg.NamedVector != "" { - vectors := make([]*weaviategrpc.Vectors, 1) - vectors[0] = &weaviategrpc.Vectors{ - VectorBytes: encodeVector(vector), - Name: cfg.NamedVector, - } - objects[i].Vectors = vectors - } if cfg.Filter { nonRefProperties, err := structpb.NewStruct(map[string]interface{}{ "category": strconv.Itoa(chunk.Filters[i]), @@ -369,6 +370,17 @@ func createSchema(cfg *Config, client *weaviate.Client) { vectorIndexConfig["filterStrategy"] = cfg.FilterStrategy if cfg.NamedVector != "" { + if cfg.MultiVectorDimensions > 0 { + vectorIndexConfig["multivector"] = map[string]interface{}{ + "enabled": true, + "muvera": map[string]interface{}{ + "enabled": cfg.MuveraEnabled, + "ksim": cfg.MuveraKSim, + "dprojections": cfg.MuveraDProjections, + "repetition": cfg.MuveraRepetition, + }, + } + } vectorConfig := make(map[string]models.VectorConfig) vectorConfig[cfg.NamedVector] = models.VectorConfig{ Vectorizer: map[string]interface{}{"none": nil}, @@ -611,15 +623,13 @@ func enableCompression(cfg *Config, client *weaviate.Client, dimensions uint, co var segments uint var vectorIndexConfig map[string]interface{} - if cfg.MultiVectorDimensions > 0 { + if cfg.NamedVector != "" { + vectorIndexConfig = classConfig.VectorConfig[cfg.NamedVector].VectorIndexConfig.(map[string]interface{}) + classConfig.Vectorizer = "" + } else if cfg.MultiVectorDimensions > 0 { vectorIndexConfig = classConfig.VectorConfig["multivector"].VectorIndexConfig.(map[string]interface{}) } else { - if cfg.NamedVector == "" { - vectorIndexConfig = classConfig.VectorIndexConfig.(map[string]interface{}) - } else { - vectorIndexConfig = classConfig.VectorConfig[cfg.NamedVector].VectorIndexConfig.(map[string]interface{}) - classConfig.Vectorizer = "" - } + vectorIndexConfig = classConfig.VectorIndexConfig.(map[string]interface{}) } switch compressionType { @@ -662,18 +672,16 @@ func enableCompression(cfg *Config, client *weaviate.Client, dimensions uint, co vectorIndexConfig["rq"] = rqConfig } - if cfg.MultiVectorDimensions > 0 { + if cfg.NamedVector != "" { + vectorConfig := classConfig.VectorConfig[cfg.NamedVector] + vectorConfig.VectorIndexConfig = vectorIndexConfig + classConfig.VectorConfig[cfg.NamedVector] = vectorConfig + } else if cfg.MultiVectorDimensions > 0 { vectorConfig := classConfig.VectorConfig["multivector"] vectorConfig.VectorIndexConfig = vectorIndexConfig classConfig.VectorConfig["multivector"] = vectorConfig } else { - if cfg.NamedVector == "" { - classConfig.VectorIndexConfig = vectorIndexConfig - } else { - vectorConfig := classConfig.VectorConfig[cfg.NamedVector] - vectorConfig.VectorIndexConfig = vectorIndexConfig - classConfig.VectorConfig[cfg.NamedVector] = vectorConfig - } + classConfig.VectorIndexConfig = vectorIndexConfig } err = client.Schema().ClassUpdater().WithClass(classConfig).Do(context.Background()) diff --git a/benchmarker/cmd/random_vectors.go b/benchmarker/cmd/random_vectors.go index 980f6fc..47ec7e0 100644 --- a/benchmarker/cmd/random_vectors.go +++ b/benchmarker/cmd/random_vectors.go @@ -137,9 +137,14 @@ func encodeVector(fs []float32) []byte { func nearVectorQueryGrpc(cfg *Config, vec []float32, tenant string, filter int) []byte { - var searchRequest *weaviategrpc.SearchRequest - if cfg.MultiVectorDimensions > 0 { + metadata := &weaviategrpc.MetadataRequest{ + Certainty: false, + Distance: false, + Uuid: true, + } + var nearVector *weaviategrpc.NearVector + if cfg.MultiVectorDimensions > 0 { rows := len(vec) / cfg.MultiVectorDimensions doc := make([][]float32, rows) for i := 0; i < rows; i++ { @@ -147,46 +152,24 @@ func nearVectorQueryGrpc(cfg *Config, vec []float32, tenant string, filter int) end := start + cfg.MultiVectorDimensions doc[i] = vec[start:end] } - multiVec := []*weaviategrpc.Vectors{{ - Name: "multivector", - VectorBytes: byteops.Fp32SliceOfSlicesToBytes(doc), - Type: weaviategrpc.Vectors_VECTOR_TYPE_MULTI_FP32, - }} - - searchRequest = &weaviategrpc.SearchRequest{ - Collection: cfg.ClassName, - Limit: uint32(cfg.Limit), - NearVector: &weaviategrpc.NearVector{ - Vectors: multiVec, - }, - Metadata: &weaviategrpc.MetadataRequest{ - Certainty: false, - Distance: false, - Uuid: true, - }, + name := "multivector" + if cfg.NamedVector != "" { + name = cfg.NamedVector } - - } else { - searchRequest = &weaviategrpc.SearchRequest{ - Collection: cfg.ClassName, - Limit: uint32(cfg.Limit), - NearVector: &weaviategrpc.NearVector{ - VectorBytes: encodeVector(vec), - }, - Metadata: &weaviategrpc.MetadataRequest{ - Certainty: false, - Distance: false, - Uuid: true, - }, + nearVector = &weaviategrpc.NearVector{ + Vectors: []*weaviategrpc.Vectors{{ + Name: name, + VectorBytes: byteops.Fp32SliceOfSlicesToBytes(doc), + Type: weaviategrpc.Vectors_VECTOR_TYPE_MULTI_FP32, + }}, } - } - - if tenant != "" { - searchRequest.Tenant = tenant - } - - if cfg.NamedVector != "" { - searchRequest.NearVector = &weaviategrpc.NearVector{ + if cfg.NamedVector != "" { + nearVector.Targets = &weaviategrpc.Targets{ + TargetVectors: []string{cfg.NamedVector}, + } + } + } else if cfg.NamedVector != "" { + nearVector = &weaviategrpc.NearVector{ Targets: &weaviategrpc.Targets{ TargetVectors: []string{cfg.NamedVector}, }, @@ -194,6 +177,21 @@ func nearVectorQueryGrpc(cfg *Config, vec []float32, tenant string, filter int) cfg.NamedVector: encodeVector(vec), }, } + } else { + nearVector = &weaviategrpc.NearVector{ + VectorBytes: encodeVector(vec), + } + } + + searchRequest := &weaviategrpc.SearchRequest{ + Collection: cfg.ClassName, + Limit: uint32(cfg.Limit), + NearVector: nearVector, + Metadata: metadata, + } + + if tenant != "" { + searchRequest.Tenant = tenant } if filter >= 0 {