Skip to content

Commit 40a043e

Browse files
committed
dimension verification
1 parent 3229cf4 commit 40a043e

10 files changed

Lines changed: 41 additions & 37 deletions

File tree

client/index.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,7 @@ type VectorIndexDescription struct {
121121
Algorithm VectorAlgorithm
122122
// Metric is the distance metric used to compare vectors.
123123
Metric DistanceMetric
124-
// Dimensions is the length of the vectors being indexed. It must be set, except on an @embedding
125-
// field, where the embedding model fixes the length and Dimensions may be left 0.
124+
// Dimensions is the length of the vectors being indexed. It must be greater than zero.
126125
Dimensions uint32
127126
// HNSW holds HNSW-specific parameters. Non-nil when Algorithm == VectorAlgorithmHNSW.
128127
HNSW *HNSWParams

internal/db/collection_index.go

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -519,10 +519,9 @@ func processNewIndexRequest(
519519
}
520520

521521
// validateVectorIndexDescription checks and fills in the vector-specific parts of an index request.
522-
// The field must hold a float32 array, and dimensions must be set unless the field is an @embedding,
523-
// whose model fixes the vector length. It also defaults the algorithm, metric, and any missing
524-
// params (mutating desc.Vector), so a request made through the index API works the same as one from
525-
// the @index directive's vector configuration.
522+
// The field must hold a float32 array, and dimensions must be greater than zero. It also defaults
523+
// the algorithm, metric, and any missing params (mutating desc.Vector), so a request made through
524+
// the index API works the same as one from the @index directive's vector configuration.
526525
//
527526
// The field is guaranteed to exist here because validateIndexDescription and
528527
// checkExistingFieldsAndAdjustRelFieldNames run before this and already check that.
@@ -543,10 +542,13 @@ func validateVectorIndexDescription(def client.CollectionVersion, desc client.Ne
543542
if !client.IsVectorEmbeddingCompatible(field.Kind) {
544543
return NewErrUnsupportedVectorIndexFieldType(field.Kind)
545544
}
545+
if desc.Vector.Dimensions == 0 {
546+
return NewErrVectorIndexMissingDimensions(fieldName)
547+
}
546548

547-
// The config object present is what picks the algorithm, so the caller never sets one directly.
548-
// Fill in the algorithm, metric, and any missing params with defaults. A nil config means an empty
549-
// one, so a caller can leave it out and still get a working HNSW index.
549+
// The algorithm config object present is what picks the algorithm, so the caller never sets one
550+
// directly. Fill in the algorithm, metric, and any missing params with defaults. A nil HNSW config
551+
// means an empty one, so a caller can leave it out and still get a working HNSW index.
550552
if desc.Vector.HNSW == nil {
551553
desc.Vector.HNSW = &client.HNSWParams{}
552554
}
@@ -572,19 +574,7 @@ func validateVectorIndexDescription(def client.CollectionVersion, desc client.Ne
572574
return err
573575
}
574576

575-
if desc.Vector.Dimensions > 0 {
576-
return nil
577-
}
578-
579-
// No dimensions were given. That is only allowed when the field is an @embedding, since the
580-
// model then fixes the dimensions. The value itself is filled in later.
581-
for _, embedding := range def.VectorEmbeddings {
582-
if embedding.FieldName == fieldName {
583-
return nil
584-
}
585-
}
586-
587-
return NewErrVectorIndexMissingDimensions(fieldName)
577+
return nil
588578
}
589579

590580
// validateNoConflictingVectorIndexMetric rejects creating a vector index on a field that another

internal/db/errors.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ const (
6262
errInvalidFieldValue string = "invalid field value"
6363
errUnsupportedIndexFieldType string = "unsupported index field type"
6464
errUnsupportedVectorIndexFieldType string = "unsupported field type for vector index"
65-
errVectorIndexMissingDimensions string = "vector index requires dimensions unless field is an embedding"
65+
errVectorIndexMissingDimensions string = "vector index dimensions must be greater than zero"
6666
errCannotIndexAccumulatedCRDTField string = "indexing accumulated CRDT fields is not yet supported"
6767
errIndexDescriptionHasNoFields string = "index description has no fields"
6868
errCreateFile string = "failed to create file"
@@ -606,8 +606,8 @@ func NewErrUnsupportedVectorIndexFieldType(kind client.FieldKind) error {
606606
)
607607
}
608608

609-
// NewErrVectorIndexMissingDimensions returns a new error indicating that a vector index request is
610-
// missing its dimensions, and dimensions could not be inferred from a generated embedding.
609+
// NewErrVectorIndexMissingDimensions returns a new error indicating that a vector index request has
610+
// no dimensions.
611611
func NewErrVectorIndexMissingDimensions(fieldName string) error {
612612
return errors.New(
613613
errVectorIndexMissingDimensions,

internal/db/vector_index_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,21 @@ func vectorIndexSearch(
8282
return docIDs
8383
}
8484

85+
func TestValidateVectorIndexDescription_EmbeddingRequiresDimensions(t *testing.T) {
86+
const fieldName = "embedding"
87+
def := client.CollectionVersion{
88+
Fields: []client.CollectionFieldDescription{{Name: fieldName, Kind: client.FieldKind_FLOAT32_ARRAY}},
89+
VectorEmbeddings: []client.VectorEmbeddingDescription{{FieldName: fieldName}},
90+
}
91+
desc := client.NewIndexRequest{
92+
Fields: []client.IndexedFieldDescription{{Name: fieldName}},
93+
Vector: &client.VectorIndexDescription{},
94+
}
95+
96+
err := validateVectorIndexDescription(def, desc)
97+
require.ErrorContains(t, err, "vector index dimensions must be greater than zero")
98+
}
99+
85100
func TestCollectionVectorIndex_Save_InsertsIntoGraphAndIsSearchable(t *testing.T) {
86101
ctx, db, col := newVectorIndexTestDB(t, 3)
87102

internal/request/graphql/schema/collection.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -751,8 +751,13 @@ func vectorIndexFromAST(
751751
return client.NewIndexRequest{}, ErrIndexWithInvalidArg
752752
}
753753

754-
if config == nil {
755-
return client.NewIndexRequest{}, ErrIndexWithInvalidArg
754+
obj := &ast.ObjectValue{}
755+
if config != nil {
756+
var ok bool
757+
obj, ok = config.(*ast.ObjectValue)
758+
if !ok {
759+
return client.NewIndexRequest{}, ErrIndexWithInvalidArg
760+
}
756761
}
757762

758763
var dimensions uint32
@@ -763,11 +768,6 @@ func vectorIndexFromAST(
763768
EfConstruction: client.DefaultHNSWEfConstruction,
764769
EfSearch: client.DefaultHNSWEfSearch,
765770
}
766-
767-
obj, ok := config.(*ast.ObjectValue)
768-
if !ok {
769-
return client.NewIndexRequest{}, ErrIndexWithInvalidArg
770-
}
771771
for _, field := range obj.Fields {
772772
switch field.Name.Value {
773773
case types.VectorIndexPropDimensions:

internal/request/graphql/schema/testfixtures/schema.relatedmany.gen.graphql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3205,7 +3205,7 @@ enum VectorIndexAlgorithm {
32053205
input VectorIndexConfig {
32063206
"Selects the vector index algorithm using its default configuration."
32073207
alg: VectorIndexAlgorithm
3208-
"Vector dimensions; required unless inferable from an @embedding."
3208+
"Vector dimensions; must be greater than zero."
32093209
dimensions: Int
32103210
"Configures the HNSW algorithm."
32113211
hnsw: HNSWIndexConfig

internal/request/graphql/schema/testfixtures/schema.relatedone.gen.graphql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3148,7 +3148,7 @@ enum VectorIndexAlgorithm {
31483148
input VectorIndexConfig {
31493149
"Selects the vector index algorithm using its default configuration."
31503150
alg: VectorIndexAlgorithm
3151-
"Vector dimensions; required unless inferable from an @embedding."
3151+
"Vector dimensions; must be greater than zero."
31523152
dimensions: Int
31533153
"Configures the HNSW algorithm."
31543154
hnsw: HNSWIndexConfig

internal/request/graphql/schema/testfixtures/schema.simple.gen.graphql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2583,7 +2583,7 @@ enum VectorIndexAlgorithm {
25832583
input VectorIndexConfig {
25842584
"Selects the vector index algorithm using its default configuration."
25852585
alg: VectorIndexAlgorithm
2586-
"Vector dimensions; required unless inferable from an @embedding."
2586+
"Vector dimensions; must be greater than zero."
25872587
dimensions: Int
25882588
"Configures the HNSW algorithm."
25892589
hnsw: HNSWIndexConfig

internal/request/graphql/schema/types/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,7 @@ func VectorIndexInputObject(
522522
Description: "Configures an approximate-nearest-neighbour index over a vector field.",
523523
Fields: gql.InputObjectConfigFieldMap{
524524
VectorIndexPropDimensions: &gql.InputObjectFieldConfig{
525-
Description: "Vector dimensions; required unless inferable from an @embedding.",
525+
Description: "Vector dimensions; must be greater than zero.",
526526
Type: gql.Int,
527527
},
528528
VectorIndexPropAlgorithm: &gql.InputObjectFieldConfig{

tests/integration/collection_version/vector_index_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ func TestCollectionVersion_VectorIndexOnFloat32ArrayWithoutDimensionsOrEmbedding
6767
embedding: [Float32!] @index(kind: vector)
6868
}
6969
`,
70-
ExpectedError: "vector index requires dimensions unless field is an embedding",
70+
ExpectedError: "vector index dimensions must be greater than zero",
7171
},
7272
},
7373
}

0 commit comments

Comments
 (0)