github.com/weaviate/weaviate@v1.24.6/adapters/repos/db/crud_integration_test.go (about)

     1  //                           _       _
     2  // __      _____  __ ___   ___  __ _| |_ ___
     3  // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
     4  //  \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
     5  //   \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
     6  //
     7  //  Copyright © 2016 - 2024 Weaviate B.V. All rights reserved.
     8  //
     9  //  CONTACT: hello@weaviate.io
    10  //
    11  
    12  //go:build integrationTest
    13  
    14  package db
    15  
    16  import (
    17  	"context"
    18  	"fmt"
    19  	"math/rand"
    20  	"testing"
    21  	"time"
    22  
    23  	"github.com/go-openapi/strfmt"
    24  	"github.com/google/uuid"
    25  	"github.com/sirupsen/logrus/hooks/test"
    26  	"github.com/stretchr/testify/assert"
    27  	"github.com/stretchr/testify/require"
    28  	"github.com/weaviate/weaviate/entities/additional"
    29  	"github.com/weaviate/weaviate/entities/dto"
    30  	"github.com/weaviate/weaviate/entities/filters"
    31  	"github.com/weaviate/weaviate/entities/models"
    32  	"github.com/weaviate/weaviate/entities/multi"
    33  	"github.com/weaviate/weaviate/entities/schema"
    34  	"github.com/weaviate/weaviate/entities/schema/crossref"
    35  	"github.com/weaviate/weaviate/entities/search"
    36  	"github.com/weaviate/weaviate/entities/searchparams"
    37  	enthnsw "github.com/weaviate/weaviate/entities/vectorindex/hnsw"
    38  	"github.com/weaviate/weaviate/usecases/objects"
    39  	"github.com/weaviate/weaviate/usecases/replica"
    40  )
    41  
    42  func TestCRUD(t *testing.T) {
    43  	dirName := t.TempDir()
    44  
    45  	logger, _ := test.NewNullLogger()
    46  	thingclass := &models.Class{
    47  		VectorIndexConfig:   enthnsw.NewDefaultUserConfig(),
    48  		InvertedIndexConfig: invertedConfig(),
    49  		Class:               "TheBestThingClass",
    50  		Properties: []*models.Property{
    51  			{
    52  				Name:         "stringProp",
    53  				DataType:     schema.DataTypeText.PropString(),
    54  				Tokenization: models.PropertyTokenizationWhitespace,
    55  			},
    56  			{
    57  				Name:     "location",
    58  				DataType: []string{string(schema.DataTypeGeoCoordinates)},
    59  			},
    60  			{
    61  				Name:     "phone",
    62  				DataType: []string{string(schema.DataTypePhoneNumber)},
    63  			},
    64  		},
    65  	}
    66  	actionclass := &models.Class{
    67  		Class:               "TheBestActionClass",
    68  		VectorIndexConfig:   enthnsw.NewDefaultUserConfig(),
    69  		InvertedIndexConfig: invertedConfig(),
    70  		Properties: []*models.Property{
    71  			{
    72  				Name:         "stringProp",
    73  				DataType:     schema.DataTypeText.PropString(),
    74  				Tokenization: models.PropertyTokenizationWhitespace,
    75  			},
    76  			{
    77  				Name:     "refProp",
    78  				DataType: []string{"TheBestThingClass"},
    79  			},
    80  			{
    81  				Name:     "phone",
    82  				DataType: []string{string(schema.DataTypePhoneNumber)},
    83  			},
    84  		},
    85  	}
    86  	schemaGetter := &fakeSchemaGetter{
    87  		schema:     schema.Schema{Objects: &models.Schema{Classes: nil}},
    88  		shardState: singleShardState(),
    89  	}
    90  	repo, err := New(logger, Config{
    91  		MemtablesFlushDirtyAfter:  60,
    92  		RootPath:                  dirName,
    93  		QueryMaximumResults:       10,
    94  		MaxImportGoroutinesFactor: 1,
    95  	}, &fakeRemoteClient{}, &fakeNodeResolver{}, &fakeRemoteNodeClient{}, &fakeReplicationClient{}, nil)
    96  	require.Nil(t, err)
    97  	repo.SetSchemaGetter(schemaGetter)
    98  	require.Nil(t, repo.WaitForStartup(testCtx()))
    99  	defer repo.Shutdown(context.Background())
   100  	migrator := NewMigrator(repo, logger)
   101  
   102  	t.Run("creating the thing class", func(t *testing.T) {
   103  		require.Nil(t,
   104  			migrator.AddClass(context.Background(), thingclass, schemaGetter.shardState))
   105  	})
   106  
   107  	t.Run("creating the action class", func(t *testing.T) {
   108  		require.Nil(t,
   109  			migrator.AddClass(context.Background(), actionclass, schemaGetter.shardState))
   110  	})
   111  
   112  	// update schema getter so it's in sync with class
   113  	schemaGetter.schema = schema.Schema{
   114  		Objects: &models.Schema{
   115  			Classes: []*models.Class{actionclass, thingclass},
   116  		},
   117  	}
   118  
   119  	thingID := strfmt.UUID("a0b55b05-bc5b-4cc9-b646-1452d1390a62")
   120  
   121  	t.Run("validating that the thing doesn't exist prior", func(t *testing.T) {
   122  		ok, err := repo.Exists(context.Background(), "TheBestThingClass", thingID, nil, "")
   123  		require.Nil(t, err)
   124  		assert.False(t, ok)
   125  	})
   126  
   127  	t.Run("adding a thing", func(t *testing.T) {
   128  		thing := &models.Object{
   129  			CreationTimeUnix:   1565612833955,
   130  			LastUpdateTimeUnix: 1000001,
   131  			ID:                 thingID,
   132  			Class:              "TheBestThingClass",
   133  			Properties: map[string]interface{}{
   134  				"stringProp": "some value",
   135  				"phone": &models.PhoneNumber{
   136  					CountryCode:            49,
   137  					DefaultCountry:         "DE",
   138  					Input:                  "0171 1234567",
   139  					Valid:                  true,
   140  					InternationalFormatted: "+49 171 1234567",
   141  					National:               1234567,
   142  					NationalFormatted:      "0171 1234567",
   143  				},
   144  				"location": &models.GeoCoordinates{
   145  					Latitude:  ptFloat32(1),
   146  					Longitude: ptFloat32(2),
   147  				},
   148  			},
   149  			Additional: models.AdditionalProperties{
   150  				"interpretation": map[string]interface{}{
   151  					"source": []interface{}{
   152  						map[string]interface{}{
   153  							"concept":    "some",
   154  							"occurrence": float64(1),
   155  							"weight":     float64(1),
   156  						},
   157  						map[string]interface{}{
   158  							"concept":    "value",
   159  							"occurrence": float64(1),
   160  							"weight":     float64(1),
   161  						},
   162  					},
   163  				},
   164  			},
   165  		}
   166  		vector := []float32{1, 3, 5, 0.4}
   167  
   168  		err := repo.PutObject(context.Background(), thing, vector, nil, nil)
   169  
   170  		assert.Nil(t, err)
   171  	})
   172  
   173  	t.Run("validating that the thing exists now", func(t *testing.T) {
   174  		ok, err := repo.Exists(context.Background(), "TheBestThingClass", thingID, nil, "")
   175  		require.Nil(t, err)
   176  		assert.True(t, ok)
   177  	})
   178  
   179  	t.Run("trying to add a thing to a non-existing class", func(t *testing.T) {
   180  		thing := &models.Object{
   181  			CreationTimeUnix:   1565612833955,
   182  			LastUpdateTimeUnix: 1000001,
   183  			ID:                 thingID,
   184  			Class:              "WrongClass",
   185  			Properties: map[string]interface{}{
   186  				"stringProp": "some value",
   187  			},
   188  		}
   189  		vector := []float32{1, 3, 5, 0.4}
   190  
   191  		err := repo.PutObject(context.Background(), thing, vector, nil, nil)
   192  		assert.Equal(t,
   193  			fmt.Errorf("import into non-existing index for WrongClass"), err)
   194  	})
   195  
   196  	timeMust := func(t strfmt.DateTime, err error) strfmt.DateTime {
   197  		if err != nil {
   198  			panic(err)
   199  		}
   200  
   201  		return t
   202  	}
   203  
   204  	t.Run("updating the thing", func(t *testing.T) {
   205  		thing := &models.Object{
   206  			CreationTimeUnix:   1565612833955,
   207  			LastUpdateTimeUnix: 10000020,
   208  			ID:                 thingID,
   209  			Class:              "TheBestThingClass",
   210  			Properties: map[string]interface{}{
   211  				"stringProp": "updated value",
   212  				"phone": &models.PhoneNumber{
   213  					CountryCode:            49,
   214  					DefaultCountry:         "DE",
   215  					Input:                  "0171 1234567",
   216  					Valid:                  true,
   217  					InternationalFormatted: "+49 171 1234567",
   218  					National:               1234567,
   219  					NationalFormatted:      "0171 1234567",
   220  				},
   221  				"location": &models.GeoCoordinates{
   222  					Latitude:  ptFloat32(1),
   223  					Longitude: ptFloat32(2),
   224  				},
   225  			},
   226  		}
   227  		vector := []float32{1, 3, 5, 0.4}
   228  
   229  		err := repo.PutObject(context.Background(), thing, vector, nil, nil)
   230  		assert.Nil(t, err)
   231  	})
   232  
   233  	t.Run("validating the updates are reflected", func(t *testing.T) {
   234  		expected := &models.Object{
   235  			CreationTimeUnix:   1565612833955,
   236  			LastUpdateTimeUnix: 10000020,
   237  			ID:                 thingID,
   238  			Class:              "TheBestThingClass",
   239  			VectorWeights:      map[string]string(nil),
   240  			Properties: map[string]interface{}{
   241  				"stringProp": "updated value",
   242  				"phone": &models.PhoneNumber{
   243  					CountryCode:            49,
   244  					DefaultCountry:         "DE",
   245  					Input:                  "0171 1234567",
   246  					Valid:                  true,
   247  					InternationalFormatted: "+49 171 1234567",
   248  					National:               1234567,
   249  					NationalFormatted:      "0171 1234567",
   250  				},
   251  				"location": &models.GeoCoordinates{
   252  					Latitude:  ptFloat32(1),
   253  					Longitude: ptFloat32(2),
   254  				},
   255  			},
   256  			Additional: models.AdditionalProperties{},
   257  		}
   258  		res, err := repo.ObjectByID(context.Background(), thingID, nil, additional.Properties{}, "")
   259  		require.Nil(t, err)
   260  		assert.Equal(t, expected, res.ObjectWithVector(false))
   261  
   262  		res, err = repo.Object(context.Background(), expected.Class, thingID, nil,
   263  			additional.Properties{}, nil, "")
   264  		require.Nil(t, err)
   265  		assert.Equal(t, expected, res.ObjectWithVector(false))
   266  	})
   267  
   268  	t.Run("finding the updated object by querying for an updated value",
   269  		func(t *testing.T) {
   270  			// This is to verify the inverted index was updated correctly
   271  			res, err := repo.Search(context.Background(), dto.GetParams{
   272  				ClassName:  "TheBestThingClass",
   273  				Pagination: &filters.Pagination{Limit: 10},
   274  				Filters: &filters.LocalFilter{
   275  					Root: &filters.Clause{
   276  						Operator: filters.OperatorEqual,
   277  						On: &filters.Path{
   278  							Class:    "TheBestThingClass",
   279  							Property: "stringProp",
   280  						},
   281  						Value: &filters.Value{
   282  							// we would not have found this object before using "updated", as
   283  							// this string was only introduced as part of the update
   284  							Value: "updated",
   285  							Type:  schema.DataTypeText,
   286  						},
   287  					},
   288  				},
   289  			})
   290  			require.Nil(t, err)
   291  			require.Len(t, res, 1)
   292  			assert.Equal(t, thingID, res[0].ID)
   293  		})
   294  
   295  	t.Run("NOT finding the previous version by querying for an outdated value",
   296  		func(t *testing.T) {
   297  			// This is to verify the inverted index was cleaned up correctly
   298  			res, err := repo.Search(context.Background(), dto.GetParams{
   299  				ClassName:  "TheBestThingClass",
   300  				Pagination: &filters.Pagination{Limit: 10},
   301  				Filters: &filters.LocalFilter{
   302  					Root: &filters.Clause{
   303  						Operator: filters.OperatorEqual,
   304  						On: &filters.Path{
   305  							Class:    "TheBestThingClass",
   306  							Property: "stringProp",
   307  						},
   308  						Value: &filters.Value{
   309  							Value: "some",
   310  							Type:  schema.DataTypeText,
   311  						},
   312  					},
   313  				},
   314  			})
   315  			require.Nil(t, err)
   316  			require.Len(t, res, 0)
   317  		})
   318  
   319  	t.Run("still finding it for an unchanged term",
   320  		func(t *testing.T) {
   321  			// This is to verify that while we're adding new links and cleaning up
   322  			// old ones, we don't actually touch those that were present and still
   323  			// should be
   324  			res, err := repo.Search(context.Background(), dto.GetParams{
   325  				ClassName:  "TheBestThingClass",
   326  				Pagination: &filters.Pagination{Limit: 10},
   327  				Filters: &filters.LocalFilter{
   328  					Root: &filters.Clause{
   329  						Operator: filters.OperatorEqual,
   330  						On: &filters.Path{
   331  							Class:    "TheBestThingClass",
   332  							Property: "stringProp",
   333  						},
   334  						Value: &filters.Value{
   335  							// we would not have found this object before using "updated", as
   336  							// this string was only introduced as part of the update
   337  							Value: "value",
   338  							Type:  schema.DataTypeText,
   339  						},
   340  					},
   341  				},
   342  			})
   343  			require.Nil(t, err)
   344  			require.Len(t, res, 1)
   345  			assert.Equal(t, thingID, res[0].ID)
   346  		})
   347  
   348  	t.Run("updating the thing back to its original value", func(t *testing.T) {
   349  		thing := &models.Object{
   350  			CreationTimeUnix:   1565612833955,
   351  			LastUpdateTimeUnix: 1000001,
   352  			ID:                 thingID,
   353  			Class:              "TheBestThingClass",
   354  			Properties: map[string]interface{}{
   355  				"stringProp": "some value",
   356  				"phone": &models.PhoneNumber{
   357  					CountryCode:            49,
   358  					DefaultCountry:         "DE",
   359  					Input:                  "0171 1234567",
   360  					Valid:                  true,
   361  					InternationalFormatted: "+49 171 1234567",
   362  					National:               1234567,
   363  					NationalFormatted:      "0171 1234567",
   364  				},
   365  				"location": &models.GeoCoordinates{
   366  					Latitude:  ptFloat32(1),
   367  					Longitude: ptFloat32(2),
   368  				},
   369  			},
   370  		}
   371  		vector := []float32{1, 3, 5, 0.4}
   372  
   373  		err := repo.PutObject(context.Background(), thing, vector, nil, nil)
   374  		assert.Nil(t, err)
   375  	})
   376  
   377  	actionID := strfmt.UUID("022ca5ba-7c0b-4a78-85bf-26346bbcfae7")
   378  	t.Run("adding an action", func(t *testing.T) {
   379  		action := &models.Object{
   380  			CreationTimeUnix:   1000002,
   381  			LastUpdateTimeUnix: 1000003,
   382  			ID:                 actionID,
   383  			Class:              "TheBestActionClass",
   384  			Properties: map[string]interface{}{
   385  				"stringProp": "some act-citing value",
   386  				"refProp": models.MultipleRef{
   387  					&models.SingleRef{
   388  						Classification: &models.ReferenceMetaClassification{
   389  							LosingDistance:         ptFloat64(0.7),
   390  							MeanLosingDistance:     ptFloat64(0.7),
   391  							ClosestLosingDistance:  ptFloat64(0.65),
   392  							WinningDistance:        0.3,
   393  							MeanWinningDistance:    0.3,
   394  							ClosestWinningDistance: 0.25,
   395  							ClosestOverallDistance: 0.25,
   396  							OverallCount:           3,
   397  							WinningCount:           2,
   398  							LosingCount:            1,
   399  						},
   400  						Beacon: strfmt.URI(
   401  							crossref.NewLocalhost("", thingID).String()),
   402  					},
   403  				},
   404  			},
   405  			Additional: models.AdditionalProperties{
   406  				"classification": &additional.Classification{
   407  					ID:               "foo",
   408  					Scope:            []string{"scope1", "scope2"},
   409  					ClassifiedFields: []string{"field1", "field2"},
   410  					Completed:        timeMust(strfmt.ParseDateTime("2006-01-02T15:04:05.000Z")),
   411  				},
   412  			},
   413  		}
   414  		vector := []float32{3, 1, 0.3, 12}
   415  
   416  		err := repo.PutObject(context.Background(), action, vector, nil, nil)
   417  
   418  		assert.Nil(t, err)
   419  	})
   420  
   421  	t.Run("searching by vector", func(t *testing.T) {
   422  		// the search vector is designed to be very close to the action, but
   423  		// somewhat far from the thing. So it should match the action closer
   424  		searchVector := []float32{2.9, 1.1, 0.5, 8.01}
   425  
   426  		res, err := repo.CrossClassVectorSearch(context.Background(), searchVector, "", 0, 10, nil)
   427  
   428  		require.Nil(t, err)
   429  		require.Equal(t, true, len(res) >= 2)
   430  		assert.Equal(t, actionID, res[0].ID)
   431  		assert.Equal(t, "TheBestActionClass", res[0].ClassName)
   432  		assert.Equal(t, "TheBestActionClass", res[0].ClassName)
   433  		assert.Equal(t, int64(1000002), res[0].Created)
   434  		assert.Equal(t, int64(1000003), res[0].Updated)
   435  		assert.Equal(t, thingID, res[1].ID)
   436  
   437  		assert.Equal(t, "TheBestThingClass", res[1].ClassName)
   438  		assert.Equal(t, int64(1565612833955), res[1].Created)
   439  		assert.Equal(t, int64(1000001), res[1].Updated)
   440  	})
   441  
   442  	t.Run("searching by vector for a single class", func(t *testing.T) {
   443  		// the search vector is designed to be very close to the action, but
   444  		// somewhat far from the thing. So it should match the action closer
   445  		searchVector := []float32{2.9, 1.1, 0.5, 8.01}
   446  
   447  		params := dto.GetParams{
   448  			SearchVector: searchVector,
   449  			ClassName:    "TheBestThingClass",
   450  			Pagination:   &filters.Pagination{Limit: 10},
   451  			Filters:      nil,
   452  		}
   453  		res, err := repo.VectorSearch(context.Background(), params)
   454  
   455  		require.Nil(t, err)
   456  		require.Len(t, res, 1, "got exactly one result")
   457  		assert.Equal(t, thingID, res[0].ID, "extracted the ID")
   458  		assert.Equal(t, "TheBestThingClass", res[0].ClassName, "matches the class name")
   459  		schema := res[0].Schema.(map[string]interface{})
   460  		assert.Equal(t, "some value", schema["stringProp"], "has correct string prop")
   461  		assert.Equal(t, &models.GeoCoordinates{ptFloat32(1), ptFloat32(2)}, schema["location"], "has correct geo prop")
   462  		assert.Equal(t, &models.PhoneNumber{
   463  			CountryCode:            49,
   464  			DefaultCountry:         "DE",
   465  			Input:                  "0171 1234567",
   466  			Valid:                  true,
   467  			InternationalFormatted: "+49 171 1234567",
   468  			National:               1234567,
   469  			NationalFormatted:      "0171 1234567",
   470  		}, schema["phone"], "has correct phone prop")
   471  		assert.Equal(t, models.AdditionalProperties{}, res[0].AdditionalProperties, "no meta information should be included unless explicitly asked for")
   472  		assert.Equal(t, thingID, schema["id"], "has id in schema as uuid field")
   473  	})
   474  
   475  	t.Run("searching by class type", func(t *testing.T) {
   476  		params := dto.GetParams{
   477  			SearchVector: nil,
   478  			ClassName:    "TheBestThingClass",
   479  			Pagination:   &filters.Pagination{Limit: 10},
   480  			Filters:      nil,
   481  		}
   482  		res, err := repo.Search(context.Background(), params)
   483  
   484  		require.Nil(t, err)
   485  		require.Len(t, res, 1, "got exactly one result")
   486  		assert.Equal(t, thingID, res[0].ID, "extracted the ID")
   487  		assert.Equal(t, "TheBestThingClass", res[0].ClassName, "matches the class name")
   488  		schema := res[0].Schema.(map[string]interface{})
   489  		assert.Equal(t, "some value", schema["stringProp"], "has correct string prop")
   490  		assert.Equal(t, &models.GeoCoordinates{ptFloat32(1), ptFloat32(2)}, schema["location"], "has correct geo prop")
   491  		assert.Equal(t, thingID, schema["id"], "has id in schema as uuid field")
   492  	})
   493  
   494  	t.Run("adding a thing with interpretation additional property", func(t *testing.T) {
   495  		thing := &models.Object{
   496  			CreationTimeUnix:   1565612833955,
   497  			LastUpdateTimeUnix: 1000001,
   498  			ID:                 thingID,
   499  			Class:              "TheBestThingClass",
   500  			Properties: map[string]interface{}{
   501  				"stringProp": "some value",
   502  				"phone": &models.PhoneNumber{
   503  					CountryCode:            49,
   504  					DefaultCountry:         "DE",
   505  					Input:                  "0171 1234567",
   506  					Valid:                  true,
   507  					InternationalFormatted: "+49 171 1234567",
   508  					National:               1234567,
   509  					NationalFormatted:      "0171 1234567",
   510  				},
   511  				"location": &models.GeoCoordinates{
   512  					Latitude:  ptFloat32(1),
   513  					Longitude: ptFloat32(2),
   514  				},
   515  			},
   516  			Additional: models.AdditionalProperties{
   517  				"interpretation": map[string]interface{}{
   518  					"source": []interface{}{
   519  						map[string]interface{}{
   520  							"concept":    "some",
   521  							"occurrence": float64(1),
   522  							"weight":     float64(1),
   523  						},
   524  						map[string]interface{}{
   525  							"concept":    "value",
   526  							"occurrence": float64(1),
   527  							"weight":     float64(1),
   528  						},
   529  					},
   530  				},
   531  			},
   532  		}
   533  		vector := []float32{1, 3, 5, 0.4}
   534  
   535  		err := repo.PutObject(context.Background(), thing, vector, nil, nil)
   536  
   537  		assert.Nil(t, err)
   538  	})
   539  
   540  	t.Run("searching all things", func(t *testing.T) {
   541  		// as the test suits grow we might have to extend the limit
   542  		res, err := repo.ObjectSearch(context.Background(), 0, 100, nil, nil, additional.Properties{}, "")
   543  		require.Nil(t, err)
   544  
   545  		item, ok := findID(res, thingID)
   546  		require.Equal(t, true, ok, "results should contain our desired thing id")
   547  
   548  		assert.Equal(t, thingID, item.ID, "extracted the ID")
   549  		assert.Equal(t, "TheBestThingClass", item.ClassName, "matches the class name")
   550  		schema := item.Schema.(map[string]interface{})
   551  		assert.Equal(t, "some value", schema["stringProp"], "has correct string prop")
   552  		assert.Equal(t, &models.GeoCoordinates{ptFloat32(1), ptFloat32(2)}, schema["location"], "has correct geo prop")
   553  		assert.Equal(t, thingID, schema["id"], "has id in schema as uuid field")
   554  		assert.Equal(t, models.AdditionalProperties{}, item.AdditionalProperties, "has no additional properties unless explicitly asked for")
   555  	})
   556  
   557  	t.Run("searching all things with Vector additional props", func(t *testing.T) {
   558  		// as the test suits grow we might have to extend the limit
   559  		res, err := repo.ObjectSearch(context.Background(), 0, 100, nil, nil, additional.Properties{Vector: true}, "")
   560  		require.Nil(t, err)
   561  
   562  		item, ok := findID(res, thingID)
   563  		require.Equal(t, true, ok, "results should contain our desired thing id")
   564  
   565  		assert.Equal(t, thingID, item.ID, "extracted the ID")
   566  		assert.Equal(t, "TheBestThingClass", item.ClassName, "matches the class name")
   567  		schema := item.Schema.(map[string]interface{})
   568  		assert.Equal(t, "some value", schema["stringProp"], "has correct string prop")
   569  		assert.Equal(t, &models.GeoCoordinates{ptFloat32(1), ptFloat32(2)}, schema["location"], "has correct geo prop")
   570  		assert.Equal(t, thingID, schema["id"], "has id in schema as uuid field")
   571  		assert.Equal(t, []float32{1, 3, 5, 0.4}, item.Vector, "has Vector property")
   572  	})
   573  
   574  	t.Run("searching all things with Vector and Interpretation additional props", func(t *testing.T) {
   575  		// as the test suits grow we might have to extend the limit
   576  		params := additional.Properties{
   577  			Vector: true,
   578  			ModuleParams: map[string]interface{}{
   579  				"interpretation": true,
   580  			},
   581  		}
   582  		res, err := repo.ObjectSearch(context.Background(), 0, 100, nil, nil, params, "")
   583  		require.Nil(t, err)
   584  
   585  		item, ok := findID(res, thingID)
   586  		require.Equal(t, true, ok, "results should contain our desired thing id")
   587  
   588  		assert.Equal(t, thingID, item.ID, "extracted the ID")
   589  		assert.Equal(t, "TheBestThingClass", item.ClassName, "matches the class name")
   590  		schema := item.Schema.(map[string]interface{})
   591  		assert.Equal(t, "some value", schema["stringProp"], "has correct string prop")
   592  		assert.Equal(t, &models.GeoCoordinates{ptFloat32(1), ptFloat32(2)}, schema["location"], "has correct geo prop")
   593  		assert.Equal(t, thingID, schema["id"], "has id in schema as uuid field")
   594  		assert.Equal(t, []float32{1, 3, 5, 0.4}, item.Vector, "has Vector property")
   595  		assert.Equal(t, models.AdditionalProperties{
   596  			"interpretation": map[string]interface{}{
   597  				"source": []interface{}{
   598  					map[string]interface{}{
   599  						"concept":    "some",
   600  						"occurrence": float64(1),
   601  						"weight":     float64(1),
   602  					},
   603  					map[string]interface{}{
   604  						"concept":    "value",
   605  						"occurrence": float64(1),
   606  						"weight":     float64(1),
   607  					},
   608  				},
   609  			},
   610  		}, item.AdditionalProperties, "has Vector and Interpretation additional property")
   611  	})
   612  
   613  	t.Run("searching a thing by ID", func(t *testing.T) {
   614  		item, err := repo.ObjectByID(context.Background(), thingID, search.SelectProperties{}, additional.Properties{}, "")
   615  		require.Nil(t, err)
   616  		require.NotNil(t, item, "must have a result")
   617  
   618  		assert.Equal(t, thingID, item.ID, "extracted the ID")
   619  		assert.Equal(t, "TheBestThingClass", item.ClassName, "matches the class name")
   620  		schema := item.Schema.(map[string]interface{})
   621  		assert.Equal(t, "some value", schema["stringProp"], "has correct string prop")
   622  		assert.Equal(t, &models.GeoCoordinates{ptFloat32(1), ptFloat32(2)}, schema["location"], "has correct geo prop")
   623  		assert.Equal(t, thingID, schema["id"], "has id in schema as uuid field")
   624  	})
   625  
   626  	// Check the same, but with Object()
   627  	t.Run("searching a thing by ID", func(t *testing.T) {
   628  		item, err := repo.Object(context.Background(), "TheBestThingClass",
   629  			thingID, search.SelectProperties{}, additional.Properties{}, nil, "")
   630  		require.Nil(t, err)
   631  		require.NotNil(t, item, "must have a result")
   632  
   633  		assert.Equal(t, thingID, item.ID, "extracted the ID")
   634  		assert.Equal(t, "TheBestThingClass", item.ClassName, "matches the class name")
   635  		schema := item.Schema.(map[string]interface{})
   636  		assert.Equal(t, "some value", schema["stringProp"], "has correct string prop")
   637  		assert.Equal(t, &models.GeoCoordinates{ptFloat32(1), ptFloat32(2)}, schema["location"], "has correct geo prop")
   638  		assert.Equal(t, thingID, schema["id"], "has id in schema as uuid field")
   639  	})
   640  
   641  	t.Run("listing multiple things by IDs (MultiGet)", func(t *testing.T) {
   642  		query := []multi.Identifier{
   643  			{
   644  				ID:        "be685717-e61e-450d-8d5c-f44f32d0336c", // this id does not exist
   645  				ClassName: "TheBestThingClass",
   646  			},
   647  			{
   648  				ID:        thingID.String(),
   649  				ClassName: "TheBestThingClass",
   650  			},
   651  		}
   652  		res, err := repo.MultiGet(context.Background(), query, additional.Properties{}, "")
   653  		require.Nil(t, err)
   654  		require.Len(t, res, 2, "length must match even with nil-items")
   655  
   656  		assert.Equal(t, strfmt.UUID(""), res[0].ID, "empty object for the not-found item")
   657  
   658  		item := res[1]
   659  		assert.Equal(t, thingID, item.ID, "extracted the ID")
   660  		assert.Equal(t, "TheBestThingClass", item.ClassName, "matches the class name")
   661  		schema := item.Schema.(map[string]interface{})
   662  		assert.Equal(t, "some value", schema["stringProp"], "has correct string prop")
   663  		assert.Equal(t, &models.GeoCoordinates{ptFloat32(1), ptFloat32(2)}, schema["location"], "has correct geo prop")
   664  		assert.Equal(t, thingID, schema["id"], "has id in schema as uuid field")
   665  	})
   666  
   667  	t.Run("searching an action by ID without meta", func(t *testing.T) {
   668  		item, err := repo.ObjectByID(context.Background(), actionID, search.SelectProperties{}, additional.Properties{}, "")
   669  		require.Nil(t, err)
   670  		require.NotNil(t, item, "must have a result")
   671  
   672  		assert.Equal(t, actionID, item.ID, "extracted the ID")
   673  		assert.Equal(t, "TheBestActionClass", item.ClassName, "matches the class name")
   674  		schema := item.Schema.(map[string]interface{})
   675  		assert.Equal(t, "some act-citing value", schema["stringProp"], "has correct string prop")
   676  		assert.Equal(t, models.AdditionalProperties{}, item.AdditionalProperties, "not meta information should be included unless explicitly asked for")
   677  		expectedRefProp := models.MultipleRef{
   678  			&models.SingleRef{
   679  				Beacon: strfmt.URI(
   680  					crossref.NewLocalhost("", thingID).String()),
   681  			},
   682  		}
   683  		assert.Equal(t, expectedRefProp, schema["refProp"])
   684  	})
   685  
   686  	t.Run("searching an action by ID with Classification and Vector additional properties", func(t *testing.T) {
   687  		item, err := repo.ObjectByID(context.Background(), actionID, search.SelectProperties{}, additional.Properties{Classification: true, Vector: true, RefMeta: true}, "")
   688  		require.Nil(t, err)
   689  		require.NotNil(t, item, "must have a result")
   690  
   691  		assert.Equal(t, actionID, item.ID, "extracted the ID")
   692  		assert.Equal(t, "TheBestActionClass", item.ClassName, "matches the class name")
   693  		schema := item.Schema.(map[string]interface{})
   694  		assert.Equal(t, "some act-citing value", schema["stringProp"], "has correct string prop")
   695  		assert.Equal(t, models.AdditionalProperties{
   696  			"classification": &additional.Classification{
   697  				ID:               "foo",
   698  				Scope:            []string{"scope1", "scope2"},
   699  				ClassifiedFields: []string{"field1", "field2"},
   700  				Completed:        timeMust(strfmt.ParseDateTime("2006-01-02T15:04:05.000Z")),
   701  			},
   702  		}, item.AdditionalProperties, "it should include the object meta as it was explicitly specified")
   703  		assert.Equal(t, []float32{3, 1, 0.3, 12}, item.Vector, "has Vector property")
   704  
   705  		expectedRefProp := models.MultipleRef{
   706  			&models.SingleRef{
   707  				Classification: &models.ReferenceMetaClassification{
   708  					LosingDistance:         ptFloat64(0.7),
   709  					MeanLosingDistance:     ptFloat64(0.7),
   710  					ClosestLosingDistance:  ptFloat64(0.65),
   711  					WinningDistance:        0.3,
   712  					MeanWinningDistance:    0.3,
   713  					ClosestWinningDistance: 0.25,
   714  					ClosestOverallDistance: 0.25,
   715  					OverallCount:           3,
   716  					WinningCount:           2,
   717  					LosingCount:            1,
   718  				},
   719  				Beacon: strfmt.URI(
   720  					crossref.NewLocalhost("", thingID).String()),
   721  			},
   722  		}
   723  		assert.Equal(t, expectedRefProp, schema["refProp"])
   724  	})
   725  
   726  	t.Run("searching an action by ID with only Vector additional property", func(t *testing.T) {
   727  		item, err := repo.ObjectByID(context.Background(), actionID, search.SelectProperties{}, additional.Properties{Vector: true}, "")
   728  		require.Nil(t, err)
   729  		require.NotNil(t, item, "must have a result")
   730  
   731  		assert.Equal(t, actionID, item.ID, "extracted the ID")
   732  		assert.Equal(t, "TheBestActionClass", item.ClassName, "matches the class name")
   733  		schema := item.Schema.(map[string]interface{})
   734  		assert.Equal(t, "some act-citing value", schema["stringProp"], "has correct string prop")
   735  		assert.Equal(t, []float32{3, 1, 0.3, 12}, item.Vector, "it should include the object meta as it was explicitly specified")
   736  	})
   737  
   738  	t.Run("searching all actions", func(t *testing.T) {
   739  		res, err := repo.ObjectSearch(context.Background(), 0, 10, nil, nil, additional.Properties{}, "")
   740  		require.Nil(t, err)
   741  
   742  		item, ok := findID(res, actionID)
   743  		require.Equal(t, true, ok, "results should contain our desired action id")
   744  
   745  		assert.Equal(t, actionID, item.ID, "extracted the ID")
   746  		assert.Equal(t, "TheBestActionClass", item.ClassName, "matches the class name")
   747  		schema := item.Schema.(map[string]interface{})
   748  		assert.Equal(t, "some act-citing value", schema["stringProp"], "has correct string prop")
   749  	})
   750  
   751  	t.Run("sorting all objects", func(t *testing.T) {
   752  		// prepare
   753  		thingID1 := strfmt.UUID("7c8183ae-150d-433f-92b6-ed095b000001")
   754  		thingID2 := strfmt.UUID("7c8183ae-150d-433f-92b6-ed095b000002")
   755  		thingID3 := strfmt.UUID("7c8183ae-150d-433f-92b6-ed095b000003")
   756  		thingID4 := strfmt.UUID("7c8183ae-150d-433f-92b6-ed095b000004")
   757  		actionID1 := strfmt.UUID("7c8183ae-150d-433f-92b6-ed095b100001")
   758  		actionID2 := strfmt.UUID("7c8183ae-150d-433f-92b6-ed095b100002")
   759  		actionID3 := strfmt.UUID("7c8183ae-150d-433f-92b6-ed095b100003")
   760  		testData := []struct {
   761  			id         strfmt.UUID
   762  			className  string
   763  			stringProp string
   764  			phone      uint64
   765  			longitude  float32
   766  		}{
   767  			{
   768  				id:         thingID1,
   769  				className:  "TheBestThingClass",
   770  				stringProp: "a very short text",
   771  				phone:      1234900,
   772  				longitude:  10,
   773  			},
   774  			{
   775  				id:         thingID2,
   776  				className:  "TheBestThingClass",
   777  				stringProp: "zebra lives in Zoo",
   778  				phone:      1234800,
   779  				longitude:  111,
   780  			},
   781  			{
   782  				id:         thingID3,
   783  				className:  "TheBestThingClass",
   784  				stringProp: "the best thing class",
   785  				phone:      1234910,
   786  				longitude:  2,
   787  			},
   788  			{
   789  				id:         thingID4,
   790  				className:  "TheBestThingClass",
   791  				stringProp: "car",
   792  				phone:      1234901,
   793  				longitude:  11,
   794  			},
   795  			{
   796  				id:         actionID1,
   797  				className:  "TheBestActionClass",
   798  				stringProp: "a very short text",
   799  				phone:      1234000,
   800  				longitude:  10,
   801  			},
   802  			{
   803  				id:         actionID2,
   804  				className:  "TheBestActionClass",
   805  				stringProp: "zebra lives in Zoo",
   806  				phone:      1234002,
   807  				longitude:  5,
   808  			},
   809  			{
   810  				id:         actionID3,
   811  				className:  "TheBestActionClass",
   812  				stringProp: "fossil fuels",
   813  				phone:      1234010,
   814  				longitude:  6,
   815  			},
   816  		}
   817  		for _, td := range testData {
   818  			object := &models.Object{
   819  				CreationTimeUnix:   1565612833990,
   820  				LastUpdateTimeUnix: 1000001,
   821  				ID:                 td.id,
   822  				Class:              td.className,
   823  				Properties: map[string]interface{}{
   824  					"stringProp": td.stringProp,
   825  					"phone": &models.PhoneNumber{
   826  						CountryCode:            49,
   827  						DefaultCountry:         "DE",
   828  						Input:                  fmt.Sprintf("0171 %d", td.phone),
   829  						Valid:                  true,
   830  						InternationalFormatted: fmt.Sprintf("+49 171 %d", td.phone),
   831  						National:               td.phone,
   832  						NationalFormatted:      fmt.Sprintf("0171 %d", td.phone),
   833  					},
   834  					"location": &models.GeoCoordinates{
   835  						Latitude:  ptFloat32(1),
   836  						Longitude: ptFloat32(td.longitude),
   837  					},
   838  				},
   839  			}
   840  			vector := []float32{1.1, 1.3, 1.5, 1.4}
   841  			err := repo.PutObject(context.Background(), object, vector, nil, nil)
   842  			assert.Nil(t, err)
   843  		}
   844  		// run sorting tests
   845  		tests := []struct {
   846  			name               string
   847  			sort               []filters.Sort
   848  			expectedThingIDs   []strfmt.UUID
   849  			expectedActionIDs  []strfmt.UUID
   850  			constainsErrorMsgs []string
   851  		}{
   852  			{
   853  				name:              "by stringProp asc",
   854  				sort:              []filters.Sort{{Path: []string{"stringProp"}, Order: "asc"}},
   855  				expectedThingIDs:  []strfmt.UUID{thingID1, thingID4, thingID, thingID3, thingID2},
   856  				expectedActionIDs: []strfmt.UUID{actionID1, actionID3, actionID, actionID2},
   857  			},
   858  			{
   859  				name:              "by stringProp desc",
   860  				sort:              []filters.Sort{{Path: []string{"stringProp"}, Order: "desc"}},
   861  				expectedThingIDs:  []strfmt.UUID{thingID2, thingID3, thingID, thingID4, thingID1},
   862  				expectedActionIDs: []strfmt.UUID{actionID2, actionID, actionID3, actionID1},
   863  			},
   864  			{
   865  				name:              "by phone asc",
   866  				sort:              []filters.Sort{{Path: []string{"phone"}, Order: "asc"}},
   867  				expectedThingIDs:  []strfmt.UUID{thingID, thingID2, thingID1, thingID4, thingID3},
   868  				expectedActionIDs: []strfmt.UUID{actionID, actionID1, actionID2, actionID3},
   869  			},
   870  			{
   871  				name:              "by phone desc",
   872  				sort:              []filters.Sort{{Path: []string{"phone"}, Order: "desc"}},
   873  				expectedThingIDs:  []strfmt.UUID{thingID3, thingID4, thingID1, thingID2, thingID},
   874  				expectedActionIDs: []strfmt.UUID{actionID3, actionID2, actionID1, actionID},
   875  			},
   876  			{
   877  				name: "by phone and stringProp asc",
   878  				sort: []filters.Sort{
   879  					{Path: []string{"phone"}, Order: "asc"},
   880  					{Path: []string{"stringProp"}, Order: "asc"},
   881  				},
   882  				expectedThingIDs:  []strfmt.UUID{thingID, thingID2, thingID1, thingID4, thingID3},
   883  				expectedActionIDs: []strfmt.UUID{actionID, actionID1, actionID2, actionID3},
   884  			},
   885  			{
   886  				name: "by location asc",
   887  				sort: []filters.Sort{{Path: []string{"location"}, Order: "asc"}},
   888  				constainsErrorMsgs: []string{"search: search index thebestactionclass: sort parameter at position 0: " +
   889  					"no such prop with name 'location' found in class 'TheBestActionClass' in the schema. " +
   890  					"Check your schema files for which properties in this class are available"},
   891  			},
   892  		}
   893  		for _, tt := range tests {
   894  			t.Run(tt.name, func(t *testing.T) {
   895  				res, err := repo.ObjectSearch(context.Background(), 0, 100, nil, tt.sort, additional.Properties{Vector: true}, "")
   896  				if len(tt.constainsErrorMsgs) > 0 {
   897  					require.NotNil(t, err)
   898  					for _, errorMsg := range tt.constainsErrorMsgs {
   899  						assert.Contains(t, err.Error(), errorMsg)
   900  					}
   901  				} else {
   902  					require.Nil(t, err)
   903  					require.Len(t, res, 9)
   904  
   905  					var thingIds, actionIds []strfmt.UUID
   906  					for i := range res {
   907  						if res[i].ClassName == "TheBestThingClass" {
   908  							thingIds = append(thingIds, res[i].ID)
   909  						} else {
   910  							actionIds = append(actionIds, res[i].ID)
   911  						}
   912  					}
   913  					assert.EqualValues(t, thingIds, tt.expectedThingIDs, "thing ids don't match")
   914  					assert.EqualValues(t, actionIds, tt.expectedActionIDs, "action ids don't match")
   915  				}
   916  			})
   917  		}
   918  		// clean up
   919  		for _, td := range testData {
   920  			err := repo.DeleteObject(context.Background(), td.className, td.id, nil, "")
   921  			assert.Nil(t, err)
   922  		}
   923  	})
   924  
   925  	t.Run("verifying the thing is indexed in the inverted index", func(t *testing.T) {
   926  		// This is a control for the upcoming deletion, after the deletion it should not
   927  		// be indexed anymore.
   928  		res, err := repo.Search(context.Background(), dto.GetParams{
   929  			ClassName:  "TheBestThingClass",
   930  			Pagination: &filters.Pagination{Limit: 10},
   931  			Filters: &filters.LocalFilter{
   932  				Root: &filters.Clause{
   933  					Operator: filters.OperatorEqual,
   934  					On: &filters.Path{
   935  						Class:    "TheBestThingClass",
   936  						Property: "stringProp",
   937  					},
   938  					Value: &filters.Value{
   939  						Value: "some",
   940  						Type:  schema.DataTypeText,
   941  					},
   942  				},
   943  			},
   944  		})
   945  		require.Nil(t, err)
   946  		require.Len(t, res, 1)
   947  	})
   948  
   949  	t.Run("verifying the action is indexed in the inverted index", func(t *testing.T) {
   950  		// This is a control for the upcoming deletion, after the deletion it should not
   951  		// be indexed anymore.
   952  		res, err := repo.Search(context.Background(), dto.GetParams{
   953  			ClassName:  "TheBestActionClass",
   954  			Pagination: &filters.Pagination{Limit: 10},
   955  			Filters: &filters.LocalFilter{
   956  				Root: &filters.Clause{
   957  					Operator: filters.OperatorEqual,
   958  					On: &filters.Path{
   959  						Class:    "TheBestActionClass",
   960  						Property: "stringProp",
   961  					},
   962  					Value: &filters.Value{
   963  						Value: "some",
   964  						Type:  schema.DataTypeText,
   965  					},
   966  				},
   967  			},
   968  		})
   969  		require.Nil(t, err)
   970  		require.Len(t, res, 1)
   971  	})
   972  
   973  	t.Run("deleting a thing again", func(t *testing.T) {
   974  		err := repo.DeleteObject(context.Background(), "TheBestThingClass", thingID, nil, "")
   975  
   976  		assert.Nil(t, err)
   977  	})
   978  
   979  	t.Run("deleting a action again", func(t *testing.T) {
   980  		err := repo.DeleteObject(context.Background(), "TheBestActionClass", actionID, nil, "")
   981  
   982  		assert.Nil(t, err)
   983  	})
   984  
   985  	t.Run("trying to delete from a non-existing class", func(t *testing.T) {
   986  		err := repo.DeleteObject(context.Background(), "WrongClass", thingID, nil, "")
   987  
   988  		assert.Equal(t, fmt.Errorf(
   989  			"delete from non-existing index for WrongClass"), err)
   990  	})
   991  
   992  	t.Run("verifying the thing is NOT indexed in the inverted index",
   993  		func(t *testing.T) {
   994  			res, err := repo.Search(context.Background(), dto.GetParams{
   995  				ClassName:  "TheBestThingClass",
   996  				Pagination: &filters.Pagination{Limit: 10},
   997  				Filters: &filters.LocalFilter{
   998  					Root: &filters.Clause{
   999  						Operator: filters.OperatorEqual,
  1000  						On: &filters.Path{
  1001  							Class:    "TheBestThingClass",
  1002  							Property: "stringProp",
  1003  						},
  1004  						Value: &filters.Value{
  1005  							Value: "some",
  1006  							Type:  schema.DataTypeText,
  1007  						},
  1008  					},
  1009  				},
  1010  			})
  1011  			require.Nil(t, err)
  1012  			require.Len(t, res, 0)
  1013  		})
  1014  
  1015  	t.Run("verifying the action is NOT indexed in the inverted index",
  1016  		func(t *testing.T) {
  1017  			res, err := repo.Search(context.Background(), dto.GetParams{
  1018  				ClassName:  "TheBestActionClass",
  1019  				Pagination: &filters.Pagination{Limit: 10},
  1020  				Filters: &filters.LocalFilter{
  1021  					Root: &filters.Clause{
  1022  						Operator: filters.OperatorEqual,
  1023  						On: &filters.Path{
  1024  							Class:    "TheBestActionClass",
  1025  							Property: "stringProp",
  1026  						},
  1027  						Value: &filters.Value{
  1028  							Value: "some",
  1029  							Type:  schema.DataTypeText,
  1030  						},
  1031  					},
  1032  				},
  1033  			})
  1034  			require.Nil(t, err)
  1035  			require.Len(t, res, 0)
  1036  		})
  1037  
  1038  	t.Run("trying to get the deleted thing by ID", func(t *testing.T) {
  1039  		item, err := repo.ObjectByID(context.Background(), thingID, search.SelectProperties{}, additional.Properties{}, "")
  1040  		require.Nil(t, err)
  1041  		require.Nil(t, item, "must not have a result")
  1042  	})
  1043  
  1044  	t.Run("trying to get the deleted action by ID", func(t *testing.T) {
  1045  		item, err := repo.ObjectByID(context.Background(), actionID, search.SelectProperties{}, additional.Properties{}, "")
  1046  		require.Nil(t, err)
  1047  		require.Nil(t, item, "must not have a result")
  1048  	})
  1049  
  1050  	t.Run("searching by vector for a single thing class again after deletion",
  1051  		func(t *testing.T) {
  1052  			searchVector := []float32{2.9, 1.1, 0.5, 8.01}
  1053  			params := dto.GetParams{
  1054  				SearchVector: searchVector,
  1055  				ClassName:    "TheBestThingClass",
  1056  				Pagination:   &filters.Pagination{Limit: 10},
  1057  				Filters:      nil,
  1058  			}
  1059  
  1060  			res, err := repo.VectorSearch(context.Background(), params)
  1061  
  1062  			require.Nil(t, err)
  1063  			assert.Len(t, res, 0)
  1064  		})
  1065  
  1066  	t.Run("searching by vector for a single action class again after deletion", func(t *testing.T) {
  1067  		searchVector := []float32{2.9, 1.1, 0.5, 8.01}
  1068  		params := dto.GetParams{
  1069  			SearchVector: searchVector,
  1070  			ClassName:    "TheBestActionClass",
  1071  			Pagination:   &filters.Pagination{Limit: 10},
  1072  			Filters:      nil,
  1073  		}
  1074  
  1075  		res, err := repo.VectorSearch(context.Background(), params)
  1076  
  1077  		require.Nil(t, err)
  1078  		assert.Len(t, res, 0)
  1079  	})
  1080  
  1081  	t.Run("ensure referenced class searches are not limited", func(t *testing.T) {
  1082  		numThings := int(repo.config.QueryMaximumResults * 10)
  1083  		createdActionIDs := make([]strfmt.UUID, numThings)
  1084  		createdThingIDs := make([]strfmt.UUID, numThings)
  1085  
  1086  		t.Run("add new action objects", func(t *testing.T) {
  1087  			actionBatch := make([]objects.BatchObject, numThings)
  1088  			for i := 0; i < len(createdActionIDs); i++ {
  1089  				newID := strfmt.UUID(uuid.NewString())
  1090  				actionBatch[i] = objects.BatchObject{
  1091  					UUID: newID,
  1092  					Object: &models.Object{
  1093  						ID:    newID,
  1094  						Class: "TheBestActionClass",
  1095  						Properties: map[string]interface{}{
  1096  							"stringProp": fmt.Sprintf("action#%d", i),
  1097  						},
  1098  					},
  1099  				}
  1100  				createdActionIDs[i] = newID
  1101  			}
  1102  			batchObjResp, err := repo.BatchPutObjects(context.Background(), actionBatch, nil)
  1103  			require.Len(t, batchObjResp, numThings)
  1104  			require.Nil(t, err)
  1105  			for _, r := range batchObjResp {
  1106  				require.Nil(t, r.Err)
  1107  			}
  1108  		})
  1109  
  1110  		t.Run("add more thing objects to reference", func(t *testing.T) {
  1111  			thingBatch := make([]objects.BatchObject, numThings)
  1112  			for i := 0; i < len(createdThingIDs); i++ {
  1113  				newID := strfmt.UUID(uuid.NewString())
  1114  				thingBatch[i] = objects.BatchObject{
  1115  					UUID: newID,
  1116  					Object: &models.Object{
  1117  						ID:    newID,
  1118  						Class: "TheBestThingClass",
  1119  						Properties: map[string]interface{}{
  1120  							"stringProp": fmt.Sprintf("thing#%d", i),
  1121  						},
  1122  					},
  1123  				}
  1124  				createdThingIDs[i] = newID
  1125  			}
  1126  			batchObjResp, err := repo.BatchPutObjects(context.Background(), thingBatch, nil)
  1127  			require.Len(t, batchObjResp, numThings)
  1128  			require.Nil(t, err)
  1129  			for _, r := range batchObjResp {
  1130  				require.Nil(t, r.Err)
  1131  			}
  1132  		})
  1133  
  1134  		t.Run("reference each thing from an action", func(t *testing.T) {
  1135  			refBatch := make([]objects.BatchReference, numThings)
  1136  			for i := range refBatch {
  1137  				ref := objects.BatchReference{
  1138  					From: &crossref.RefSource{
  1139  						Local:    true,
  1140  						PeerName: "localhost",
  1141  						Class:    "TheBestActionClass",
  1142  						Property: schema.PropertyName("refProp"),
  1143  						TargetID: createdActionIDs[i],
  1144  					},
  1145  					To: &crossref.Ref{
  1146  						Local:    true,
  1147  						PeerName: "localhost",
  1148  						TargetID: createdThingIDs[i],
  1149  					},
  1150  				}
  1151  				refBatch[i] = ref
  1152  			}
  1153  			batchRefResp, err := repo.AddBatchReferences(context.Background(), refBatch, nil)
  1154  			require.Nil(t, err)
  1155  			require.Len(t, batchRefResp, numThings)
  1156  			for _, r := range batchRefResp {
  1157  				require.Nil(t, r.Err)
  1158  			}
  1159  		})
  1160  
  1161  		t.Run("query every action for its referenced thing", func(t *testing.T) {
  1162  			for i := range createdActionIDs {
  1163  				resp, err := repo.Search(context.Background(), dto.GetParams{
  1164  					ClassName:            "TheBestActionClass",
  1165  					Pagination:           &filters.Pagination{Limit: 5},
  1166  					AdditionalProperties: additional.Properties{ID: true},
  1167  					Properties: search.SelectProperties{
  1168  						{
  1169  							Name: "refProp",
  1170  							Refs: []search.SelectClass{
  1171  								{
  1172  									ClassName: "TheBestThingClass",
  1173  									RefProperties: search.SelectProperties{
  1174  										{
  1175  											Name:        "stringProp",
  1176  											IsPrimitive: true,
  1177  										},
  1178  									},
  1179  								},
  1180  							},
  1181  						},
  1182  					},
  1183  					Filters: &filters.LocalFilter{
  1184  						Root: &filters.Clause{
  1185  							Operator: filters.OperatorAnd,
  1186  							Operands: []filters.Clause{
  1187  								{
  1188  									Operator: filters.OperatorEqual,
  1189  									On: &filters.Path{
  1190  										Class:    "TheBestActionClass",
  1191  										Property: "stringProp",
  1192  									},
  1193  									Value: &filters.Value{
  1194  										Value: fmt.Sprintf("action#%d", i),
  1195  										Type:  schema.DataTypeText,
  1196  									},
  1197  								},
  1198  								{
  1199  									Operator: filters.OperatorLike,
  1200  									On: &filters.Path{
  1201  										Class:    "TheBestActionClass",
  1202  										Property: "refProp",
  1203  										Child: &filters.Path{
  1204  											Class:    "TheBestThingClass",
  1205  											Property: "stringProp",
  1206  										},
  1207  									},
  1208  									Value: &filters.Value{
  1209  										Value: "thing#*",
  1210  										Type:  schema.DataTypeText,
  1211  									},
  1212  								},
  1213  							},
  1214  						},
  1215  					},
  1216  				})
  1217  
  1218  				require.Nil(t, err)
  1219  				require.Len(t, resp, 1)
  1220  				assert.Len(t, resp[0].Schema.(map[string]interface{})["refProp"], 1)
  1221  			}
  1222  		})
  1223  	})
  1224  
  1225  	t.Run("query obj by id which has no props", func(t *testing.T) {
  1226  		id := strfmt.UUID("2cd8a381-6568-4724-9d5c-1ef28d439e94")
  1227  
  1228  		t.Run("insert test obj", func(t *testing.T) {
  1229  			vec := []float32{0.1, 0.2, 0.3, 0.4}
  1230  
  1231  			obj := &models.Object{
  1232  				ID:     id,
  1233  				Class:  "TheBestActionClass",
  1234  				Vector: vec,
  1235  			}
  1236  			require.Nil(t, repo.PutObject(context.Background(), obj, vec, nil, nil))
  1237  		})
  1238  
  1239  		t.Run("perform search with id filter", func(t *testing.T) {
  1240  			res, err := repo.Search(context.Background(), dto.GetParams{
  1241  				Pagination: &filters.Pagination{Limit: 10},
  1242  				ClassName:  "TheBestActionClass",
  1243  				Filters: &filters.LocalFilter{
  1244  					Root: &filters.Clause{
  1245  						Operator: filters.OperatorEqual,
  1246  						On: &filters.Path{
  1247  							Class:    "TheBestActionClass",
  1248  							Property: filters.InternalPropID,
  1249  						},
  1250  						Value: &filters.Value{
  1251  							Value: id.String(),
  1252  							Type:  schema.DataTypeText,
  1253  						},
  1254  					},
  1255  				},
  1256  			})
  1257  
  1258  			require.Nil(t, err)
  1259  
  1260  			expected := []search.Result{
  1261  				{
  1262  					ID:        id,
  1263  					ClassName: "TheBestActionClass",
  1264  					Schema: map[string]interface{}{
  1265  						"id": id,
  1266  					},
  1267  					Score:                0,
  1268  					AdditionalProperties: models.AdditionalProperties{},
  1269  					Dims:                 4,
  1270  				},
  1271  			}
  1272  
  1273  			for i := range expected {
  1274  				expected[i].DocID = res[i].DocID
  1275  			}
  1276  
  1277  			assert.Equal(t, expected, res)
  1278  		})
  1279  	})
  1280  }
  1281  
  1282  func TestCRUD_Query(t *testing.T) {
  1283  	dirName := t.TempDir()
  1284  
  1285  	logger, _ := test.NewNullLogger()
  1286  	thingclass := &models.Class{
  1287  		VectorIndexConfig:   enthnsw.NewDefaultUserConfig(),
  1288  		InvertedIndexConfig: invertedConfig(),
  1289  		Class:               "TheBestThingClass",
  1290  		Properties: []*models.Property{
  1291  			{
  1292  				Name:         "stringProp",
  1293  				DataType:     schema.DataTypeText.PropString(),
  1294  				Tokenization: models.PropertyTokenizationWhitespace,
  1295  			},
  1296  		},
  1297  	}
  1298  	schemaGetter := &fakeSchemaGetter{
  1299  		schema:     schema.Schema{Objects: &models.Schema{Classes: nil}},
  1300  		shardState: singleShardState(),
  1301  	}
  1302  	repo, err := New(logger, Config{
  1303  		MemtablesFlushDirtyAfter:  60,
  1304  		RootPath:                  dirName,
  1305  		QueryMaximumResults:       10,
  1306  		MaxImportGoroutinesFactor: 1,
  1307  	}, &fakeRemoteClient{}, &fakeNodeResolver{}, &fakeRemoteNodeClient{}, &fakeReplicationClient{}, nil)
  1308  	require.Nil(t, err)
  1309  	repo.SetSchemaGetter(schemaGetter)
  1310  	require.Nil(t, repo.WaitForStartup(testCtx()))
  1311  	defer repo.Shutdown(context.Background())
  1312  	migrator := NewMigrator(repo, logger)
  1313  
  1314  	t.Run("creating the thing class", func(t *testing.T) {
  1315  		require.Nil(t,
  1316  			migrator.AddClass(context.Background(), thingclass, schemaGetter.shardState))
  1317  	})
  1318  
  1319  	// update schema getter so it's in sync with class
  1320  	schemaGetter.schema = schema.Schema{
  1321  		Objects: &models.Schema{
  1322  			Classes: []*models.Class{thingclass},
  1323  		},
  1324  	}
  1325  
  1326  	t.Run("scroll through all objects", func(t *testing.T) {
  1327  		// prepare
  1328  		className := "TheBestThingClass"
  1329  		thingID1 := strfmt.UUID("7c8183ae-150d-433f-92b6-ed095b000001")
  1330  		thingID2 := strfmt.UUID("7c8183ae-150d-433f-92b6-ed095b000002")
  1331  		thingID3 := strfmt.UUID("7c8183ae-150d-433f-92b6-ed095b000003")
  1332  		thingID4 := strfmt.UUID("7c8183ae-150d-433f-92b6-ed095b000004")
  1333  		thingID5 := strfmt.UUID("7c8183ae-150d-433f-92b6-ed095b000005")
  1334  		thingID6 := strfmt.UUID("7c8183ae-150d-433f-92b6-ed095b000006")
  1335  		thingID7 := strfmt.UUID("7c8183ae-150d-433f-92b6-ed095b000007")
  1336  		testData := []struct {
  1337  			id         strfmt.UUID
  1338  			className  string
  1339  			stringProp string
  1340  			phone      uint64
  1341  			longitude  float32
  1342  		}{
  1343  			{
  1344  				id:         thingID1,
  1345  				className:  className,
  1346  				stringProp: "a very short text",
  1347  			},
  1348  			{
  1349  				id:         thingID2,
  1350  				className:  className,
  1351  				stringProp: "zebra lives in Zoo",
  1352  			},
  1353  			{
  1354  				id:         thingID3,
  1355  				className:  className,
  1356  				stringProp: "the best thing class",
  1357  			},
  1358  			{
  1359  				id:         thingID4,
  1360  				className:  className,
  1361  				stringProp: "car",
  1362  			},
  1363  			{
  1364  				id:         thingID5,
  1365  				className:  className,
  1366  				stringProp: "a very short text",
  1367  			},
  1368  			{
  1369  				id:         thingID6,
  1370  				className:  className,
  1371  				stringProp: "zebra lives in Zoo",
  1372  			},
  1373  			{
  1374  				id:         thingID7,
  1375  				className:  className,
  1376  				stringProp: "fossil fuels",
  1377  			},
  1378  		}
  1379  		for _, td := range testData {
  1380  			object := &models.Object{
  1381  				CreationTimeUnix:   1565612833990,
  1382  				LastUpdateTimeUnix: 1000001,
  1383  				ID:                 td.id,
  1384  				Class:              td.className,
  1385  				Properties: map[string]interface{}{
  1386  					"stringProp": td.stringProp,
  1387  				},
  1388  			}
  1389  			vector := []float32{1.1, 1.3, 1.5, 1.4}
  1390  			err := repo.PutObject(context.Background(), object, vector, nil, nil)
  1391  			assert.Nil(t, err)
  1392  		}
  1393  		// toParams helper method
  1394  		toParams := func(className string, offset, limit int,
  1395  			cursor *filters.Cursor, filters *filters.LocalFilter, sort []filters.Sort,
  1396  		) *objects.QueryInput {
  1397  			return &objects.QueryInput{
  1398  				Class:      className,
  1399  				Offset:     offset,
  1400  				Limit:      limit,
  1401  				Cursor:     cursor,
  1402  				Filters:    filters,
  1403  				Sort:       sort,
  1404  				Additional: additional.Properties{},
  1405  			}
  1406  		}
  1407  		// run scrolling through all results
  1408  		tests := []struct {
  1409  			name               string
  1410  			className          string
  1411  			cursor             *filters.Cursor
  1412  			query              *objects.QueryInput
  1413  			expectedThingIDs   []strfmt.UUID
  1414  			constainsErrorMsgs []string
  1415  		}{
  1416  			{
  1417  				name:             "all results with step limit: 100",
  1418  				query:            toParams(className, 0, 100, &filters.Cursor{After: "", Limit: 100}, nil, nil),
  1419  				expectedThingIDs: []strfmt.UUID{thingID1, thingID2, thingID3, thingID4, thingID5, thingID6, thingID7},
  1420  			},
  1421  			{
  1422  				name:             "all results with step limit: 1",
  1423  				query:            toParams(className, 0, 1, &filters.Cursor{After: "", Limit: 1}, nil, nil),
  1424  				expectedThingIDs: []strfmt.UUID{thingID1, thingID2, thingID3, thingID4, thingID5, thingID6, thingID7},
  1425  			},
  1426  			{
  1427  				name:             "all results with step limit: 1 after: thingID4",
  1428  				query:            toParams(className, 0, 1, &filters.Cursor{After: thingID4.String(), Limit: 1}, nil, nil),
  1429  				expectedThingIDs: []strfmt.UUID{thingID5, thingID6, thingID7},
  1430  			},
  1431  			{
  1432  				name:             "all results with step limit: 1 after: thingID7",
  1433  				query:            toParams(className, 0, 1, &filters.Cursor{After: thingID7.String(), Limit: 1}, nil, nil),
  1434  				expectedThingIDs: []strfmt.UUID{},
  1435  			},
  1436  			{
  1437  				name:             "all results with step limit: 3",
  1438  				query:            toParams(className, 0, 3, &filters.Cursor{After: "", Limit: 3}, nil, nil),
  1439  				expectedThingIDs: []strfmt.UUID{thingID1, thingID2, thingID3, thingID4, thingID5, thingID6, thingID7},
  1440  			},
  1441  			{
  1442  				name:             "all results with step limit: 7",
  1443  				query:            toParams(className, 0, 7, &filters.Cursor{After: "", Limit: 7}, nil, nil),
  1444  				expectedThingIDs: []strfmt.UUID{thingID1, thingID2, thingID3, thingID4, thingID5, thingID6, thingID7},
  1445  			},
  1446  			{
  1447  				name:               "error on empty class",
  1448  				query:              toParams("", 0, 7, &filters.Cursor{After: "", Limit: 7}, nil, nil),
  1449  				constainsErrorMsgs: []string{"class not found"},
  1450  			},
  1451  			{
  1452  				name: "error on sort parameter",
  1453  				query: toParams(className, 0, 7,
  1454  					&filters.Cursor{After: "", Limit: 7}, nil,
  1455  					[]filters.Sort{{Path: []string{"stringProp"}, Order: "asc"}},
  1456  				),
  1457  				cursor:             &filters.Cursor{After: "", Limit: 7},
  1458  				constainsErrorMsgs: []string{"sort cannot be set with after and limit parameters"},
  1459  			},
  1460  			{
  1461  				name: "error on offset parameter",
  1462  				query: toParams(className, 10, 7,
  1463  					&filters.Cursor{After: "", Limit: 7}, nil,
  1464  					nil,
  1465  				),
  1466  				cursor:             &filters.Cursor{After: "", Limit: 7},
  1467  				constainsErrorMsgs: []string{"offset cannot be set with after and limit parameters"},
  1468  			},
  1469  			{
  1470  				name: "error on offset and sort parameter",
  1471  				query: toParams(className, 10, 7,
  1472  					&filters.Cursor{After: "", Limit: 7}, nil,
  1473  					[]filters.Sort{{Path: []string{"stringProp"}, Order: "asc"}},
  1474  				),
  1475  				cursor:             &filters.Cursor{After: "", Limit: 7},
  1476  				constainsErrorMsgs: []string{"offset,sort cannot be set with after and limit parameters"},
  1477  			},
  1478  		}
  1479  		for _, tt := range tests {
  1480  			t.Run(tt.name, func(t *testing.T) {
  1481  				if len(tt.constainsErrorMsgs) > 0 {
  1482  					res, err := repo.Query(context.Background(), tt.query)
  1483  					require.NotNil(t, err)
  1484  					assert.Nil(t, res)
  1485  					for _, errorMsg := range tt.constainsErrorMsgs {
  1486  						assert.Contains(t, err.Error(), errorMsg)
  1487  					}
  1488  				} else {
  1489  					cursorSearch := func(t *testing.T, className string, cursor *filters.Cursor) []strfmt.UUID {
  1490  						res, err := repo.Query(context.Background(), toParams(className, 0, cursor.Limit, cursor, nil, nil))
  1491  						require.Nil(t, err)
  1492  						var ids []strfmt.UUID
  1493  						for i := range res {
  1494  							ids = append(ids, res[i].ID)
  1495  						}
  1496  						return ids
  1497  					}
  1498  
  1499  					var thingIds []strfmt.UUID
  1500  					cursor := tt.query.Cursor
  1501  					for {
  1502  						result := cursorSearch(t, tt.query.Class, cursor)
  1503  						thingIds = append(thingIds, result...)
  1504  						if len(result) == 0 {
  1505  							break
  1506  						}
  1507  						after := result[len(result)-1]
  1508  						cursor = &filters.Cursor{After: after.String(), Limit: cursor.Limit}
  1509  					}
  1510  
  1511  					require.Equal(t, len(tt.expectedThingIDs), len(thingIds))
  1512  					for i := range tt.expectedThingIDs {
  1513  						assert.Equal(t, tt.expectedThingIDs[i], thingIds[i])
  1514  					}
  1515  				}
  1516  			})
  1517  		}
  1518  		// clean up
  1519  		for _, td := range testData {
  1520  			err := repo.DeleteObject(context.Background(), td.className, td.id, nil, "")
  1521  			assert.Nil(t, err)
  1522  		}
  1523  	})
  1524  }
  1525  
  1526  func Test_ImportWithoutVector_UpdateWithVectorLater(t *testing.T) {
  1527  	r := getRandomSeed()
  1528  	total := 100
  1529  	individual := total / 4
  1530  	className := "DeferredVector"
  1531  	var data []*models.Object
  1532  	var class *models.Class
  1533  
  1534  	dirName := t.TempDir()
  1535  	logger, _ := test.NewNullLogger()
  1536  
  1537  	schemaGetter := &fakeSchemaGetter{
  1538  		schema:     schema.Schema{Objects: &models.Schema{Classes: nil}},
  1539  		shardState: singleShardState(),
  1540  	}
  1541  	repo, err := New(logger, Config{
  1542  		MemtablesFlushDirtyAfter:  60,
  1543  		RootPath:                  dirName,
  1544  		QueryMaximumResults:       10000,
  1545  		MaxImportGoroutinesFactor: 1,
  1546  	}, &fakeRemoteClient{}, &fakeNodeResolver{}, &fakeRemoteNodeClient{}, &fakeReplicationClient{}, nil)
  1547  	require.Nil(t, err)
  1548  	repo.SetSchemaGetter(schemaGetter)
  1549  	require.Nil(t, repo.WaitForStartup(testCtx()))
  1550  	defer repo.Shutdown(context.Background())
  1551  	migrator := NewMigrator(repo, logger)
  1552  
  1553  	t.Run("prepare data for test", func(t *testing.T) {
  1554  		data = make([]*models.Object, total)
  1555  		for i := range data {
  1556  			data[i] = &models.Object{
  1557  				ID:    strfmt.UUID(uuid.Must(uuid.NewRandom()).String()),
  1558  				Class: className,
  1559  				Properties: map[string]interface{}{
  1560  					"int_prop": int64(i),
  1561  				},
  1562  				Vector: nil,
  1563  			}
  1564  		}
  1565  	})
  1566  
  1567  	t.Run("create required schema", func(t *testing.T) {
  1568  		class = &models.Class{
  1569  			Class: className,
  1570  			Properties: []*models.Property{
  1571  				{
  1572  					DataType: []string{string(schema.DataTypeInt)},
  1573  					Name:     "int_prop",
  1574  				},
  1575  			},
  1576  			VectorIndexConfig:   enthnsw.NewDefaultUserConfig(),
  1577  			InvertedIndexConfig: invertedConfig(),
  1578  		}
  1579  		require.Nil(t,
  1580  			migrator.AddClass(context.Background(), class, schemaGetter.shardState))
  1581  	})
  1582  
  1583  	// update schema getter so it's in sync with class
  1584  	schemaGetter.schema = schema.Schema{
  1585  		Objects: &models.Schema{
  1586  			Classes: []*models.Class{class},
  1587  		},
  1588  	}
  1589  
  1590  	t.Run("import individual objects without vector", func(t *testing.T) {
  1591  		for i := 0; i < individual; i++ {
  1592  			err := repo.PutObject(context.Background(), data[i], nil, nil, nil) // nil vector !
  1593  			require.Nil(t, err)
  1594  		}
  1595  	})
  1596  
  1597  	t.Run("import batch objects without vector", func(t *testing.T) {
  1598  		batch := make(objects.BatchObjects, total-individual)
  1599  
  1600  		for i := range batch {
  1601  			batch[i] = objects.BatchObject{
  1602  				OriginalIndex: i,
  1603  				Err:           nil,
  1604  				Object:        data[i+individual],
  1605  				UUID:          data[i+individual].ID,
  1606  			}
  1607  		}
  1608  
  1609  		res, err := repo.BatchPutObjects(context.Background(), batch, nil)
  1610  		require.Nil(t, err)
  1611  
  1612  		for _, obj := range res {
  1613  			require.Nil(t, obj.Err)
  1614  		}
  1615  	})
  1616  
  1617  	t.Run("verify inverted index works correctly", func(t *testing.T) {
  1618  		res, err := repo.Search(context.Background(), dto.GetParams{
  1619  			Filters:   buildFilter("int_prop", total+1, lte, dtInt),
  1620  			ClassName: className,
  1621  			Pagination: &filters.Pagination{
  1622  				Offset: 0,
  1623  				Limit:  total,
  1624  			},
  1625  		})
  1626  		require.Nil(t, err)
  1627  		assert.Len(t, res, total)
  1628  	})
  1629  
  1630  	t.Run("perform unfiltered vector search and verify there are no matches", func(t *testing.T) {
  1631  		res, err := repo.VectorSearch(context.Background(), dto.GetParams{
  1632  			Filters:   nil,
  1633  			ClassName: className,
  1634  			Pagination: &filters.Pagination{
  1635  				Offset: 0,
  1636  				Limit:  total,
  1637  			},
  1638  			SearchVector: randomVector(r, 7),
  1639  		})
  1640  		require.Nil(t, err)
  1641  		assert.Len(t, res, 0) // we skipped the vector on half the elements, so we should now match half
  1642  	})
  1643  
  1644  	t.Run("update some of the objects to add vectors", func(t *testing.T) {
  1645  		for i := range data {
  1646  			if i%2 == 1 {
  1647  				continue
  1648  			}
  1649  
  1650  			data[i].Vector = randomVector(r, 7)
  1651  			err := repo.PutObject(context.Background(), data[i], data[i].Vector, nil, nil)
  1652  			require.Nil(t, err)
  1653  		}
  1654  	})
  1655  
  1656  	t.Run("perform unfiltered vector search and verify correct matches", func(t *testing.T) {
  1657  		res, err := repo.VectorSearch(context.Background(), dto.GetParams{
  1658  			Filters:   nil,
  1659  			ClassName: className,
  1660  			Pagination: &filters.Pagination{
  1661  				Offset: 0,
  1662  				Limit:  total,
  1663  			},
  1664  			SearchVector: randomVector(r, 7),
  1665  		})
  1666  		require.Nil(t, err)
  1667  		assert.Len(t, res, total/2) // we skipped the vector on half the elements, so we should now match half
  1668  	})
  1669  
  1670  	t.Run("perform filtered vector search and verify correct matches", func(t *testing.T) {
  1671  		res, err := repo.VectorSearch(context.Background(), dto.GetParams{
  1672  			Filters:   buildFilter("int_prop", 50, lt, dtInt),
  1673  			ClassName: className,
  1674  			Pagination: &filters.Pagination{
  1675  				Offset: 0,
  1676  				Limit:  total,
  1677  			},
  1678  			SearchVector: randomVector(r, 7),
  1679  		})
  1680  		require.Nil(t, err)
  1681  		// we skipped the vector on half the elements, and cut the list in half with
  1682  		// the filter, so we're only expected a quarter of the total size now
  1683  		assert.Len(t, res, total/4)
  1684  	})
  1685  }
  1686  
  1687  func TestVectorSearch_ByDistance(t *testing.T) {
  1688  	className := "SomeClass"
  1689  	var class *models.Class
  1690  
  1691  	dirName := t.TempDir()
  1692  	logger, _ := test.NewNullLogger()
  1693  
  1694  	schemaGetter := &fakeSchemaGetter{
  1695  		schema:     schema.Schema{Objects: &models.Schema{Classes: nil}},
  1696  		shardState: singleShardState(),
  1697  	}
  1698  	repo, err := New(logger, Config{
  1699  		MemtablesFlushDirtyAfter: 60,
  1700  		RootPath:                 dirName,
  1701  		// this is set really low to ensure that search
  1702  		// by distance is conducted, which executes
  1703  		// without regard to this value
  1704  		QueryMaximumResults:       1,
  1705  		MaxImportGoroutinesFactor: 1,
  1706  	}, &fakeRemoteClient{}, &fakeNodeResolver{}, &fakeRemoteNodeClient{}, &fakeReplicationClient{}, nil)
  1707  	require.Nil(t, err)
  1708  	repo.SetSchemaGetter(schemaGetter)
  1709  	require.Nil(t, repo.WaitForStartup(testCtx()))
  1710  	defer repo.Shutdown(context.Background())
  1711  	migrator := NewMigrator(repo, logger)
  1712  
  1713  	t.Run("create required schema", func(t *testing.T) {
  1714  		class = &models.Class{
  1715  			Class: className,
  1716  			Properties: []*models.Property{
  1717  				{
  1718  					DataType: []string{string(schema.DataTypeInt)},
  1719  					Name:     "int_prop",
  1720  				},
  1721  			},
  1722  			VectorIndexConfig:   enthnsw.NewDefaultUserConfig(),
  1723  			InvertedIndexConfig: invertedConfig(),
  1724  		}
  1725  		require.Nil(t,
  1726  			migrator.AddClass(context.Background(), class, schemaGetter.shardState))
  1727  	})
  1728  
  1729  	// update schema getter so it's in sync with class
  1730  	schemaGetter.schema = schema.Schema{
  1731  		Objects: &models.Schema{
  1732  			Classes: []*models.Class{class},
  1733  		},
  1734  	}
  1735  
  1736  	searchVector := []float32{-0.10190568, -0.06259751, 0.05616188, -0.19249836, 0.09714927, -0.1902525, -0.064424865, -0.0387358, 0.17581701, 0.4476738, 0.29261824, 0.12026761, -0.19975126, 0.023600178, 0.17348698, 0.12701738, -0.36018127, -0.12051587, -0.17620522, 0.060741074, -0.064512916, 0.18640806, -0.1529852, 0.08211839, -0.02558465, -0.11369845, 0.0924098, -0.10544433, -0.14728987, -0.041860342, -0.08533595, 0.25886244, 0.2963937, 0.26010615, 0.2111097, 0.029396622, 0.01429563, 0.06410264, -0.119665794, 0.33583277, -0.05802661, 0.023306102, 0.14435922, -0.003951336, -0.13870825, 0.07140894, 0.10469943, -0.059021875, -0.065911904, 0.024216041, -0.26282874, 0.04896568, -0.08291928, -0.12793182, -0.077824734, 0.08843151, 0.31247458, -0.066301286, 0.006904921, -0.08277095, 0.13936226, -0.64392364, -0.19566211, 0.047227614, 0.086121306, -0.20725192, -0.096485816, -0.16436341, -0.06559169, -0.019639932, -0.012729637, 0.08901619, 0.0015896161, -0.24789932, 0.35496348, -0.16272856, -0.01648429, 0.11247674, 0.08099968, 0.13339259, 0.055829972, -0.34662855, 0.068509, 0.13880715, 0.3201848, -0.055557363, 0.22142135, -0.12867308, 0.0037871755, 0.24888979, -0.007443307, 0.08906625, -0.02022331, 0.11510742, -0.2385861, 0.16177008, -0.16214795, -0.28715602, 0.016784908, 0.19386634, -0.07731616, -0.100485384, 0.4100712, 0.061834496, -0.2325293, -0.026056025, -0.11632323, -0.17040555, -0.081960455, -0.0061040106, -0.05949373, 0.044952348, -0.079565264, 0.024430245, -0.09375341, -0.30249637, 0.115205586, -0.13083287, -0.04264671, -0.089810364, 0.16227561, 0.07318055, -0.10496504, 0.00063501706, -0.04936106, -0.0022282854, 1.0893154, 0.1698662, -0.019563455, -0.011128426, 0.04477475, -0.15656771, -0.056911886, -0.5759019, -0.1881429, 0.17088258, 0.24124439, 0.111288875, -0.0015475494, -0.021278847, -0.08362156, 0.09997524, -0.094385885, -0.1674031, 0.061180864, 0.28517494, -0.016217072, 0.025866214, -0.22854298, -0.17924422, -0.037767246, 0.12252907, -0.31698978, -0.038031228, 0.055408552, 0.1743545, -0.040576655, 0.1293942, -0.56650764, -0.10306195, -0.19548112, -0.245544, -0.018241389, -0.039024632, -0.31659162, 0.1565075, 0.08412337, 0.13177724, -0.13766576, -0.15355161, -0.16960397, -0.012436442, 0.04828157, 0.12566057, -0.35308784, -0.37520224, -0.1265899, -0.13991497, 0.14402144, 0.117542416, -0.20750546, -0.5849919, -0.010469457, -0.19677396, 0.011365964, 0.00666846, -0.083470255, 0.24928358, 0.07026387, 0.19082819, 0.24557637, 0.014292963, 0.14846677, 0.031625308, -0.20398879, 0.19507346, -0.18119761, -0.045725327, -0.042455163, -0.099733196, -0.33636123, -0.28447086, 0.30274838, -0.01603988, -0.0529655, 0.15784146, 0.08746072, -0.1703993, 0.2414512, 0.060322937, -0.00812057, 0.031162385, -0.1764905, 0.22107981, -0.016657066, 0.31948856, 0.07282925, -0.036991462, 0.01266936, -0.009106514, -0.038732465, 0.20973183, 0.033236098, -0.10673938, -0.06880061, 0.115524575, -0.39688373, 0.08749971, -0.21816005, -0.22100002, -0.3716853, -0.14720486, 0.24316181, 0.29673144, 0.020808747, 0.07658521, 0.16310681, 0.38785335, 0.0992224, 0.14177811, 0.025954131, -0.08690783, 0.19653428, 0.09584941, 0.040072605, -0.00038361162, -0.094546966, 0.1910902, 0.13217318, 0.060072783, -0.0655816, 0.2777626, 0.1799169, 0.20187178, -0.0996889, -0.01932122, -0.13133621, 0.057482753, -0.36892185, -0.032093313, 0.14607865, 0.12033318, -0.041683596, -0.2048406, -0.041777443, -0.14975598, -0.2526341, 0.12659752, 0.010567178, -0.297333, -0.27522174, 0.06923473, 0.043150593, -0.017045585, -0.2400216, 0.11413547, -0.40081662, -0.0018820907, 0.13800722, 0.085972115, -0.01519989, -0.10491216, 0.09170084, 0.063085504, 0.046743374, -0.014466267, 0.09880224, 0.027706565, 0.09951337, 0.17317492, -0.025654864, 0.14658073, 0.042377427, -0.08402882, -0.12423425, 0.32714987, -0.1527207, 0.106094465, 0.017378228, -0.06302387}
  1737  	searchObject := strfmt.UUID("fe687bf4-f10f-4c23-948d-0746ea2927b3")
  1738  
  1739  	tests := map[strfmt.UUID]struct {
  1740  		inputVec []float32
  1741  		expected bool
  1742  	}{
  1743  		strfmt.UUID("88460290-03b2-44a3-9adb-9fa3ae11d9e6"): {
  1744  			inputVec: []float32{-0.11015724, -0.05380307, 0.027512914, -0.16925375, 0.08306809, -0.19312492, -0.08910436, -0.011051652, 0.17981204, 0.40469593, 0.28226805, 0.09381516, -0.18380599, 0.03102771, 0.1645333, 0.1530153, -0.3187937, -0.10800173, -0.18466279, 0.0004336393, -0.0495677, 0.19905856, -0.11614494, 0.08834681, -0.011200292, -0.11969374, 0.12497086, -0.12427251, -0.13395442, -0.0060353535, -0.07504816, 0.23205791, 0.2982508, 0.2517544, 0.176147, -0.036871903, 0.017852835, 0.040007118, -0.118621, 0.3648693, -0.058933854, 0.04004229, 0.11871147, -0.019860389, -0.12701912, 0.106662825, 0.086498804, -0.04303973, -0.0742352, 0.018250324, -0.26544014, 0.029228423, -0.087171465, -0.1282789, -0.06403083, 0.09680911, 0.31433868, -0.081510685, -0.011283603, -0.041624587, 0.16530018, -0.6714878, -0.2436993, 0.03173918, 0.106117725, -0.20803581, -0.10429562, -0.16975354, -0.078582145, -0.0065962705, -0.06840946, 0.094937086, -0.020617036, -0.23795949, 0.34785536, -0.19834635, -0.015064479, 0.11930141, 0.090962164, 0.120560184, 0.054095767, -0.38602966, 0.057141174, 0.12039684, 0.32000408, -0.05146908, 0.20762976, -0.09342379, 0.037577383, 0.23894139, -0.0075003104, 0.104791366, -0.015841056, 0.102840215, -0.20813248, 0.1855997, -0.12594056, -0.27132365, -0.0055563124, 0.21954241, -0.10798524, -0.111896284, 0.44049335, 0.049884494, -0.22339955, -0.005374135, -0.120713554, -0.22275059, -0.09146004, 0.017188415, -0.106493734, 0.045247544, -0.07725446, 0.056848228, -0.10294392, -0.2896642, 0.112891, -0.13773362, -0.089911595, -0.13500965, 0.14051703, 0.040092673, -0.13896292, 0.04580957, -0.014300959, 0.03737215, 1.0661443, 0.19767477, -0.07703914, -0.012910904, -0.0037716173, -0.14437087, -0.06938004, -0.5348036, -0.16047458, 0.19416414, 0.21938956, 0.092242256, -0.012630808, -0.021863988, -0.051702406, 0.08780951, -0.0815602, -0.15332024, 0.077632725, 0.25709584, -0.025725808, 0.042116437, -0.22687604, -0.11791685, -0.028626656, 0.16734225, -0.3017483, -0.03236202, 0.02888077, 0.18193199, -0.009032297, 0.14454253, -0.511494, -0.12119192, -0.20757924, -0.2561716, -0.03904554, -0.07348411, -0.28547177, 0.15967208, 0.079396725, 0.14358875, -0.12829632, -0.18175666, -0.15540425, -0.020419862, 0.019070208, 0.12168836, -0.3428434, -0.357543, -0.11218741, -0.12834033, 0.13564876, 0.12768728, -0.1817461, -0.61235875, -0.029409664, -0.19765733, 0.03872163, 0.0074950717, -0.10025679, 0.2872255, 0.033995092, 0.12945211, 0.21831632, 0.04666009, 0.14233032, 0.016767867, -0.2039244, 0.2000191, -0.13099428, -0.020210614, -0.06286195, -0.0948797, -0.34830436, -0.21595824, 0.32722405, -0.024735296, -0.07859145, 0.16975155, 0.08186461, -0.19249061, 0.23405583, 0.04837592, 0.021467948, -0.022215014, -0.14892808, 0.23908867, -0.050126728, 0.2867907, 0.07740656, -0.01714987, -0.0046314416, -0.0048108613, -0.007407311, 0.1807499, 0.049772616, -0.14680666, -0.07335314, 0.09023705, -0.40600133, 0.05522128, -0.20085222, -0.20410904, -0.34319055, -0.10792269, 0.2297779, 0.30397663, 0.05230268, 0.06408224, 0.13797496, 0.3691112, 0.083033495, 0.13695791, -0.015612457, -0.06413475, 0.18117142, 0.12928344, 0.049171276, 0.016104931, -0.102417335, 0.19589683, 0.14380622, 0.0748065, -0.005402455, 0.27243868, 0.14925551, 0.19564849, -0.10738364, -0.054175537, -0.10068278, 0.06004795, -0.38755924, -0.01654251, 0.1394104, 0.0968949, 0.004271706, -0.17105898, -0.050423585, -0.15311627, -0.24458972, 0.12665795, -0.022814916, -0.23887472, -0.289588, 0.05521137, 0.041259795, -0.021133862, -0.23674431, 0.08424598, -0.37863016, 0.017239956, 0.13776784, 0.060790475, 0.057887543, -0.08784489, 0.08803934, 0.027996546, 0.085972995, -0.014455558, 0.11668073, 0.03812387, 0.088413864, 0.22228678, -0.015599858, 0.11000236, 0.035271563, -0.08088438, -0.13092226, 0.29378533, -0.12311522, 0.09377676, 0.02948718, -0.09136077},
  1745  			expected: true,
  1746  		},
  1747  		strfmt.UUID("c99bc97d-7035-4311-94f3-947dc6471f51"): {
  1748  			inputVec: []float32{-0.07545987, -0.046643265, 0.044445477, -0.18531442, 0.07922216, -0.19388637, -0.069393866, -0.036144026, 0.1713317, 0.41803706, 0.23576374, 0.073170714, -0.14085358, 0.012535708, 0.17439325, 0.10057567, -0.33506152, -0.06800867, -0.18882714, 0.002687021, -0.03276807, 0.17267752, -0.13951558, 0.071382746, 0.020254405, -0.10178502, 0.13977699, -0.107296936, -0.113307, -0.002506761, -0.092065684, 0.21008658, 0.31157792, 0.19640765, 0.15769793, -0.0050196033, 0.0022481605, 0.015436289, -0.11822955, 0.31494477, -0.07425527, 0.051401984, 0.11648046, -0.00016831602, -0.12758006, 0.06814693, 0.06108981, -0.025454175, -0.018695071, 0.041827776, -0.23480764, 0.06652185, -0.078328855, -0.121668324, -0.04341973, 0.114403985, 0.32614416, -0.07992741, -0.019665314, -0.017408244, 0.12615794, -0.6350545, -0.17056493, 0.07171332, 0.047071394, -0.18428493, -0.09011123, -0.15995751, -0.03345579, -0.014678, -0.038699757, 0.044125225, 0.0042562615, -0.29445595, 0.30460796, -0.13630153, 0.00014055961, 0.08996278, 0.08948901, 0.12164838, 0.079090506, -0.36153567, 0.02817218, 0.11914518, 0.29805067, -0.07431765, 0.16793592, -0.099549234, 0.045226075, 0.22235383, -0.045654725, 0.09233901, -0.004902314, 0.08621588, -0.19723448, 0.19557382, -0.13199815, -0.22924824, -0.015981175, 0.19762704, -0.08940076, -0.084909916, 0.43372774, 0.026998578, -0.20827708, 0.037450224, -0.078997016, -0.18065391, -0.071308024, 0.00870316, -0.114981964, 0.017085023, -0.07696264, 0.009330409, -0.097458, -0.25530958, 0.118254915, -0.12516825, -0.008301536, -0.20432962, 0.15235707, 0.012840041, -0.18034773, 0.039270073, -0.03131139, 0.013706253, 0.98688674, 0.18840753, -0.055119563, 0.00836046, 0.019445436, -0.10701598, -0.024610046, -0.50088006, -0.15488546, 0.14209819, 0.1798376, 0.08615982, -0.0119235935, -0.0060070297, -0.08406098, 0.10096481, -0.09077014, -0.15957798, 0.10556352, 0.2100476, -0.036947068, 0.05316554, -0.20480183, -0.14873864, -0.0069070593, 0.16027303, -0.288908, -0.04487129, 0.0705415, 0.11973847, -0.0017247469, 0.14092937, -0.5262047, -0.094283305, -0.19120996, -0.2816572, -0.010916339, -0.07984056, -0.28659204, 0.13706332, 0.07364347, 0.12300072, -0.17554194, -0.16378267, -0.15244205, 0.00075927645, 0.017289847, 0.12072629, -0.33452734, -0.33727616, -0.12780978, -0.09350711, 0.105674624, 0.10770573, -0.17278843, -0.5760599, -0.013741414, -0.15395893, 0.009837732, 0.015417911, -0.11384676, 0.24567491, 0.04905973, 0.10762609, 0.2131752, 0.019281652, 0.11665857, 0.022718405, -0.2234067, 0.23241606, -0.12194457, -0.049972955, -0.012225418, -0.14856412, -0.386102, -0.23018965, 0.28920102, -0.023396742, -0.114672944, 0.12130062, 0.05654803, -0.16194181, 0.24095012, 0.03644393, 0.028024165, -0.008832254, -0.16496961, 0.19496499, -0.035887964, 0.25981775, 0.0970074, 0.0013458093, -0.009548204, 0.040741496, -0.019192837, 0.20718361, -0.004034228, -0.1343262, -0.06990001, 0.09888768, -0.35942966, 0.043895893, -0.19182123, -0.17963983, -0.3222771, -0.10223457, 0.23866613, 0.25855777, 0.04051543, 0.08756274, 0.15683484, 0.37856522, 0.04853359, 0.10198129, -0.0061066896, -0.049892712, 0.17087941, 0.14563805, 0.06984385, 0.0071270005, -0.11838641, 0.18716812, 0.14013803, 0.05242403, 0.034357738, 0.3083466, 0.14742611, 0.17841975, -0.124118194, -0.014102871, -0.052544866, 0.037493005, -0.33485797, -0.013164912, 0.1066288, 0.11141791, -0.04029921, -0.16429856, -0.032241724, -0.15965424, -0.2430594, 0.13654563, 0.009401224, -0.2045843, -0.28467956, 0.07325551, 0.027996557, -0.033877768, -0.24350801, 0.08329816, -0.35555813, 0.006908567, 0.07227365, 0.03188268, 0.032559503, -0.09180395, 0.05601515, 0.0047281734, 0.06878795, -0.018943194, 0.08251342, 0.042039152, 0.12902294, 0.20526606, -0.014881293, 0.11723917, 0.0115632, -0.09016013, -0.12117223, 0.31020245, -0.111444525, 0.077845715, 0.00046715315, -0.104099475},
  1749  			expected: true,
  1750  		},
  1751  		strfmt.UUID("fe687bf4-f10f-4c23-948d-0746ea2927b3"): {
  1752  			inputVec: []float32{-0.20739016, -0.19551805, 0.06645163, 0.008650202, 0.03700748, -0.04132599, -0.029881354, 0.04684896, 0.096614264, 0.42888844, 0.10003969, 0.026234219, -0.051639702, -0.118660435, 0.14473079, 0.2911885, -0.1180539, -0.16804434, -0.48081538, 0.021702053, 0.12612472, 0.15442817, -0.05836532, 0.074295096, -0.28077397, -0.24297802, 0.047836643, -0.36753318, -0.30482984, 0.09265357, 0.25571078, 0.41130066, 0.46177864, 0.34033778, 0.20721313, -0.37726295, 0.07721501, 0.08009689, 0.00027321206, 0.5168123, -0.15305339, 0.0937765, 0.096195236, -0.21120761, 0.014014921, 0.3133104, 0.20773117, 0.08483507, -0.27784437, -0.17281856, -0.6050923, -0.22439326, -0.16914369, -0.3149047, -0.13828672, 0.16334395, -0.0018224253, -0.024342008, 0.3511251, 0.04979151, 0.34223744, -0.6965703, -0.36211932, -0.27092442, 0.34418032, -0.09667905, 0.13344757, -0.15622364, -0.24129291, 0.06958589, -0.2681816, -0.09497071, -0.08923615, -0.06642436, 0.48688608, -0.33535984, 0.014242731, 0.079838976, 0.32949054, 0.09051045, -0.2653392, -0.47393548, 0.07508276, 0.0062832804, 0.724184, -0.18929236, 0.11718613, 0.049603477, 0.08766128, 0.31040704, 0.04038693, -0.0017023507, -0.18986607, 0.056264438, -0.20978904, -0.107441366, -0.30505633, -0.45781082, -0.11571784, 0.32160303, -0.1347523, -0.08090298, 0.51651996, -0.023250414, -0.18725531, -0.14222279, 0.009277832, -0.49789724, -0.25156206, 0.0042495225, 0.0038805408, -0.031416763, 0.10277136, 0.14383446, -0.23241928, -0.42357358, 0.027033398, -0.2262604, -0.2685295, -0.14510548, 0.18256307, 0.063297585, 0.027636252, 0.081166506, 0.06726344, 0.1677495, 1.5217289, 0.33152232, -0.2209926, 0.051426213, 0.15640806, -0.30210486, -0.32857975, -0.4170022, -0.028293105, 0.28772062, 0.50510746, 0.09162247, -0.12383193, -0.25066972, -0.1441897, 0.107192926, -0.07404076, 0.0042472635, 0.11014519, 0.22332853, 0.09434378, -0.3278343, 0.041899726, 0.06838457, 0.10983681, 0.11864574, -0.25336757, -0.047530346, -0.027303243, 0.37403497, 0.13420461, 0.14946426, -0.41996637, -0.037703935, -0.47961184, -0.29839846, -0.103934005, -0.12058302, -0.12806267, 0.22814582, 0.3904893, -0.16044962, -0.17479864, -0.33139735, -0.29185295, 0.0653074, 0.042426735, 0.06092335, -0.18776153, -0.52555144, -0.15889317, -0.20644087, 0.2293067, 0.26668283, -0.15607063, -0.696593, -0.08224992, -0.4283747, 0.26883888, -0.031052848, -0.1311875, 0.26636878, 0.16457985, 0.15660451, 0.10629464, 0.17345549, 0.23963387, 0.22997221, -0.111713186, -0.08499592, -0.2274625, 0.19285984, -0.08285016, -0.02692149, -0.3426618, -0.13361897, 0.2870389, -0.12032792, -0.22944619, 0.25588584, 0.24607788, -0.2762531, 0.30983892, 0.011088746, -0.15739818, 0.053215, -0.21660997, 0.033805694, -0.17886437, 0.2979239, 0.2163545, -0.08381542, 0.19666128, -0.28977823, -0.20994817, -0.012160099, 0.057499636, -0.12549455, 0.19303595, -0.14420606, -0.51937664, 0.23400985, -0.27893808, -0.2660984, -0.27870297, -0.32149136, 0.19958079, 0.34468395, 0.18947665, -0.16529581, 0.101419374, 0.30195153, 0.09030288, 0.12496541, 0.02999903, -0.016697621, 0.15314853, 0.27848768, 0.24102053, 0.06933273, 0.08923653, 0.10477832, 0.4389032, 0.15679164, -0.11119637, 0.134823, 0.30230528, 0.20818473, -0.005579584, -0.3474488, -0.44394243, 0.22270252, -0.3668763, 0.07474772, 0.011691334, 0.088187896, 0.23832949, -0.07960201, 0.066471875, 0.034641538, -0.39984587, 0.0032980456, -0.28492525, -0.46358657, -0.2148288, -0.107226945, 0.02734428, -0.24686679, -0.123900555, 0.18174778, -0.31248868, 0.13808723, 0.31549984, 0.21521719, 0.13966985, -0.27272752, 0.12091104, 0.14257833, 0.23175247, 0.15639938, 0.40828535, 0.31916845, 0.023645567, 0.20658277, -0.20365283, 0.113746524, 0.13173752, -0.050343305, -0.31581175, 0.09704622, -0.014172505, 0.16924341, 0.30327854, -0.17770194},
  1753  			expected: false,
  1754  		},
  1755  		strfmt.UUID("e7bf6c45-de72-493a-b273-5ef198974d61"): {
  1756  			inputVec: []float32{0.089313604, -0.050221898, 0.18352903, 0.16257699, 0.14520381, 0.17993976, 0.14594483, 0.019256027, -0.15505213, 0.23606326, -0.14456263, 0.2679586, -0.112208664, 0.12997514, 0.0051072896, 0.28151348, -0.10495799, 0.026782967, -0.38603118, 0.16190273, -0.0428943, -0.16265322, -0.17910561, 0.0746288, -0.3117934, -0.15871756, -0.11377734, -0.06822346, -0.13829489, 0.13019162, 0.30741218, 0.16194165, 0.013218932, 0.054517113, 0.12490437, -0.07709048, 0.02556826, -0.21159878, -0.09082174, 0.24629511, 0.05013666, 0.25168124, -0.14423938, -0.0937688, -0.07811525, -0.049346007, 0.3592527, 0.30411252, -0.1168557, 0.18870471, 0.06614835, -0.20099068, -0.084436245, 0.073036775, -0.03448665, -0.11147946, -0.10862863, -0.012393957, 0.18990599, 0.060957544, 0.19518377, -0.027541652, -0.26750082, -0.12780671, 0.09570065, -0.03541132, 0.094820626, -0.13539355, -0.09468136, 0.18476579, -0.20970085, -0.20989786, -0.12084438, -0.04517079, -0.008074663, 0.02824076, 0.114496395, -0.20462593, 0.103516705, -0.101554185, -0.1374868, -0.24884155, -0.08101618, -0.016105993, 0.22608215, -0.007247754, -0.17246912, 0.058247145, -0.041018173, 0.19471274, -0.022576109, 0.032828204, -0.079321206, -0.09259324, 0.041115705, -0.25280195, -0.28517374, -0.19496292, 0.18070905, 0.06384923, -0.004056949, 0.1536253, 0.17861623, -0.033833142, 0.12039968, 0.04458716, 0.08793809, -0.15683243, -0.1087904, 0.1741014, 0.007256374, -0.20265253, 0.034111258, 0.03311363, -0.09449356, -0.13161612, -0.026084669, 0.07609202, 0.03452338, 0.08840356, -0.044566724, 0.1507175, 0.089273594, 0.18872644, 0.18333815, -0.023196407, 0.63831943, 0.20309874, 0.10217627, 0.11445079, 0.18965706, -0.16809432, -0.343172, -0.06439529, 0.08362327, 0.32746288, 0.38483366, 0.020372175, -0.25239283, 0.019468365, -0.016367752, 0.016749177, 0.024621855, 0.030529505, 0.20601188, -0.100692995, -0.16414656, -0.23193358, 0.26616478, 0.06166736, 0.14341855, 0.1294041, 0.045133967, 0.0014262896, -0.0194398, 0.040737696, 0.10099013, -0.10838136, -0.28768313, -0.073719576, -0.15836753, -0.10482511, -0.1349642, -0.107005455, 0.01957546, 0.13799994, 0.056444198, -0.38841644, -0.07585945, -0.018703599, -0.19934878, 0.15176265, 0.04133126, 0.063531734, 0.09720055, -0.29999572, 0.04765686, -0.23604262, 0.081500284, 0.056092553, -0.13664724, -0.37729686, 0.031137427, -0.052083906, 0.117984496, -0.14562207, -0.029609507, 0.13725121, 0.090367764, 0.12787215, 0.11026589, 0.25123242, 0.12911159, 0.055398554, 0.0032232201, 0.026706887, 0.14584258, 0.019900957, -0.12197998, -0.087177716, -0.24649806, -0.17869286, 0.07139921, -0.09633085, -0.16027117, 0.23617831, 0.05429949, -0.061085824, 0.040451035, 0.052443117, -0.14255014, 0.15598148, -0.2336374, 0.08394173, -0.34318882, 0.3419207, 0.18282516, -0.03709172, 0.10525048, -0.1871602, -0.22663523, 0.01635051, 0.16996534, -0.18056048, -0.169894, -0.18467705, -0.3641231, 0.060861763, -0.080082566, -0.08888943, 0.11629789, -0.00973362, 0.07452957, 0.25680214, 0.042024083, -0.024963235, 0.1743134, 0.10921186, 0.25191578, 0.028438354, 0.004781374, -0.08364819, 0.051807538, 0.1165724, 0.29184434, -0.21512283, 0.12515399, -0.08803969, 0.41930157, -0.10181762, 0.038189832, 0.085555896, -0.026453126, 0.04717047, 0.12667313, 0.023158737, -0.45877644, 0.18732828, 0.062374037, -0.21956007, -0.04449947, 0.19028638, 0.1359094, 0.26384917, 0.077602044, 0.35136092, 0.069637895, 0.048263475, -0.02498448, -0.09221205, -0.012142404, -0.124592446, 0.14599627, -0.050875153, -0.25454503, -0.069588415, -0.29793787, -0.13407284, 0.25388947, 0.35565627, -0.034204755, 0.0024766966, 0.086427726, -0.054318108, 0.063218184, -0.037823644, 0.108287826, 0.14440496, 0.025134278, 0.14978257, -0.03355889, 0.02980915, -0.13764386, 0.4167542, -0.03938922, 0.026970355, 0.24595529, 0.111741625, -0.074567944, -0.057232533},
  1757  			expected: false,
  1758  		},
  1759  		strfmt.UUID("0999d109-1d5f-465a-bd8b-e3fbd46f10aa"): {
  1760  			inputVec: []float32{-0.10486144, -0.07437922, 0.069469325, -0.1438278, 0.07740161, -0.18606456, -0.09991434, -0.020051572, 0.19863395, 0.4347328, 0.297606, 0.07853262, -0.16025662, 0.023596637, 0.16935731, 0.17052403, -0.29870638, -0.10309007, -0.20055692, 0.0027809117, -0.03928043, 0.21178603, -0.13793766, 0.08118157, 0.006693433, -0.13829204, 0.14778963, -0.13180175, -0.21128704, -0.0026104634, -0.076393716, 0.22200249, 0.32417125, 0.26045212, 0.1783609, -0.114116184, 0.0100981165, 0.07233143, -0.15913877, 0.4238603, -0.036907215, 0.0595873, 0.0807002, -0.07637312, -0.12889846, 0.111177936, 0.091114685, -0.018454906, -0.12132672, 0.056664582, -0.30461523, 0.020763714, -0.10992191, -0.14430659, -0.092879646, 0.13615008, 0.33039626, -0.115675874, 0.03607886, -0.027918883, 0.19531779, -0.7211654, -0.23073879, 0.011791817, 0.1315166, -0.22779183, -0.13773227, -0.1814997, -0.09008116, 0.021698939, -0.102921166, 0.090760864, 0.011856942, -0.25561005, 0.40769714, -0.21286584, -0.018059848, 0.13812906, 0.079457305, 0.12631191, 0.0024881593, -0.4282836, 0.0619608, 0.12207897, 0.39083096, -0.009502015, 0.19990632, -0.06503092, 0.0635979, 0.27579078, -0.020699967, 0.068474516, 0.0043831975, 0.10303624, -0.1885405, 0.22989234, -0.15952443, -0.29842895, 0.006752088, 0.22831629, -0.13150804, -0.13695218, 0.5357904, 0.050116863, -0.24064547, -0.01375713, -0.096647836, -0.24984525, -0.10429946, 0.002098812, -0.08113263, 0.05237009, -0.10246039, 0.05234802, -0.13899775, -0.3439524, 0.12522809, -0.18406768, -0.09022853, -0.19954625, 0.15810682, 0.039185096, -0.13576287, 0.045047805, 0.0035671506, 0.055920787, 1.1730403, 0.24019612, -0.13423051, -0.008052084, -0.00431602, -0.17079304, -0.09064658, -0.58728856, -0.1365065, 0.22919424, 0.22795208, 0.13396585, 0.018962797, -0.0075796233, -0.072394304, 0.10908417, -0.10881145, -0.16565171, 0.10378018, 0.27296618, -0.059810717, 0.03355443, -0.22429268, -0.12499127, -0.0441017, 0.20800696, -0.29992488, -0.003536096, 0.0026575085, 0.2427503, -0.007395092, 0.13233404, -0.5494433, -0.13144702, -0.2899963, -0.27367246, -0.05257514, -0.0939783, -0.267614, 0.16651331, 0.13891254, 0.08047202, -0.14046521, -0.19062972, -0.1433134, 0.0067776316, 0.00207368, 0.12986982, -0.35847133, -0.41852546, -0.15541135, -0.09865207, 0.14805861, 0.17072491, -0.22655731, -0.6473966, -0.007884447, -0.2060257, 0.035390265, 0.02781265, -0.09760371, 0.30535778, 0.047540557, 0.14565119, 0.21733035, 0.06558403, 0.13184759, 0.044231005, -0.22218557, 0.1897204, -0.1596938, 0.017510587, -0.030249557, -0.082377456, -0.39669412, -0.18365891, 0.34806964, -0.024830062, -0.06955674, 0.21521395, 0.1201222, -0.21855503, 0.23522708, 0.038058903, -0.019610198, -0.025448406, -0.18122384, 0.26068974, -0.055872105, 0.29595166, 0.11005987, -0.00841942, 0.006325112, -0.0013332894, -0.025598384, 0.17320716, 0.03480282, -0.1504056, -0.07133905, 0.08367911, -0.41866872, 0.062191408, -0.14972427, -0.18488628, -0.37027854, -0.14803104, 0.23587811, 0.33285886, 0.059688937, 0.030515533, 0.16795416, 0.3813925, 0.0755207, 0.15504116, -0.003507182, -0.08249321, 0.24292688, 0.13771294, 0.08057683, 0.016365156, -0.12878628, 0.1833687, 0.17496476, 0.050333332, 0.008188007, 0.32129762, 0.15476923, 0.2052587, -0.060781036, -0.1502798, -0.10187848, 0.11062117, -0.41137248, 0.016532877, 0.107270226, 0.08759128, 0.011842419, -0.17039144, -0.0139911, -0.13244899, -0.23845059, 0.075682834, -0.052250806, -0.30011725, -0.28581655, -0.00055503653, 0.022204043, -0.08598292, -0.24763824, 0.08245162, -0.39607832, 0.008443992, 0.16124122, 0.08812278, 0.0335653, -0.09692297, 0.07613783, 0.033542078, 0.11447116, -0.0069911424, 0.09004892, 0.09898015, 0.14595516, 0.24977732, -0.0018444546, 0.06290809, 0.013354713, -0.10336537, -0.1028908, 0.31109008, -0.110210516, 0.07165067, 0.050161615, -0.11413514},
  1761  			expected: true,
  1762  		},
  1763  	}
  1764  
  1765  	t.Run("insert test objects", func(t *testing.T) {
  1766  		for id, props := range tests {
  1767  			err := repo.PutObject(context.Background(), &models.Object{Class: className, ID: id}, props.inputVec, nil, nil)
  1768  			require.Nil(t, err)
  1769  		}
  1770  	})
  1771  
  1772  	t.Run("perform nearVector search by distance", func(t *testing.T) {
  1773  		results, err := repo.VectorSearch(context.Background(), dto.GetParams{
  1774  			ClassName:  className,
  1775  			Pagination: &filters.Pagination{Limit: filters.LimitFlagSearchByDist},
  1776  			NearVector: &searchparams.NearVector{
  1777  				Distance: 0.1,
  1778  			},
  1779  			SearchVector:         searchVector,
  1780  			AdditionalProperties: additional.Properties{Distance: true},
  1781  		})
  1782  		require.Nil(t, err)
  1783  		require.NotEmpty(t, results)
  1784  		// ensure that we receive more results than
  1785  		// the `QueryMaximumResults`, as this should
  1786  		// only apply to limited vector searches
  1787  		require.Greater(t, len(results), 1)
  1788  
  1789  		for _, res := range results {
  1790  			if props, ok := tests[res.ID]; !ok {
  1791  				t.Fatalf("received unexpected result: %+v", res)
  1792  			} else {
  1793  				assert.True(t, props.expected, "result id was not intended to meet threshold %s", res.ID)
  1794  			}
  1795  		}
  1796  	})
  1797  
  1798  	t.Run("perform nearObject search by distance", func(t *testing.T) {
  1799  		results, err := repo.VectorSearch(context.Background(), dto.GetParams{
  1800  			ClassName:  className,
  1801  			Pagination: &filters.Pagination{Limit: filters.LimitFlagSearchByDist},
  1802  			NearObject: &searchparams.NearObject{
  1803  				Distance: 0.1,
  1804  				ID:       searchObject.String(),
  1805  			},
  1806  			SearchVector:         searchVector,
  1807  			AdditionalProperties: additional.Properties{Distance: true},
  1808  		})
  1809  		require.Nil(t, err)
  1810  		require.NotEmpty(t, results)
  1811  		// ensure that we receive more results than
  1812  		// the `QueryMaximumResults`, as this should
  1813  		// only apply to limited vector searches
  1814  		require.Greater(t, len(results), 1)
  1815  
  1816  		for _, res := range results {
  1817  			if props, ok := tests[res.ID]; !ok {
  1818  				t.Fatalf("received unexpected result: %+v", res)
  1819  			} else {
  1820  				assert.True(t, props.expected, "result id was not intended to meet threshold %s", res.ID)
  1821  			}
  1822  		}
  1823  	})
  1824  }
  1825  
  1826  func TestVectorSearch_ByCertainty(t *testing.T) {
  1827  	className := "SomeClass"
  1828  	var class *models.Class
  1829  
  1830  	dirName := t.TempDir()
  1831  	logger, _ := test.NewNullLogger()
  1832  
  1833  	schemaGetter := &fakeSchemaGetter{
  1834  		schema:     schema.Schema{Objects: &models.Schema{Classes: nil}},
  1835  		shardState: singleShardState(),
  1836  	}
  1837  	repo, err := New(logger, Config{
  1838  		MemtablesFlushDirtyAfter: 60,
  1839  		RootPath:                 dirName,
  1840  		// this is set really low to ensure that search
  1841  		// by distance is conducted, which executes
  1842  		// without regard to this value
  1843  		QueryMaximumResults:       1,
  1844  		MaxImportGoroutinesFactor: 1,
  1845  	}, &fakeRemoteClient{}, &fakeNodeResolver{}, &fakeRemoteNodeClient{}, &fakeReplicationClient{}, nil)
  1846  	require.Nil(t, err)
  1847  	repo.SetSchemaGetter(schemaGetter)
  1848  	require.Nil(t, repo.WaitForStartup(testCtx()))
  1849  	defer repo.Shutdown(context.Background())
  1850  	migrator := NewMigrator(repo, logger)
  1851  
  1852  	t.Run("create required schema", func(t *testing.T) {
  1853  		class = &models.Class{
  1854  			Class: className,
  1855  			Properties: []*models.Property{
  1856  				{
  1857  					DataType: []string{string(schema.DataTypeInt)},
  1858  					Name:     "int_prop",
  1859  				},
  1860  			},
  1861  			VectorIndexConfig:   enthnsw.NewDefaultUserConfig(),
  1862  			InvertedIndexConfig: invertedConfig(),
  1863  		}
  1864  		require.Nil(t,
  1865  			migrator.AddClass(context.Background(), class, schemaGetter.shardState))
  1866  	})
  1867  
  1868  	// update schema getter so it's in sync with class
  1869  	schemaGetter.schema = schema.Schema{
  1870  		Objects: &models.Schema{
  1871  			Classes: []*models.Class{class},
  1872  		},
  1873  	}
  1874  
  1875  	searchVector := []float32{-0.10190568, -0.06259751, 0.05616188, -0.19249836, 0.09714927, -0.1902525, -0.064424865, -0.0387358, 0.17581701, 0.4476738, 0.29261824, 0.12026761, -0.19975126, 0.023600178, 0.17348698, 0.12701738, -0.36018127, -0.12051587, -0.17620522, 0.060741074, -0.064512916, 0.18640806, -0.1529852, 0.08211839, -0.02558465, -0.11369845, 0.0924098, -0.10544433, -0.14728987, -0.041860342, -0.08533595, 0.25886244, 0.2963937, 0.26010615, 0.2111097, 0.029396622, 0.01429563, 0.06410264, -0.119665794, 0.33583277, -0.05802661, 0.023306102, 0.14435922, -0.003951336, -0.13870825, 0.07140894, 0.10469943, -0.059021875, -0.065911904, 0.024216041, -0.26282874, 0.04896568, -0.08291928, -0.12793182, -0.077824734, 0.08843151, 0.31247458, -0.066301286, 0.006904921, -0.08277095, 0.13936226, -0.64392364, -0.19566211, 0.047227614, 0.086121306, -0.20725192, -0.096485816, -0.16436341, -0.06559169, -0.019639932, -0.012729637, 0.08901619, 0.0015896161, -0.24789932, 0.35496348, -0.16272856, -0.01648429, 0.11247674, 0.08099968, 0.13339259, 0.055829972, -0.34662855, 0.068509, 0.13880715, 0.3201848, -0.055557363, 0.22142135, -0.12867308, 0.0037871755, 0.24888979, -0.007443307, 0.08906625, -0.02022331, 0.11510742, -0.2385861, 0.16177008, -0.16214795, -0.28715602, 0.016784908, 0.19386634, -0.07731616, -0.100485384, 0.4100712, 0.061834496, -0.2325293, -0.026056025, -0.11632323, -0.17040555, -0.081960455, -0.0061040106, -0.05949373, 0.044952348, -0.079565264, 0.024430245, -0.09375341, -0.30249637, 0.115205586, -0.13083287, -0.04264671, -0.089810364, 0.16227561, 0.07318055, -0.10496504, 0.00063501706, -0.04936106, -0.0022282854, 1.0893154, 0.1698662, -0.019563455, -0.011128426, 0.04477475, -0.15656771, -0.056911886, -0.5759019, -0.1881429, 0.17088258, 0.24124439, 0.111288875, -0.0015475494, -0.021278847, -0.08362156, 0.09997524, -0.094385885, -0.1674031, 0.061180864, 0.28517494, -0.016217072, 0.025866214, -0.22854298, -0.17924422, -0.037767246, 0.12252907, -0.31698978, -0.038031228, 0.055408552, 0.1743545, -0.040576655, 0.1293942, -0.56650764, -0.10306195, -0.19548112, -0.245544, -0.018241389, -0.039024632, -0.31659162, 0.1565075, 0.08412337, 0.13177724, -0.13766576, -0.15355161, -0.16960397, -0.012436442, 0.04828157, 0.12566057, -0.35308784, -0.37520224, -0.1265899, -0.13991497, 0.14402144, 0.117542416, -0.20750546, -0.5849919, -0.010469457, -0.19677396, 0.011365964, 0.00666846, -0.083470255, 0.24928358, 0.07026387, 0.19082819, 0.24557637, 0.014292963, 0.14846677, 0.031625308, -0.20398879, 0.19507346, -0.18119761, -0.045725327, -0.042455163, -0.099733196, -0.33636123, -0.28447086, 0.30274838, -0.01603988, -0.0529655, 0.15784146, 0.08746072, -0.1703993, 0.2414512, 0.060322937, -0.00812057, 0.031162385, -0.1764905, 0.22107981, -0.016657066, 0.31948856, 0.07282925, -0.036991462, 0.01266936, -0.009106514, -0.038732465, 0.20973183, 0.033236098, -0.10673938, -0.06880061, 0.115524575, -0.39688373, 0.08749971, -0.21816005, -0.22100002, -0.3716853, -0.14720486, 0.24316181, 0.29673144, 0.020808747, 0.07658521, 0.16310681, 0.38785335, 0.0992224, 0.14177811, 0.025954131, -0.08690783, 0.19653428, 0.09584941, 0.040072605, -0.00038361162, -0.094546966, 0.1910902, 0.13217318, 0.060072783, -0.0655816, 0.2777626, 0.1799169, 0.20187178, -0.0996889, -0.01932122, -0.13133621, 0.057482753, -0.36892185, -0.032093313, 0.14607865, 0.12033318, -0.041683596, -0.2048406, -0.041777443, -0.14975598, -0.2526341, 0.12659752, 0.010567178, -0.297333, -0.27522174, 0.06923473, 0.043150593, -0.017045585, -0.2400216, 0.11413547, -0.40081662, -0.0018820907, 0.13800722, 0.085972115, -0.01519989, -0.10491216, 0.09170084, 0.063085504, 0.046743374, -0.014466267, 0.09880224, 0.027706565, 0.09951337, 0.17317492, -0.025654864, 0.14658073, 0.042377427, -0.08402882, -0.12423425, 0.32714987, -0.1527207, 0.106094465, 0.017378228, -0.06302387}
  1876  	searchObject := strfmt.UUID("fe687bf4-f10f-4c23-948d-0746ea2927b3")
  1877  
  1878  	tests := map[strfmt.UUID]struct {
  1879  		inputVec []float32
  1880  		expected bool
  1881  	}{
  1882  		strfmt.UUID("88460290-03b2-44a3-9adb-9fa3ae11d9e6"): {
  1883  			inputVec: []float32{-0.11015724, -0.05380307, 0.027512914, -0.16925375, 0.08306809, -0.19312492, -0.08910436, -0.011051652, 0.17981204, 0.40469593, 0.28226805, 0.09381516, -0.18380599, 0.03102771, 0.1645333, 0.1530153, -0.3187937, -0.10800173, -0.18466279, 0.0004336393, -0.0495677, 0.19905856, -0.11614494, 0.08834681, -0.011200292, -0.11969374, 0.12497086, -0.12427251, -0.13395442, -0.0060353535, -0.07504816, 0.23205791, 0.2982508, 0.2517544, 0.176147, -0.036871903, 0.017852835, 0.040007118, -0.118621, 0.3648693, -0.058933854, 0.04004229, 0.11871147, -0.019860389, -0.12701912, 0.106662825, 0.086498804, -0.04303973, -0.0742352, 0.018250324, -0.26544014, 0.029228423, -0.087171465, -0.1282789, -0.06403083, 0.09680911, 0.31433868, -0.081510685, -0.011283603, -0.041624587, 0.16530018, -0.6714878, -0.2436993, 0.03173918, 0.106117725, -0.20803581, -0.10429562, -0.16975354, -0.078582145, -0.0065962705, -0.06840946, 0.094937086, -0.020617036, -0.23795949, 0.34785536, -0.19834635, -0.015064479, 0.11930141, 0.090962164, 0.120560184, 0.054095767, -0.38602966, 0.057141174, 0.12039684, 0.32000408, -0.05146908, 0.20762976, -0.09342379, 0.037577383, 0.23894139, -0.0075003104, 0.104791366, -0.015841056, 0.102840215, -0.20813248, 0.1855997, -0.12594056, -0.27132365, -0.0055563124, 0.21954241, -0.10798524, -0.111896284, 0.44049335, 0.049884494, -0.22339955, -0.005374135, -0.120713554, -0.22275059, -0.09146004, 0.017188415, -0.106493734, 0.045247544, -0.07725446, 0.056848228, -0.10294392, -0.2896642, 0.112891, -0.13773362, -0.089911595, -0.13500965, 0.14051703, 0.040092673, -0.13896292, 0.04580957, -0.014300959, 0.03737215, 1.0661443, 0.19767477, -0.07703914, -0.012910904, -0.0037716173, -0.14437087, -0.06938004, -0.5348036, -0.16047458, 0.19416414, 0.21938956, 0.092242256, -0.012630808, -0.021863988, -0.051702406, 0.08780951, -0.0815602, -0.15332024, 0.077632725, 0.25709584, -0.025725808, 0.042116437, -0.22687604, -0.11791685, -0.028626656, 0.16734225, -0.3017483, -0.03236202, 0.02888077, 0.18193199, -0.009032297, 0.14454253, -0.511494, -0.12119192, -0.20757924, -0.2561716, -0.03904554, -0.07348411, -0.28547177, 0.15967208, 0.079396725, 0.14358875, -0.12829632, -0.18175666, -0.15540425, -0.020419862, 0.019070208, 0.12168836, -0.3428434, -0.357543, -0.11218741, -0.12834033, 0.13564876, 0.12768728, -0.1817461, -0.61235875, -0.029409664, -0.19765733, 0.03872163, 0.0074950717, -0.10025679, 0.2872255, 0.033995092, 0.12945211, 0.21831632, 0.04666009, 0.14233032, 0.016767867, -0.2039244, 0.2000191, -0.13099428, -0.020210614, -0.06286195, -0.0948797, -0.34830436, -0.21595824, 0.32722405, -0.024735296, -0.07859145, 0.16975155, 0.08186461, -0.19249061, 0.23405583, 0.04837592, 0.021467948, -0.022215014, -0.14892808, 0.23908867, -0.050126728, 0.2867907, 0.07740656, -0.01714987, -0.0046314416, -0.0048108613, -0.007407311, 0.1807499, 0.049772616, -0.14680666, -0.07335314, 0.09023705, -0.40600133, 0.05522128, -0.20085222, -0.20410904, -0.34319055, -0.10792269, 0.2297779, 0.30397663, 0.05230268, 0.06408224, 0.13797496, 0.3691112, 0.083033495, 0.13695791, -0.015612457, -0.06413475, 0.18117142, 0.12928344, 0.049171276, 0.016104931, -0.102417335, 0.19589683, 0.14380622, 0.0748065, -0.005402455, 0.27243868, 0.14925551, 0.19564849, -0.10738364, -0.054175537, -0.10068278, 0.06004795, -0.38755924, -0.01654251, 0.1394104, 0.0968949, 0.004271706, -0.17105898, -0.050423585, -0.15311627, -0.24458972, 0.12665795, -0.022814916, -0.23887472, -0.289588, 0.05521137, 0.041259795, -0.021133862, -0.23674431, 0.08424598, -0.37863016, 0.017239956, 0.13776784, 0.060790475, 0.057887543, -0.08784489, 0.08803934, 0.027996546, 0.085972995, -0.014455558, 0.11668073, 0.03812387, 0.088413864, 0.22228678, -0.015599858, 0.11000236, 0.035271563, -0.08088438, -0.13092226, 0.29378533, -0.12311522, 0.09377676, 0.02948718, -0.09136077},
  1884  			expected: true,
  1885  		},
  1886  		strfmt.UUID("c99bc97d-7035-4311-94f3-947dc6471f51"): {
  1887  			inputVec: []float32{-0.07545987, -0.046643265, 0.044445477, -0.18531442, 0.07922216, -0.19388637, -0.069393866, -0.036144026, 0.1713317, 0.41803706, 0.23576374, 0.073170714, -0.14085358, 0.012535708, 0.17439325, 0.10057567, -0.33506152, -0.06800867, -0.18882714, 0.002687021, -0.03276807, 0.17267752, -0.13951558, 0.071382746, 0.020254405, -0.10178502, 0.13977699, -0.107296936, -0.113307, -0.002506761, -0.092065684, 0.21008658, 0.31157792, 0.19640765, 0.15769793, -0.0050196033, 0.0022481605, 0.015436289, -0.11822955, 0.31494477, -0.07425527, 0.051401984, 0.11648046, -0.00016831602, -0.12758006, 0.06814693, 0.06108981, -0.025454175, -0.018695071, 0.041827776, -0.23480764, 0.06652185, -0.078328855, -0.121668324, -0.04341973, 0.114403985, 0.32614416, -0.07992741, -0.019665314, -0.017408244, 0.12615794, -0.6350545, -0.17056493, 0.07171332, 0.047071394, -0.18428493, -0.09011123, -0.15995751, -0.03345579, -0.014678, -0.038699757, 0.044125225, 0.0042562615, -0.29445595, 0.30460796, -0.13630153, 0.00014055961, 0.08996278, 0.08948901, 0.12164838, 0.079090506, -0.36153567, 0.02817218, 0.11914518, 0.29805067, -0.07431765, 0.16793592, -0.099549234, 0.045226075, 0.22235383, -0.045654725, 0.09233901, -0.004902314, 0.08621588, -0.19723448, 0.19557382, -0.13199815, -0.22924824, -0.015981175, 0.19762704, -0.08940076, -0.084909916, 0.43372774, 0.026998578, -0.20827708, 0.037450224, -0.078997016, -0.18065391, -0.071308024, 0.00870316, -0.114981964, 0.017085023, -0.07696264, 0.009330409, -0.097458, -0.25530958, 0.118254915, -0.12516825, -0.008301536, -0.20432962, 0.15235707, 0.012840041, -0.18034773, 0.039270073, -0.03131139, 0.013706253, 0.98688674, 0.18840753, -0.055119563, 0.00836046, 0.019445436, -0.10701598, -0.024610046, -0.50088006, -0.15488546, 0.14209819, 0.1798376, 0.08615982, -0.0119235935, -0.0060070297, -0.08406098, 0.10096481, -0.09077014, -0.15957798, 0.10556352, 0.2100476, -0.036947068, 0.05316554, -0.20480183, -0.14873864, -0.0069070593, 0.16027303, -0.288908, -0.04487129, 0.0705415, 0.11973847, -0.0017247469, 0.14092937, -0.5262047, -0.094283305, -0.19120996, -0.2816572, -0.010916339, -0.07984056, -0.28659204, 0.13706332, 0.07364347, 0.12300072, -0.17554194, -0.16378267, -0.15244205, 0.00075927645, 0.017289847, 0.12072629, -0.33452734, -0.33727616, -0.12780978, -0.09350711, 0.105674624, 0.10770573, -0.17278843, -0.5760599, -0.013741414, -0.15395893, 0.009837732, 0.015417911, -0.11384676, 0.24567491, 0.04905973, 0.10762609, 0.2131752, 0.019281652, 0.11665857, 0.022718405, -0.2234067, 0.23241606, -0.12194457, -0.049972955, -0.012225418, -0.14856412, -0.386102, -0.23018965, 0.28920102, -0.023396742, -0.114672944, 0.12130062, 0.05654803, -0.16194181, 0.24095012, 0.03644393, 0.028024165, -0.008832254, -0.16496961, 0.19496499, -0.035887964, 0.25981775, 0.0970074, 0.0013458093, -0.009548204, 0.040741496, -0.019192837, 0.20718361, -0.004034228, -0.1343262, -0.06990001, 0.09888768, -0.35942966, 0.043895893, -0.19182123, -0.17963983, -0.3222771, -0.10223457, 0.23866613, 0.25855777, 0.04051543, 0.08756274, 0.15683484, 0.37856522, 0.04853359, 0.10198129, -0.0061066896, -0.049892712, 0.17087941, 0.14563805, 0.06984385, 0.0071270005, -0.11838641, 0.18716812, 0.14013803, 0.05242403, 0.034357738, 0.3083466, 0.14742611, 0.17841975, -0.124118194, -0.014102871, -0.052544866, 0.037493005, -0.33485797, -0.013164912, 0.1066288, 0.11141791, -0.04029921, -0.16429856, -0.032241724, -0.15965424, -0.2430594, 0.13654563, 0.009401224, -0.2045843, -0.28467956, 0.07325551, 0.027996557, -0.033877768, -0.24350801, 0.08329816, -0.35555813, 0.006908567, 0.07227365, 0.03188268, 0.032559503, -0.09180395, 0.05601515, 0.0047281734, 0.06878795, -0.018943194, 0.08251342, 0.042039152, 0.12902294, 0.20526606, -0.014881293, 0.11723917, 0.0115632, -0.09016013, -0.12117223, 0.31020245, -0.111444525, 0.077845715, 0.00046715315, -0.104099475},
  1888  			expected: true,
  1889  		},
  1890  		strfmt.UUID("fe687bf4-f10f-4c23-948d-0746ea2927b3"): {
  1891  			inputVec: []float32{-0.20739016, -0.19551805, 0.06645163, 0.008650202, 0.03700748, -0.04132599, -0.029881354, 0.04684896, 0.096614264, 0.42888844, 0.10003969, 0.026234219, -0.051639702, -0.118660435, 0.14473079, 0.2911885, -0.1180539, -0.16804434, -0.48081538, 0.021702053, 0.12612472, 0.15442817, -0.05836532, 0.074295096, -0.28077397, -0.24297802, 0.047836643, -0.36753318, -0.30482984, 0.09265357, 0.25571078, 0.41130066, 0.46177864, 0.34033778, 0.20721313, -0.37726295, 0.07721501, 0.08009689, 0.00027321206, 0.5168123, -0.15305339, 0.0937765, 0.096195236, -0.21120761, 0.014014921, 0.3133104, 0.20773117, 0.08483507, -0.27784437, -0.17281856, -0.6050923, -0.22439326, -0.16914369, -0.3149047, -0.13828672, 0.16334395, -0.0018224253, -0.024342008, 0.3511251, 0.04979151, 0.34223744, -0.6965703, -0.36211932, -0.27092442, 0.34418032, -0.09667905, 0.13344757, -0.15622364, -0.24129291, 0.06958589, -0.2681816, -0.09497071, -0.08923615, -0.06642436, 0.48688608, -0.33535984, 0.014242731, 0.079838976, 0.32949054, 0.09051045, -0.2653392, -0.47393548, 0.07508276, 0.0062832804, 0.724184, -0.18929236, 0.11718613, 0.049603477, 0.08766128, 0.31040704, 0.04038693, -0.0017023507, -0.18986607, 0.056264438, -0.20978904, -0.107441366, -0.30505633, -0.45781082, -0.11571784, 0.32160303, -0.1347523, -0.08090298, 0.51651996, -0.023250414, -0.18725531, -0.14222279, 0.009277832, -0.49789724, -0.25156206, 0.0042495225, 0.0038805408, -0.031416763, 0.10277136, 0.14383446, -0.23241928, -0.42357358, 0.027033398, -0.2262604, -0.2685295, -0.14510548, 0.18256307, 0.063297585, 0.027636252, 0.081166506, 0.06726344, 0.1677495, 1.5217289, 0.33152232, -0.2209926, 0.051426213, 0.15640806, -0.30210486, -0.32857975, -0.4170022, -0.028293105, 0.28772062, 0.50510746, 0.09162247, -0.12383193, -0.25066972, -0.1441897, 0.107192926, -0.07404076, 0.0042472635, 0.11014519, 0.22332853, 0.09434378, -0.3278343, 0.041899726, 0.06838457, 0.10983681, 0.11864574, -0.25336757, -0.047530346, -0.027303243, 0.37403497, 0.13420461, 0.14946426, -0.41996637, -0.037703935, -0.47961184, -0.29839846, -0.103934005, -0.12058302, -0.12806267, 0.22814582, 0.3904893, -0.16044962, -0.17479864, -0.33139735, -0.29185295, 0.0653074, 0.042426735, 0.06092335, -0.18776153, -0.52555144, -0.15889317, -0.20644087, 0.2293067, 0.26668283, -0.15607063, -0.696593, -0.08224992, -0.4283747, 0.26883888, -0.031052848, -0.1311875, 0.26636878, 0.16457985, 0.15660451, 0.10629464, 0.17345549, 0.23963387, 0.22997221, -0.111713186, -0.08499592, -0.2274625, 0.19285984, -0.08285016, -0.02692149, -0.3426618, -0.13361897, 0.2870389, -0.12032792, -0.22944619, 0.25588584, 0.24607788, -0.2762531, 0.30983892, 0.011088746, -0.15739818, 0.053215, -0.21660997, 0.033805694, -0.17886437, 0.2979239, 0.2163545, -0.08381542, 0.19666128, -0.28977823, -0.20994817, -0.012160099, 0.057499636, -0.12549455, 0.19303595, -0.14420606, -0.51937664, 0.23400985, -0.27893808, -0.2660984, -0.27870297, -0.32149136, 0.19958079, 0.34468395, 0.18947665, -0.16529581, 0.101419374, 0.30195153, 0.09030288, 0.12496541, 0.02999903, -0.016697621, 0.15314853, 0.27848768, 0.24102053, 0.06933273, 0.08923653, 0.10477832, 0.4389032, 0.15679164, -0.11119637, 0.134823, 0.30230528, 0.20818473, -0.005579584, -0.3474488, -0.44394243, 0.22270252, -0.3668763, 0.07474772, 0.011691334, 0.088187896, 0.23832949, -0.07960201, 0.066471875, 0.034641538, -0.39984587, 0.0032980456, -0.28492525, -0.46358657, -0.2148288, -0.107226945, 0.02734428, -0.24686679, -0.123900555, 0.18174778, -0.31248868, 0.13808723, 0.31549984, 0.21521719, 0.13966985, -0.27272752, 0.12091104, 0.14257833, 0.23175247, 0.15639938, 0.40828535, 0.31916845, 0.023645567, 0.20658277, -0.20365283, 0.113746524, 0.13173752, -0.050343305, -0.31581175, 0.09704622, -0.014172505, 0.16924341, 0.30327854, -0.17770194},
  1892  			expected: false,
  1893  		},
  1894  		strfmt.UUID("e7bf6c45-de72-493a-b273-5ef198974d61"): {
  1895  			inputVec: []float32{0.089313604, -0.050221898, 0.18352903, 0.16257699, 0.14520381, 0.17993976, 0.14594483, 0.019256027, -0.15505213, 0.23606326, -0.14456263, 0.2679586, -0.112208664, 0.12997514, 0.0051072896, 0.28151348, -0.10495799, 0.026782967, -0.38603118, 0.16190273, -0.0428943, -0.16265322, -0.17910561, 0.0746288, -0.3117934, -0.15871756, -0.11377734, -0.06822346, -0.13829489, 0.13019162, 0.30741218, 0.16194165, 0.013218932, 0.054517113, 0.12490437, -0.07709048, 0.02556826, -0.21159878, -0.09082174, 0.24629511, 0.05013666, 0.25168124, -0.14423938, -0.0937688, -0.07811525, -0.049346007, 0.3592527, 0.30411252, -0.1168557, 0.18870471, 0.06614835, -0.20099068, -0.084436245, 0.073036775, -0.03448665, -0.11147946, -0.10862863, -0.012393957, 0.18990599, 0.060957544, 0.19518377, -0.027541652, -0.26750082, -0.12780671, 0.09570065, -0.03541132, 0.094820626, -0.13539355, -0.09468136, 0.18476579, -0.20970085, -0.20989786, -0.12084438, -0.04517079, -0.008074663, 0.02824076, 0.114496395, -0.20462593, 0.103516705, -0.101554185, -0.1374868, -0.24884155, -0.08101618, -0.016105993, 0.22608215, -0.007247754, -0.17246912, 0.058247145, -0.041018173, 0.19471274, -0.022576109, 0.032828204, -0.079321206, -0.09259324, 0.041115705, -0.25280195, -0.28517374, -0.19496292, 0.18070905, 0.06384923, -0.004056949, 0.1536253, 0.17861623, -0.033833142, 0.12039968, 0.04458716, 0.08793809, -0.15683243, -0.1087904, 0.1741014, 0.007256374, -0.20265253, 0.034111258, 0.03311363, -0.09449356, -0.13161612, -0.026084669, 0.07609202, 0.03452338, 0.08840356, -0.044566724, 0.1507175, 0.089273594, 0.18872644, 0.18333815, -0.023196407, 0.63831943, 0.20309874, 0.10217627, 0.11445079, 0.18965706, -0.16809432, -0.343172, -0.06439529, 0.08362327, 0.32746288, 0.38483366, 0.020372175, -0.25239283, 0.019468365, -0.016367752, 0.016749177, 0.024621855, 0.030529505, 0.20601188, -0.100692995, -0.16414656, -0.23193358, 0.26616478, 0.06166736, 0.14341855, 0.1294041, 0.045133967, 0.0014262896, -0.0194398, 0.040737696, 0.10099013, -0.10838136, -0.28768313, -0.073719576, -0.15836753, -0.10482511, -0.1349642, -0.107005455, 0.01957546, 0.13799994, 0.056444198, -0.38841644, -0.07585945, -0.018703599, -0.19934878, 0.15176265, 0.04133126, 0.063531734, 0.09720055, -0.29999572, 0.04765686, -0.23604262, 0.081500284, 0.056092553, -0.13664724, -0.37729686, 0.031137427, -0.052083906, 0.117984496, -0.14562207, -0.029609507, 0.13725121, 0.090367764, 0.12787215, 0.11026589, 0.25123242, 0.12911159, 0.055398554, 0.0032232201, 0.026706887, 0.14584258, 0.019900957, -0.12197998, -0.087177716, -0.24649806, -0.17869286, 0.07139921, -0.09633085, -0.16027117, 0.23617831, 0.05429949, -0.061085824, 0.040451035, 0.052443117, -0.14255014, 0.15598148, -0.2336374, 0.08394173, -0.34318882, 0.3419207, 0.18282516, -0.03709172, 0.10525048, -0.1871602, -0.22663523, 0.01635051, 0.16996534, -0.18056048, -0.169894, -0.18467705, -0.3641231, 0.060861763, -0.080082566, -0.08888943, 0.11629789, -0.00973362, 0.07452957, 0.25680214, 0.042024083, -0.024963235, 0.1743134, 0.10921186, 0.25191578, 0.028438354, 0.004781374, -0.08364819, 0.051807538, 0.1165724, 0.29184434, -0.21512283, 0.12515399, -0.08803969, 0.41930157, -0.10181762, 0.038189832, 0.085555896, -0.026453126, 0.04717047, 0.12667313, 0.023158737, -0.45877644, 0.18732828, 0.062374037, -0.21956007, -0.04449947, 0.19028638, 0.1359094, 0.26384917, 0.077602044, 0.35136092, 0.069637895, 0.048263475, -0.02498448, -0.09221205, -0.012142404, -0.124592446, 0.14599627, -0.050875153, -0.25454503, -0.069588415, -0.29793787, -0.13407284, 0.25388947, 0.35565627, -0.034204755, 0.0024766966, 0.086427726, -0.054318108, 0.063218184, -0.037823644, 0.108287826, 0.14440496, 0.025134278, 0.14978257, -0.03355889, 0.02980915, -0.13764386, 0.4167542, -0.03938922, 0.026970355, 0.24595529, 0.111741625, -0.074567944, -0.057232533},
  1896  			expected: false,
  1897  		},
  1898  		strfmt.UUID("0999d109-1d5f-465a-bd8b-e3fbd46f10aa"): {
  1899  			inputVec: []float32{-0.10486144, -0.07437922, 0.069469325, -0.1438278, 0.07740161, -0.18606456, -0.09991434, -0.020051572, 0.19863395, 0.4347328, 0.297606, 0.07853262, -0.16025662, 0.023596637, 0.16935731, 0.17052403, -0.29870638, -0.10309007, -0.20055692, 0.0027809117, -0.03928043, 0.21178603, -0.13793766, 0.08118157, 0.006693433, -0.13829204, 0.14778963, -0.13180175, -0.21128704, -0.0026104634, -0.076393716, 0.22200249, 0.32417125, 0.26045212, 0.1783609, -0.114116184, 0.0100981165, 0.07233143, -0.15913877, 0.4238603, -0.036907215, 0.0595873, 0.0807002, -0.07637312, -0.12889846, 0.111177936, 0.091114685, -0.018454906, -0.12132672, 0.056664582, -0.30461523, 0.020763714, -0.10992191, -0.14430659, -0.092879646, 0.13615008, 0.33039626, -0.115675874, 0.03607886, -0.027918883, 0.19531779, -0.7211654, -0.23073879, 0.011791817, 0.1315166, -0.22779183, -0.13773227, -0.1814997, -0.09008116, 0.021698939, -0.102921166, 0.090760864, 0.011856942, -0.25561005, 0.40769714, -0.21286584, -0.018059848, 0.13812906, 0.079457305, 0.12631191, 0.0024881593, -0.4282836, 0.0619608, 0.12207897, 0.39083096, -0.009502015, 0.19990632, -0.06503092, 0.0635979, 0.27579078, -0.020699967, 0.068474516, 0.0043831975, 0.10303624, -0.1885405, 0.22989234, -0.15952443, -0.29842895, 0.006752088, 0.22831629, -0.13150804, -0.13695218, 0.5357904, 0.050116863, -0.24064547, -0.01375713, -0.096647836, -0.24984525, -0.10429946, 0.002098812, -0.08113263, 0.05237009, -0.10246039, 0.05234802, -0.13899775, -0.3439524, 0.12522809, -0.18406768, -0.09022853, -0.19954625, 0.15810682, 0.039185096, -0.13576287, 0.045047805, 0.0035671506, 0.055920787, 1.1730403, 0.24019612, -0.13423051, -0.008052084, -0.00431602, -0.17079304, -0.09064658, -0.58728856, -0.1365065, 0.22919424, 0.22795208, 0.13396585, 0.018962797, -0.0075796233, -0.072394304, 0.10908417, -0.10881145, -0.16565171, 0.10378018, 0.27296618, -0.059810717, 0.03355443, -0.22429268, -0.12499127, -0.0441017, 0.20800696, -0.29992488, -0.003536096, 0.0026575085, 0.2427503, -0.007395092, 0.13233404, -0.5494433, -0.13144702, -0.2899963, -0.27367246, -0.05257514, -0.0939783, -0.267614, 0.16651331, 0.13891254, 0.08047202, -0.14046521, -0.19062972, -0.1433134, 0.0067776316, 0.00207368, 0.12986982, -0.35847133, -0.41852546, -0.15541135, -0.09865207, 0.14805861, 0.17072491, -0.22655731, -0.6473966, -0.007884447, -0.2060257, 0.035390265, 0.02781265, -0.09760371, 0.30535778, 0.047540557, 0.14565119, 0.21733035, 0.06558403, 0.13184759, 0.044231005, -0.22218557, 0.1897204, -0.1596938, 0.017510587, -0.030249557, -0.082377456, -0.39669412, -0.18365891, 0.34806964, -0.024830062, -0.06955674, 0.21521395, 0.1201222, -0.21855503, 0.23522708, 0.038058903, -0.019610198, -0.025448406, -0.18122384, 0.26068974, -0.055872105, 0.29595166, 0.11005987, -0.00841942, 0.006325112, -0.0013332894, -0.025598384, 0.17320716, 0.03480282, -0.1504056, -0.07133905, 0.08367911, -0.41866872, 0.062191408, -0.14972427, -0.18488628, -0.37027854, -0.14803104, 0.23587811, 0.33285886, 0.059688937, 0.030515533, 0.16795416, 0.3813925, 0.0755207, 0.15504116, -0.003507182, -0.08249321, 0.24292688, 0.13771294, 0.08057683, 0.016365156, -0.12878628, 0.1833687, 0.17496476, 0.050333332, 0.008188007, 0.32129762, 0.15476923, 0.2052587, -0.060781036, -0.1502798, -0.10187848, 0.11062117, -0.41137248, 0.016532877, 0.107270226, 0.08759128, 0.011842419, -0.17039144, -0.0139911, -0.13244899, -0.23845059, 0.075682834, -0.052250806, -0.30011725, -0.28581655, -0.00055503653, 0.022204043, -0.08598292, -0.24763824, 0.08245162, -0.39607832, 0.008443992, 0.16124122, 0.08812278, 0.0335653, -0.09692297, 0.07613783, 0.033542078, 0.11447116, -0.0069911424, 0.09004892, 0.09898015, 0.14595516, 0.24977732, -0.0018444546, 0.06290809, 0.013354713, -0.10336537, -0.1028908, 0.31109008, -0.110210516, 0.07165067, 0.050161615, -0.11413514},
  1900  			expected: true,
  1901  		},
  1902  	}
  1903  
  1904  	t.Run("insert test objects", func(t *testing.T) {
  1905  		for id, props := range tests {
  1906  			err := repo.PutObject(context.Background(), &models.Object{Class: className, ID: id}, props.inputVec, nil, nil)
  1907  			require.Nil(t, err)
  1908  		}
  1909  	})
  1910  
  1911  	t.Run("perform nearVector search by distance", func(t *testing.T) {
  1912  		results, err := repo.VectorSearch(context.Background(), dto.GetParams{
  1913  			ClassName:  className,
  1914  			Pagination: &filters.Pagination{Limit: filters.LimitFlagSearchByDist},
  1915  			NearVector: &searchparams.NearVector{
  1916  				Certainty: 0.9,
  1917  			},
  1918  			SearchVector:         searchVector,
  1919  			AdditionalProperties: additional.Properties{Certainty: true},
  1920  		})
  1921  		require.Nil(t, err)
  1922  		require.NotEmpty(t, results)
  1923  		// ensure that we receive more results than
  1924  		// the `QueryMaximumResults`, as this should
  1925  		// only apply to limited vector searches
  1926  		require.Greater(t, len(results), 1)
  1927  
  1928  		for _, res := range results {
  1929  			if props, ok := tests[res.ID]; !ok {
  1930  				t.Fatalf("received unexpected result: %+v", res)
  1931  			} else {
  1932  				assert.True(t, props.expected, "result id was not intended to meet threshold %s", res.ID)
  1933  			}
  1934  		}
  1935  	})
  1936  
  1937  	t.Run("perform nearObject search by distance", func(t *testing.T) {
  1938  		results, err := repo.VectorSearch(context.Background(), dto.GetParams{
  1939  			ClassName:  className,
  1940  			Pagination: &filters.Pagination{Limit: filters.LimitFlagSearchByDist},
  1941  			NearObject: &searchparams.NearObject{
  1942  				Certainty: 0.9,
  1943  				ID:        searchObject.String(),
  1944  			},
  1945  			SearchVector:         searchVector,
  1946  			AdditionalProperties: additional.Properties{Certainty: true},
  1947  		})
  1948  		require.Nil(t, err)
  1949  		require.NotEmpty(t, results)
  1950  		// ensure that we receive more results than
  1951  		// the `QueryMaximumResults`, as this should
  1952  		// only apply to limited vector searches
  1953  		require.Greater(t, len(results), 1)
  1954  
  1955  		for _, res := range results {
  1956  			if props, ok := tests[res.ID]; !ok {
  1957  				t.Fatalf("received unexpected result: %+v", res)
  1958  			} else {
  1959  				assert.True(t, props.expected, "result id was not intended to meet threshold %s", res.ID)
  1960  			}
  1961  		}
  1962  	})
  1963  }
  1964  
  1965  func Test_PutPatchRestart(t *testing.T) {
  1966  	dirName := t.TempDir()
  1967  	logger, _ := test.NewNullLogger()
  1968  	ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
  1969  	defer cancel()
  1970  
  1971  	testClass := &models.Class{
  1972  		VectorIndexConfig:   enthnsw.NewDefaultUserConfig(),
  1973  		InvertedIndexConfig: invertedConfig(),
  1974  		Class:               "PutPatchRestart",
  1975  		Properties: []*models.Property{
  1976  			{
  1977  				Name:         "description",
  1978  				DataType:     schema.DataTypeText.PropString(),
  1979  				Tokenization: models.PropertyTokenizationWhitespace,
  1980  			},
  1981  		},
  1982  	}
  1983  
  1984  	schemaGetter := &fakeSchemaGetter{
  1985  		schema:     schema.Schema{Objects: &models.Schema{Classes: nil}},
  1986  		shardState: singleShardState(),
  1987  	}
  1988  	repo, err := New(logger, Config{
  1989  		MemtablesFlushDirtyAfter:  60,
  1990  		RootPath:                  dirName,
  1991  		QueryMaximumResults:       100,
  1992  		MaxImportGoroutinesFactor: 1,
  1993  	}, &fakeRemoteClient{}, &fakeNodeResolver{}, &fakeRemoteNodeClient{}, &fakeReplicationClient{}, nil)
  1994  	require.Nil(t, err)
  1995  	repo.SetSchemaGetter(schemaGetter)
  1996  	defer repo.Shutdown(context.Background())
  1997  	require.Nil(t, repo.WaitForStartup(ctx))
  1998  	migrator := NewMigrator(repo, logger)
  1999  
  2000  	require.Nil(t,
  2001  		migrator.AddClass(ctx, testClass, schemaGetter.shardState))
  2002  
  2003  	// update schema getter so it's in sync with class
  2004  	schemaGetter.schema = schema.Schema{
  2005  		Objects: &models.Schema{
  2006  			Classes: []*models.Class{testClass},
  2007  		},
  2008  	}
  2009  
  2010  	testID := strfmt.UUID("93c31577-922e-4184-87a5-5ac6db12f73c")
  2011  	testVec := []float32{0.1, 0.2, 0.1, 0.3}
  2012  
  2013  	t.Run("create initial object", func(t *testing.T) {
  2014  		err = repo.PutObject(ctx, &models.Object{
  2015  			ID:         testID,
  2016  			Class:      testClass.Class,
  2017  			Properties: map[string]interface{}{"description": "test object init"},
  2018  		}, testVec, nil, nil)
  2019  		require.Nil(t, err)
  2020  	})
  2021  
  2022  	t.Run("repeatedly put with nil vec, patch with vec, and restart", func(t *testing.T) {
  2023  		for i := 0; i < 10; i++ {
  2024  			err = repo.PutObject(ctx, &models.Object{
  2025  				ID:    testID,
  2026  				Class: testClass.Class,
  2027  				Properties: map[string]interface{}{
  2028  					"description": fmt.Sprintf("test object, put #%d", i+1),
  2029  				},
  2030  			}, nil, nil, nil)
  2031  			require.Nil(t, err)
  2032  
  2033  			err = repo.Merge(ctx, objects.MergeDocument{
  2034  				ID:    testID,
  2035  				Class: testClass.Class,
  2036  				PrimitiveSchema: map[string]interface{}{
  2037  					"description": fmt.Sprintf("test object, patch #%d", i+1),
  2038  				},
  2039  				Vector:     testVec,
  2040  				UpdateTime: time.Now().UnixNano() / int64(time.Millisecond),
  2041  			}, nil, "")
  2042  			require.Nil(t, err)
  2043  
  2044  			require.Nil(t, repo.Shutdown(ctx))
  2045  			require.Nil(t, repo.WaitForStartup(ctx))
  2046  		}
  2047  	})
  2048  
  2049  	t.Run("assert the final result is correct", func(t *testing.T) {
  2050  		findByIDFilter := &filters.LocalFilter{
  2051  			Root: &filters.Clause{
  2052  				Operator: filters.OperatorEqual,
  2053  				On: &filters.Path{
  2054  					Class:    schema.ClassName(testClass.Class),
  2055  					Property: filters.InternalPropID,
  2056  				},
  2057  				Value: &filters.Value{
  2058  					Value: testID.String(),
  2059  					Type:  schema.DataTypeText,
  2060  				},
  2061  			},
  2062  		}
  2063  		res, err := repo.ObjectSearch(ctx, 0, 10, findByIDFilter,
  2064  			nil, additional.Properties{}, "")
  2065  		require.Nil(t, err)
  2066  		assert.Len(t, res, 1)
  2067  
  2068  		expectedDescription := "test object, patch #10"
  2069  		resultDescription := res[0].Schema.(map[string]interface{})["description"]
  2070  		assert.Equal(t, expectedDescription, resultDescription)
  2071  	})
  2072  }
  2073  
  2074  func TestCRUDWithEmptyArrays(t *testing.T) {
  2075  	dirName := t.TempDir()
  2076  
  2077  	logger, _ := test.NewNullLogger()
  2078  
  2079  	class := &models.Class{
  2080  		Class:               "TestClass",
  2081  		VectorIndexConfig:   enthnsw.NewDefaultUserConfig(),
  2082  		InvertedIndexConfig: invertedConfig(),
  2083  		Properties: []*models.Property{
  2084  			{
  2085  				Name:     "textArray",
  2086  				DataType: schema.DataTypeTextArray.PropString(),
  2087  			},
  2088  			{
  2089  				Name:     "numberArray",
  2090  				DataType: []string{string(schema.DataTypeNumberArray)},
  2091  			},
  2092  			{
  2093  				Name:     "boolArray",
  2094  				DataType: []string{string(schema.DataTypeBooleanArray)},
  2095  			},
  2096  		},
  2097  	}
  2098  	classRefName := "TestRefClass"
  2099  	classRef := &models.Class{
  2100  		Class:               classRefName,
  2101  		VectorIndexConfig:   enthnsw.NewDefaultUserConfig(),
  2102  		InvertedIndexConfig: invertedConfig(),
  2103  		Properties: []*models.Property{
  2104  			{
  2105  				Name:         "stringProp",
  2106  				DataType:     schema.DataTypeText.PropString(),
  2107  				Tokenization: models.PropertyTokenizationWhitespace,
  2108  			},
  2109  		},
  2110  	}
  2111  	classNameWithRefs := "TestClassWithRefs"
  2112  	classWithRefs := &models.Class{
  2113  		Class:               classNameWithRefs,
  2114  		VectorIndexConfig:   enthnsw.NewDefaultUserConfig(),
  2115  		InvertedIndexConfig: invertedConfig(),
  2116  		Properties: []*models.Property{
  2117  			{
  2118  				Name:         "stringProp",
  2119  				DataType:     schema.DataTypeText.PropString(),
  2120  				Tokenization: models.PropertyTokenizationWhitespace,
  2121  			},
  2122  			{
  2123  				Name:     "refProp",
  2124  				DataType: []string{classRefName},
  2125  			},
  2126  		},
  2127  	}
  2128  	schemaGetter := &fakeSchemaGetter{
  2129  		schema:     schema.Schema{Objects: &models.Schema{Classes: nil}},
  2130  		shardState: singleShardState(),
  2131  	}
  2132  	repo, err := New(logger, Config{
  2133  		MemtablesFlushDirtyAfter:  60,
  2134  		RootPath:                  dirName,
  2135  		QueryMaximumResults:       100,
  2136  		MaxImportGoroutinesFactor: 1,
  2137  	}, &fakeRemoteClient{}, &fakeNodeResolver{}, &fakeRemoteNodeClient{}, &fakeReplicationClient{}, nil)
  2138  	require.Nil(t, err)
  2139  	repo.SetSchemaGetter(schemaGetter)
  2140  	require.Nil(t, repo.WaitForStartup(testCtx()))
  2141  	defer repo.Shutdown(context.Background())
  2142  	migrator := NewMigrator(repo, logger)
  2143  	require.Nil(t,
  2144  		migrator.AddClass(context.Background(), class, schemaGetter.shardState))
  2145  	require.Nil(t,
  2146  		migrator.AddClass(context.Background(), classRef, schemaGetter.shardState))
  2147  	require.Nil(t,
  2148  		migrator.AddClass(context.Background(), classWithRefs, schemaGetter.shardState))
  2149  	// update schema getter so it's in sync with class
  2150  	schemaGetter.schema = schema.Schema{
  2151  		Objects: &models.Schema{
  2152  			Classes: []*models.Class{class, classRef, classWithRefs},
  2153  		},
  2154  	}
  2155  
  2156  	t.Run("empty arrays", func(t *testing.T) {
  2157  		objID := strfmt.UUID("a0b55b05-bc5b-4cc9-b646-1452d1390a62")
  2158  		obj1 := &models.Object{
  2159  			ID:    objID,
  2160  			Class: "TestClass",
  2161  			Properties: map[string]interface{}{
  2162  				"textArray":   []string{},
  2163  				"numberArray": []float64{},
  2164  				"boolArray":   []bool{},
  2165  			},
  2166  		}
  2167  		obj2 := &models.Object{
  2168  			ID:    objID,
  2169  			Class: "TestClass",
  2170  			Properties: map[string]interface{}{
  2171  				"textArray":   []string{"value"},
  2172  				"numberArray": []float64{0.5},
  2173  				"boolArray":   []bool{true},
  2174  			},
  2175  		}
  2176  
  2177  		assert.Nil(t, repo.PutObject(context.Background(), obj1, []float32{1, 3, 5, 0.4}, nil, nil))
  2178  		assert.Nil(t, repo.PutObject(context.Background(), obj2, []float32{1, 3, 5, 0.4}, nil, nil))
  2179  
  2180  		res, err := repo.ObjectByID(context.Background(), objID, nil, additional.Properties{}, "")
  2181  		require.Nil(t, err)
  2182  		assert.Equal(t, obj2.Properties, res.ObjectWithVector(false).Properties)
  2183  	})
  2184  
  2185  	t.Run("empty references", func(t *testing.T) {
  2186  		objRefID := strfmt.UUID("a0b55b05-bc5b-4cc9-b646-1452d1390000")
  2187  		objRef := &models.Object{
  2188  			ID:    objRefID,
  2189  			Class: classRefName,
  2190  			Properties: map[string]interface{}{
  2191  				"stringProp": "string prop value",
  2192  			},
  2193  		}
  2194  		assert.Nil(t, repo.PutObject(context.Background(), objRef, []float32{1, 3, 5, 0.4}, nil, nil))
  2195  
  2196  		obj1ID := strfmt.UUID("a0b55b05-bc5b-4cc9-b646-1452d1390a62")
  2197  		obj1 := &models.Object{
  2198  			ID:    obj1ID,
  2199  			Class: classNameWithRefs,
  2200  			Properties: map[string]interface{}{
  2201  				"stringProp": "some prop",
  2202  				// due to the fix introduced in https://github.com/weaviate/weaviate/pull/2320,
  2203  				// MultipleRef's can appear as empty []interface{} when no actual refs are provided for
  2204  				// an object's reference property.
  2205  				//
  2206  				// when obj1 is unmarshalled from storage, refProp will be represented as []interface{},
  2207  				// because it is an empty reference property. so when comparing obj1 with the result of
  2208  				// repo.Object, we need this refProp here to be a []interface{}. Note that this is due
  2209  				// to our usage of storobj.Object.MarshallerVersion 1, and future MarshallerVersions may
  2210  				// not have this ambiguous property type limitation.
  2211  				"refProp": []interface{}{},
  2212  			},
  2213  		}
  2214  		obj2ID := strfmt.UUID("a0b55b05-bc5b-4cc9-b646-1452d1390a63")
  2215  		obj2 := &models.Object{
  2216  			ID:    obj2ID,
  2217  			Class: classNameWithRefs,
  2218  			Properties: map[string]interface{}{
  2219  				"stringProp": "some second prop",
  2220  				"refProp": models.MultipleRef{
  2221  					&models.SingleRef{
  2222  						Beacon: strfmt.URI(
  2223  							crossref.NewLocalhost(classRefName, objRefID).String()),
  2224  					},
  2225  				},
  2226  			},
  2227  		}
  2228  
  2229  		assert.Nil(t, repo.PutObject(context.Background(), obj1, []float32{1, 3, 5, 0.4}, nil, nil))
  2230  		assert.Nil(t, repo.PutObject(context.Background(), obj2, []float32{1, 3, 5, 0.4}, nil, nil))
  2231  
  2232  		res, err := repo.Object(context.Background(), classNameWithRefs, obj1ID, nil,
  2233  			additional.Properties{}, nil, "")
  2234  		require.Nil(t, err)
  2235  		assert.NotNil(t, res)
  2236  		assert.Equal(t, obj1.Properties, res.ObjectWithVector(false).Properties)
  2237  
  2238  		res, err = repo.Object(context.Background(), classNameWithRefs, obj2ID, nil,
  2239  			additional.Properties{}, nil, "")
  2240  		require.Nil(t, err)
  2241  		assert.NotNil(t, res)
  2242  		assert.Equal(t, obj2.Properties, res.ObjectWithVector(false).Properties)
  2243  	})
  2244  }
  2245  
  2246  func TestOverwriteObjects(t *testing.T) {
  2247  	dirName := t.TempDir()
  2248  	logger, _ := test.NewNullLogger()
  2249  	class := &models.Class{
  2250  		VectorIndexConfig:   enthnsw.NewDefaultUserConfig(),
  2251  		InvertedIndexConfig: invertedConfig(),
  2252  		Class:               "SomeClass",
  2253  		Properties: []*models.Property{
  2254  			{
  2255  				Name:         "stringProp",
  2256  				DataType:     schema.DataTypeText.PropString(),
  2257  				Tokenization: models.PropertyTokenizationWhitespace,
  2258  			},
  2259  		},
  2260  	}
  2261  	schemaGetter := &fakeSchemaGetter{
  2262  		schema:     schema.Schema{Objects: &models.Schema{Classes: nil}},
  2263  		shardState: singleShardState(),
  2264  	}
  2265  	repo, err := New(logger, Config{
  2266  		MemtablesFlushDirtyAfter:  60,
  2267  		RootPath:                  dirName,
  2268  		QueryMaximumResults:       10,
  2269  		MaxImportGoroutinesFactor: 1,
  2270  	}, &fakeRemoteClient{}, &fakeNodeResolver{},
  2271  		&fakeRemoteNodeClient{}, &fakeReplicationClient{}, nil)
  2272  	require.Nil(t, err)
  2273  	repo.SetSchemaGetter(schemaGetter)
  2274  	require.Nil(t, repo.WaitForStartup(testCtx()))
  2275  	defer repo.Shutdown(context.Background())
  2276  	migrator := NewMigrator(repo, logger)
  2277  	t.Run("create the class", func(t *testing.T) {
  2278  		require.Nil(t,
  2279  			migrator.AddClass(context.Background(), class, schemaGetter.shardState))
  2280  	})
  2281  	// update schema getter so it's in sync with class
  2282  	schemaGetter.schema = schema.Schema{
  2283  		Objects: &models.Schema{
  2284  			Classes: []*models.Class{class},
  2285  		},
  2286  	}
  2287  
  2288  	now := time.Now()
  2289  	later := now.Add(time.Hour) // time-traveling ;)
  2290  	stale := &models.Object{
  2291  		ID:                 "981c09f9-67f3-4e6e-a988-c53eaefbd58e",
  2292  		Class:              class.Class,
  2293  		CreationTimeUnix:   now.UnixMilli(),
  2294  		LastUpdateTimeUnix: now.UnixMilli(),
  2295  		Properties: map[string]interface{}{
  2296  			"oldValue": "how things used to be",
  2297  		},
  2298  		Vector:        []float32{1, 2, 3},
  2299  		VectorWeights: (map[string]string)(nil),
  2300  		Additional:    models.AdditionalProperties{},
  2301  	}
  2302  
  2303  	fresh := &models.Object{
  2304  		ID:                 "981c09f9-67f3-4e6e-a988-c53eaefbd58e",
  2305  		Class:              class.Class,
  2306  		CreationTimeUnix:   now.UnixMilli(),
  2307  		LastUpdateTimeUnix: later.UnixMilli(),
  2308  		Properties: map[string]interface{}{
  2309  			"oldValue": "how things used to be",
  2310  			"newValue": "how they are now",
  2311  		},
  2312  		Vector:        []float32{4, 5, 6},
  2313  		VectorWeights: (map[string]string)(nil),
  2314  		Additional:    models.AdditionalProperties{},
  2315  	}
  2316  
  2317  	t.Run("insert stale object", func(t *testing.T) {
  2318  		err := repo.PutObject(context.Background(), stale, stale.Vector, nil, nil)
  2319  		require.Nil(t, err)
  2320  	})
  2321  
  2322  	t.Run("overwrite with fresh object", func(t *testing.T) {
  2323  		input := []*objects.VObject{
  2324  			{
  2325  				LatestObject:    fresh,
  2326  				Vector:          []float32{4, 5, 6},
  2327  				StaleUpdateTime: stale.LastUpdateTimeUnix,
  2328  			},
  2329  		}
  2330  
  2331  		idx := repo.GetIndex(schema.ClassName(class.Class))
  2332  		shd, err := idx.determineObjectShard(fresh.ID, "")
  2333  		require.Nil(t, err)
  2334  
  2335  		received, err := idx.overwriteObjects(context.Background(), shd, input)
  2336  		assert.Nil(t, err)
  2337  		assert.ElementsMatch(t, nil, received)
  2338  	})
  2339  
  2340  	t.Run("assert data was overwritten", func(t *testing.T) {
  2341  		found, err := repo.Object(context.Background(), stale.Class,
  2342  			stale.ID, nil, additional.Properties{}, nil, "")
  2343  		assert.Nil(t, err)
  2344  		assert.EqualValues(t, fresh, found.Object())
  2345  	})
  2346  }
  2347  
  2348  func TestIndexDigestObjects(t *testing.T) {
  2349  	dirName := t.TempDir()
  2350  	logger, _ := test.NewNullLogger()
  2351  	class := &models.Class{
  2352  		VectorIndexConfig:   enthnsw.NewDefaultUserConfig(),
  2353  		InvertedIndexConfig: invertedConfig(),
  2354  		Class:               "SomeClass",
  2355  		Properties: []*models.Property{
  2356  			{
  2357  				Name:         "stringProp",
  2358  				DataType:     schema.DataTypeText.PropString(),
  2359  				Tokenization: models.PropertyTokenizationWhitespace,
  2360  			},
  2361  		},
  2362  	}
  2363  	schemaGetter := &fakeSchemaGetter{
  2364  		schema:     schema.Schema{Objects: &models.Schema{Classes: nil}},
  2365  		shardState: singleShardState(),
  2366  	}
  2367  	repo, err := New(logger, Config{
  2368  		MemtablesFlushDirtyAfter:  60,
  2369  		RootPath:                  dirName,
  2370  		QueryMaximumResults:       10,
  2371  		MaxImportGoroutinesFactor: 1,
  2372  	}, &fakeRemoteClient{}, &fakeNodeResolver{},
  2373  		&fakeRemoteNodeClient{}, &fakeReplicationClient{}, nil)
  2374  	require.Nil(t, err)
  2375  	repo.SetSchemaGetter(schemaGetter)
  2376  	require.Nil(t, repo.WaitForStartup(testCtx()))
  2377  	defer repo.Shutdown(context.Background())
  2378  	migrator := NewMigrator(repo, logger)
  2379  	t.Run("create the class", func(t *testing.T) {
  2380  		require.Nil(t,
  2381  			migrator.AddClass(context.Background(), class, schemaGetter.shardState))
  2382  	})
  2383  	// update schema getter so it's in sync with class
  2384  	schemaGetter.schema = schema.Schema{
  2385  		Objects: &models.Schema{
  2386  			Classes: []*models.Class{class},
  2387  		},
  2388  	}
  2389  
  2390  	now := time.Now()
  2391  	later := now.Add(time.Hour) // time-traveling ;)
  2392  	obj1 := &models.Object{
  2393  		ID:                 "ae48fda2-866a-4c90-94fc-fce40d5f3767",
  2394  		Class:              class.Class,
  2395  		CreationTimeUnix:   now.UnixMilli(),
  2396  		LastUpdateTimeUnix: now.UnixMilli(),
  2397  		Properties: map[string]interface{}{
  2398  			"oldValue": "how things used to be",
  2399  		},
  2400  		Vector:        []float32{1, 2, 3},
  2401  		VectorWeights: (map[string]string)(nil),
  2402  		Additional:    models.AdditionalProperties{},
  2403  	}
  2404  
  2405  	obj2 := &models.Object{
  2406  		ID:                 "b71ffac8-6534-4368-9718-5410ca89ce16",
  2407  		Class:              class.Class,
  2408  		CreationTimeUnix:   later.UnixMilli(),
  2409  		LastUpdateTimeUnix: later.UnixMilli(),
  2410  		Properties: map[string]interface{}{
  2411  			"oldValue": "how things used to be",
  2412  		},
  2413  		Vector:        []float32{1, 2, 3},
  2414  		VectorWeights: (map[string]string)(nil),
  2415  		Additional:    models.AdditionalProperties{},
  2416  	}
  2417  
  2418  	t.Run("insert test objects", func(t *testing.T) {
  2419  		err := repo.PutObject(context.Background(), obj1, obj1.Vector, nil, nil)
  2420  		require.Nil(t, err)
  2421  		err = repo.PutObject(context.Background(), obj2, obj2.Vector, nil, nil)
  2422  		require.Nil(t, err)
  2423  	})
  2424  
  2425  	t.Run("get digest object", func(t *testing.T) {
  2426  		idx := repo.GetIndex(schema.ClassName(class.Class))
  2427  		shd, err := idx.determineObjectShard(obj1.ID, "")
  2428  		require.Nil(t, err)
  2429  
  2430  		input := []strfmt.UUID{obj1.ID, obj2.ID}
  2431  
  2432  		expected := []replica.RepairResponse{
  2433  			{
  2434  				ID:         obj1.ID.String(),
  2435  				UpdateTime: obj1.LastUpdateTimeUnix,
  2436  			},
  2437  			{
  2438  				ID:         obj2.ID.String(),
  2439  				UpdateTime: obj2.LastUpdateTimeUnix,
  2440  			},
  2441  		}
  2442  
  2443  		res, err := idx.digestObjects(context.Background(), shd, input)
  2444  		require.Nil(t, err)
  2445  		assert.Equal(t, expected, res)
  2446  	})
  2447  }
  2448  
  2449  func findID(list []search.Result, id strfmt.UUID) (search.Result, bool) {
  2450  	for _, item := range list {
  2451  		if item.ID == id {
  2452  			return item, true
  2453  		}
  2454  	}
  2455  
  2456  	return search.Result{}, false
  2457  }
  2458  
  2459  func ptFloat32(in float32) *float32 {
  2460  	return &in
  2461  }
  2462  
  2463  func ptFloat64(in float64) *float64 {
  2464  	return &in
  2465  }
  2466  
  2467  func randomVector(r *rand.Rand, dim int) []float32 {
  2468  	out := make([]float32, dim)
  2469  	for i := range out {
  2470  		out[i] = r.Float32()
  2471  	}
  2472  
  2473  	return out
  2474  }
  2475  
  2476  func TestIndexDifferentVectorLength(t *testing.T) {
  2477  	logger, _ := test.NewNullLogger()
  2478  	class := &models.Class{
  2479  		VectorIndexConfig:   enthnsw.NewDefaultUserConfig(),
  2480  		InvertedIndexConfig: invertedConfig(),
  2481  		Class:               "SomeClass",
  2482  		Properties: []*models.Property{
  2483  			{
  2484  				Name:         "stringProp",
  2485  				DataType:     schema.DataTypeText.PropString(),
  2486  				Tokenization: models.PropertyTokenizationWhitespace,
  2487  			},
  2488  		},
  2489  	}
  2490  	schemaGetter := &fakeSchemaGetter{
  2491  		schema:     schema.Schema{Objects: &models.Schema{Classes: nil}},
  2492  		shardState: singleShardState(),
  2493  	}
  2494  	repo, err := New(logger, Config{
  2495  		MemtablesFlushDirtyAfter:  60,
  2496  		RootPath:                  t.TempDir(),
  2497  		QueryMaximumResults:       10,
  2498  		MaxImportGoroutinesFactor: 1,
  2499  	}, &fakeRemoteClient{}, &fakeNodeResolver{},
  2500  		&fakeRemoteNodeClient{}, &fakeReplicationClient{}, nil)
  2501  	require.Nil(t, err)
  2502  	repo.SetSchemaGetter(schemaGetter)
  2503  	require.Nil(t, repo.WaitForStartup(testCtx()))
  2504  	defer repo.Shutdown(context.Background())
  2505  	migrator := NewMigrator(repo, logger)
  2506  	require.Nil(t, migrator.AddClass(context.Background(), class, schemaGetter.shardState))
  2507  	// update schema getter so it's in sync with class
  2508  	schemaGetter.schema = schema.Schema{
  2509  		Objects: &models.Schema{
  2510  			Classes: []*models.Class{class},
  2511  		},
  2512  	}
  2513  
  2514  	obj1ID := strfmt.UUID("ae48fda2-866a-4c90-94fc-fce40d5f3767")
  2515  	objNilID := strfmt.UUID("b71ffac9-6534-4368-9718-5410ca89ce16")
  2516  
  2517  	t.Run("Add object with nil vector", func(t *testing.T) {
  2518  		objNil := &models.Object{
  2519  			ID:     objNilID,
  2520  			Class:  class.Class,
  2521  			Vector: nil,
  2522  		}
  2523  		require.Nil(t, repo.PutObject(context.Background(), objNil, objNil.Vector, nil, nil))
  2524  		found, err := repo.Object(context.Background(), class.Class, objNil.ID, nil,
  2525  			additional.Properties{}, nil, "")
  2526  		require.Nil(t, err)
  2527  		require.Equal(t, found.Vector, []float32{})
  2528  		require.Equal(t, objNil.ID, found.ID)
  2529  	})
  2530  
  2531  	t.Run("Add object with non-nil vector after nil vector", func(t *testing.T) {
  2532  		obj1 := &models.Object{
  2533  			ID:     obj1ID,
  2534  			Class:  class.Class,
  2535  			Vector: []float32{1, 2, 3},
  2536  		}
  2537  		require.Nil(t, repo.PutObject(context.Background(), obj1, obj1.Vector, nil, nil))
  2538  	})
  2539  
  2540  	t.Run("Add object with different vector length", func(t *testing.T) {
  2541  		obj2 := &models.Object{
  2542  			ID:     "b71ffac8-6534-4368-9718-5410ca89ce16",
  2543  			Class:  class.Class,
  2544  			Vector: []float32{1, 2, 3, 4},
  2545  		}
  2546  		require.NotNil(t, repo.PutObject(context.Background(), obj2, obj2.Vector, nil, nil))
  2547  		found, err := repo.Object(context.Background(), class.Class, obj2.ID, nil,
  2548  			additional.Properties{}, nil, "")
  2549  		require.Nil(t, err)
  2550  		require.Nil(t, found)
  2551  	})
  2552  
  2553  	t.Run("Update object with different vector length", func(t *testing.T) {
  2554  		err = repo.Merge(context.Background(), objects.MergeDocument{
  2555  			ID:              obj1ID,
  2556  			Class:           class.Class,
  2557  			PrimitiveSchema: map[string]interface{}{},
  2558  			Vector:          []float32{1, 2, 3, 4},
  2559  			UpdateTime:      time.Now().UnixNano() / int64(time.Millisecond),
  2560  		}, nil, "")
  2561  		require.NotNil(t, err)
  2562  		found, err := repo.Object(context.Background(), class.Class,
  2563  			obj1ID, nil, additional.Properties{}, nil, "")
  2564  		require.Nil(t, err)
  2565  		require.Len(t, found.Vector, 3)
  2566  	})
  2567  
  2568  	t.Run("Update nil object with fitting vector", func(t *testing.T) {
  2569  		err = repo.Merge(context.Background(), objects.MergeDocument{
  2570  			ID:              objNilID,
  2571  			Class:           class.Class,
  2572  			PrimitiveSchema: map[string]interface{}{},
  2573  			Vector:          []float32{1, 2, 3},
  2574  			UpdateTime:      time.Now().UnixNano() / int64(time.Millisecond),
  2575  		}, nil, "")
  2576  		require.Nil(t, err)
  2577  		found, err := repo.Object(context.Background(), class.Class, objNilID, nil,
  2578  			additional.Properties{}, nil, "")
  2579  		require.Nil(t, err)
  2580  		require.Len(t, found.Vector, 3)
  2581  	})
  2582  
  2583  	t.Run("Add nil object after objects with vector", func(t *testing.T) {
  2584  		obj2Nil := &models.Object{
  2585  			ID:     "b71ffac8-6534-4368-9718-5410ca89ce16",
  2586  			Class:  class.Class,
  2587  			Vector: nil,
  2588  		}
  2589  		require.Nil(t, repo.PutObject(context.Background(), obj2Nil, obj2Nil.Vector, nil, nil))
  2590  		found, err := repo.Object(context.Background(), class.Class, obj2Nil.ID, nil,
  2591  			additional.Properties{}, nil, "")
  2592  		require.Nil(t, err)
  2593  		require.Equal(t, obj2Nil.ID, found.ID)
  2594  		require.Equal(t, []float32{}, found.Vector)
  2595  	})
  2596  }