From d5baa81ecc10dcd559f7299b10c213970000df51 Mon Sep 17 00:00:00 2001 From: Rahul Rampure Date: Thu, 6 Nov 2025 12:55:49 +0530 Subject: [PATCH 1/6] Support GPU-Accelerated Vector Search --- document/field_vector.go | 13 ++++++++++--- document/field_vector_base64.go | 4 ++-- mapping/field.go | 3 +++ mapping/mapping_vectors.go | 4 ++-- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/document/field_vector.go b/document/field_vector.go index 9c55cf1a2..78038ab6a 100644 --- a/document/field_vector.go +++ b/document/field_vector.go @@ -42,6 +42,7 @@ type VectorField struct { value []float32 numPlainTextBytes uint64 vectorIndexOptimizedFor string // Optimization applied to this index. + gpu bool // Whether to use GPU for indexing/searching } func (n *VectorField) Size() int { @@ -98,17 +99,18 @@ func (n *VectorField) GoString() string { // For the sake of not polluting the API, we are keeping arrayPositions as a // parameter, but it is not used. func NewVectorField(name string, arrayPositions []uint64, - vector []float32, dims int, similarity, vectorIndexOptimizedFor string) *VectorField { + vector []float32, dims int, similarity, vectorIndexOptimizedFor string, + gpu bool) *VectorField { return NewVectorFieldWithIndexingOptions(name, arrayPositions, vector, dims, similarity, vectorIndexOptimizedFor, - DefaultVectorIndexingOptions) + gpu, DefaultVectorIndexingOptions) } // For the sake of not polluting the API, we are keeping arrayPositions as a // parameter, but it is not used. func NewVectorFieldWithIndexingOptions(name string, arrayPositions []uint64, vector []float32, dims int, similarity, vectorIndexOptimizedFor string, - options index.FieldIndexingOptions) *VectorField { + gpu bool, options index.FieldIndexingOptions) *VectorField { return &VectorField{ name: name, @@ -118,6 +120,7 @@ func NewVectorFieldWithIndexingOptions(name string, arrayPositions []uint64, value: vector, numPlainTextBytes: numBytesFloat32s(vector), vectorIndexOptimizedFor: vectorIndexOptimizedFor, + gpu: gpu, } } @@ -144,3 +147,7 @@ func (n *VectorField) Similarity() string { func (n *VectorField) IndexOptimizedFor() string { return n.vectorIndexOptimizedFor } + +func (n *VectorField) GPU() bool { + return n.gpu +} diff --git a/document/field_vector_base64.go b/document/field_vector_base64.go index 31d6cbffd..80202748a 100644 --- a/document/field_vector_base64.go +++ b/document/field_vector_base64.go @@ -94,7 +94,7 @@ func (n *VectorBase64Field) GoString() string { // For the sake of not polluting the API, we are keeping arrayPositions as a // parameter, but it is not used. func NewVectorBase64Field(name string, arrayPositions []uint64, vectorBase64 string, - dims int, similarity, vectorIndexOptimizedFor string) (*VectorBase64Field, error) { + dims int, similarity, vectorIndexOptimizedFor string, gpu bool) (*VectorBase64Field, error) { decodedVector, err := DecodeVector(vectorBase64) if err != nil { @@ -104,7 +104,7 @@ func NewVectorBase64Field(name string, arrayPositions []uint64, vectorBase64 str return &VectorBase64Field{ vectorField: NewVectorFieldWithIndexingOptions(name, arrayPositions, decodedVector, dims, similarity, - vectorIndexOptimizedFor, DefaultVectorIndexingOptions), + vectorIndexOptimizedFor, gpu, DefaultVectorIndexingOptions), base64Encoding: vectorBase64, }, nil diff --git a/mapping/field.go b/mapping/field.go index 0b6074910..6e1a8ee4c 100644 --- a/mapping/field.go +++ b/mapping/field.go @@ -83,6 +83,9 @@ type FieldMapping struct { VectorIndexOptimizedFor string `json:"vector_index_optimized_for,omitempty"` SynonymSource string `json:"synonym_source,omitempty"` + + // Flag that indicates whether to use GPU for field indexing and searching + GPU bool `json:"gpu,omitempty"` } // NewTextFieldMapping returns a default field mapping for text diff --git a/mapping/mapping_vectors.go b/mapping/mapping_vectors.go index 20cbac6a8..9791bfcbe 100644 --- a/mapping/mapping_vectors.go +++ b/mapping/mapping_vectors.go @@ -149,7 +149,7 @@ func (fm *FieldMapping) processVector(propertyMightBeVector interface{}, fieldName := getFieldName(pathString, path, fm) options := fm.Options() field := document.NewVectorFieldWithIndexingOptions(fieldName, indexes, vector, - fm.Dims, fm.Similarity, fm.VectorIndexOptimizedFor, options) + fm.Dims, fm.Similarity, fm.VectorIndexOptimizedFor, fm.GPU, options) context.doc.AddField(field) // "_all" composite field is not applicable for vector field @@ -176,7 +176,7 @@ func (fm *FieldMapping) processVectorBase64(propertyMightBeVectorBase64 interfac fieldName := getFieldName(pathString, path, fm) options := fm.Options() field := document.NewVectorFieldWithIndexingOptions(fieldName, indexes, decodedVector, - fm.Dims, fm.Similarity, fm.VectorIndexOptimizedFor, options) + fm.Dims, fm.Similarity, fm.VectorIndexOptimizedFor, fm.GPU, options) context.doc.AddField(field) // "_all" composite field is not applicable for vector_base64 field From 11792f184622757fbfbadb099ee6e278bc0fa8d2 Mon Sep 17 00:00:00 2001 From: Rahul Rampure Date: Fri, 7 Nov 2025 11:51:43 +0530 Subject: [PATCH 2/6] make gpu part on options --- document/field_vector.go | 8 +++----- document/field_vector_base64.go | 4 ++-- mapping/field.go | 10 +++++++++- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/document/field_vector.go b/document/field_vector.go index 78038ab6a..b3b99689a 100644 --- a/document/field_vector.go +++ b/document/field_vector.go @@ -99,18 +99,17 @@ func (n *VectorField) GoString() string { // For the sake of not polluting the API, we are keeping arrayPositions as a // parameter, but it is not used. func NewVectorField(name string, arrayPositions []uint64, - vector []float32, dims int, similarity, vectorIndexOptimizedFor string, - gpu bool) *VectorField { + vector []float32, dims int, similarity, vectorIndexOptimizedFor string) *VectorField { return NewVectorFieldWithIndexingOptions(name, arrayPositions, vector, dims, similarity, vectorIndexOptimizedFor, - gpu, DefaultVectorIndexingOptions) + DefaultVectorIndexingOptions) } // For the sake of not polluting the API, we are keeping arrayPositions as a // parameter, but it is not used. func NewVectorFieldWithIndexingOptions(name string, arrayPositions []uint64, vector []float32, dims int, similarity, vectorIndexOptimizedFor string, - gpu bool, options index.FieldIndexingOptions) *VectorField { + options index.FieldIndexingOptions) *VectorField { return &VectorField{ name: name, @@ -120,7 +119,6 @@ func NewVectorFieldWithIndexingOptions(name string, arrayPositions []uint64, value: vector, numPlainTextBytes: numBytesFloat32s(vector), vectorIndexOptimizedFor: vectorIndexOptimizedFor, - gpu: gpu, } } diff --git a/document/field_vector_base64.go b/document/field_vector_base64.go index 80202748a..31d6cbffd 100644 --- a/document/field_vector_base64.go +++ b/document/field_vector_base64.go @@ -94,7 +94,7 @@ func (n *VectorBase64Field) GoString() string { // For the sake of not polluting the API, we are keeping arrayPositions as a // parameter, but it is not used. func NewVectorBase64Field(name string, arrayPositions []uint64, vectorBase64 string, - dims int, similarity, vectorIndexOptimizedFor string, gpu bool) (*VectorBase64Field, error) { + dims int, similarity, vectorIndexOptimizedFor string) (*VectorBase64Field, error) { decodedVector, err := DecodeVector(vectorBase64) if err != nil { @@ -104,7 +104,7 @@ func NewVectorBase64Field(name string, arrayPositions []uint64, vectorBase64 str return &VectorBase64Field{ vectorField: NewVectorFieldWithIndexingOptions(name, arrayPositions, decodedVector, dims, similarity, - vectorIndexOptimizedFor, gpu, DefaultVectorIndexingOptions), + vectorIndexOptimizedFor, DefaultVectorIndexingOptions), base64Encoding: vectorBase64, }, nil diff --git a/mapping/field.go b/mapping/field.go index 6e1a8ee4c..ffbde6b8a 100644 --- a/mapping/field.go +++ b/mapping/field.go @@ -85,7 +85,7 @@ type FieldMapping struct { SynonymSource string `json:"synonym_source,omitempty"` // Flag that indicates whether to use GPU for field indexing and searching - GPU bool `json:"gpu,omitempty"` + UseGPU bool `json:"gpu,omitempty"` } // NewTextFieldMapping returns a default field mapping for text @@ -229,6 +229,9 @@ func (fm *FieldMapping) Options() index.FieldIndexingOptions { if fm.SkipFreqNorm { rv |= index.SkipFreqNorm } + if fm.UseGPU { + rv |= index.GPU + } return rv } @@ -482,6 +485,11 @@ func (fm *FieldMapping) UnmarshalJSON(data []byte) error { if err != nil { return err } + case "gpu": + err := util.UnmarshalJSON(v, &fm.UseGPU) + if err != nil { + return err + } default: invalidKeys = append(invalidKeys, k) } From 1b8ba1f372e5b77e5d0254350f1bb8c0078759ff Mon Sep 17 00:00:00 2001 From: Rahul Rampure Date: Fri, 7 Nov 2025 12:18:27 +0530 Subject: [PATCH 3/6] fix options --- mapping/mapping_vectors.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mapping/mapping_vectors.go b/mapping/mapping_vectors.go index 9791bfcbe..20cbac6a8 100644 --- a/mapping/mapping_vectors.go +++ b/mapping/mapping_vectors.go @@ -149,7 +149,7 @@ func (fm *FieldMapping) processVector(propertyMightBeVector interface{}, fieldName := getFieldName(pathString, path, fm) options := fm.Options() field := document.NewVectorFieldWithIndexingOptions(fieldName, indexes, vector, - fm.Dims, fm.Similarity, fm.VectorIndexOptimizedFor, fm.GPU, options) + fm.Dims, fm.Similarity, fm.VectorIndexOptimizedFor, options) context.doc.AddField(field) // "_all" composite field is not applicable for vector field @@ -176,7 +176,7 @@ func (fm *FieldMapping) processVectorBase64(propertyMightBeVectorBase64 interfac fieldName := getFieldName(pathString, path, fm) options := fm.Options() field := document.NewVectorFieldWithIndexingOptions(fieldName, indexes, decodedVector, - fm.Dims, fm.Similarity, fm.VectorIndexOptimizedFor, fm.GPU, options) + fm.Dims, fm.Similarity, fm.VectorIndexOptimizedFor, options) context.doc.AddField(field) // "_all" composite field is not applicable for vector_base64 field From 70f3684ae8b024bc88252249b23ba7d380d59718 Mon Sep 17 00:00:00 2001 From: Rahul Rampure Date: Fri, 21 Nov 2025 14:53:33 +0530 Subject: [PATCH 4/6] revert --- document/field_vector.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/document/field_vector.go b/document/field_vector.go index b3b99689a..9c55cf1a2 100644 --- a/document/field_vector.go +++ b/document/field_vector.go @@ -42,7 +42,6 @@ type VectorField struct { value []float32 numPlainTextBytes uint64 vectorIndexOptimizedFor string // Optimization applied to this index. - gpu bool // Whether to use GPU for indexing/searching } func (n *VectorField) Size() int { @@ -145,7 +144,3 @@ func (n *VectorField) Similarity() string { func (n *VectorField) IndexOptimizedFor() string { return n.vectorIndexOptimizedFor } - -func (n *VectorField) GPU() bool { - return n.gpu -} From 9bf07fa4449c021ead064ed24b3bab9e62e4dd3c Mon Sep 17 00:00:00 2001 From: Rahul Rampure Date: Fri, 21 Nov 2025 17:05:09 +0530 Subject: [PATCH 5/6] fix index update --- index_update.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/index_update.go b/index_update.go index 5666d035b..e224a1431 100644 --- a/index_update.go +++ b/index_update.go @@ -507,6 +507,9 @@ func compareFieldMapping(original, updated *mapping.FieldMapping) (*index.Update if original.VectorIndexOptimizedFor != updated.VectorIndexOptimizedFor { return nil, fmt.Errorf("vectorIndexOptimizedFor cannot be updated for vector and vector_base64 fields") } + if original.UseGPU != updated.UseGPU { + return nil, fmt.Errorf("useGPU cannot be updated for vector and vector_base64 fields") + } } if original.IncludeInAll != updated.IncludeInAll { return nil, fmt.Errorf("includeInAll cannot be changed") From bc5d1934db852dd91f97ace5b3d8f6d4f2ad8a9b Mon Sep 17 00:00:00 2001 From: Rahul Rampure Date: Fri, 21 Nov 2025 17:06:39 +0530 Subject: [PATCH 6/6] alias fix --- mapping/mapping_vectors.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mapping/mapping_vectors.go b/mapping/mapping_vectors.go index 20cbac6a8..3ee7b800b 100644 --- a/mapping/mapping_vectors.go +++ b/mapping/mapping_vectors.go @@ -237,6 +237,11 @@ func validateVectorFieldAlias(field *FieldMapping, parentName string, "(different similarity values %s and %s)", fieldAlias.Name, field.Similarity, fieldAlias.Similarity) } + if field.UseGPU != fieldAlias.UseGPU { + return fmt.Errorf("field: '%s', invalid alias "+ + "(different useGPU values %v and %v)", fieldAlias.Name, + field.UseGPU, fieldAlias.UseGPU) + } return nil }