github.com/weaviate/weaviate@v1.24.6/usecases/traverser/traverser_explore_concepts_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  package traverser
    13  
    14  import (
    15  	"context"
    16  	"testing"
    17  
    18  	"github.com/go-openapi/strfmt"
    19  	"github.com/sirupsen/logrus/hooks/test"
    20  	"github.com/stretchr/testify/assert"
    21  	"github.com/stretchr/testify/require"
    22  	"github.com/weaviate/weaviate/entities/search"
    23  	"github.com/weaviate/weaviate/entities/searchparams"
    24  	"github.com/weaviate/weaviate/usecases/config"
    25  )
    26  
    27  func Test_ExploreConcepts(t *testing.T) {
    28  	t.Run("without any near searchers", func(t *testing.T) {
    29  		authorizer := &fakeAuthorizer{}
    30  		locks := &fakeLocks{}
    31  		logger, _ := test.NewNullLogger()
    32  		vectorSearcher := &fakeVectorSearcher{}
    33  		log, _ := test.NewNullLogger()
    34  		metrics := &fakeMetrics{}
    35  		explorer := NewExplorer(vectorSearcher, log, getFakeModulesProvider(), metrics, defaultConfig)
    36  		schemaGetter := &fakeSchemaGetter{}
    37  		traverser := NewTraverser(&config.WeaviateConfig{}, locks, logger, authorizer,
    38  			vectorSearcher, explorer, schemaGetter, getFakeModulesProvider(), nil, -1)
    39  		params := ExploreParams{}
    40  
    41  		_, err := traverser.Explore(context.Background(), nil, params)
    42  		assert.Contains(t, err.Error(), "received no search params")
    43  	})
    44  
    45  	t.Run("with two searchers set at the same time", func(t *testing.T) {
    46  		authorizer := &fakeAuthorizer{}
    47  		locks := &fakeLocks{}
    48  		logger, _ := test.NewNullLogger()
    49  		vectorSearcher := &fakeVectorSearcher{}
    50  		log, _ := test.NewNullLogger()
    51  		metrics := &fakeMetrics{}
    52  		explorer := NewExplorer(vectorSearcher, log, getFakeModulesProvider(), metrics, defaultConfig)
    53  		schemaGetter := &fakeSchemaGetter{}
    54  		traverser := NewTraverser(&config.WeaviateConfig{}, locks, logger, authorizer,
    55  			vectorSearcher, explorer, schemaGetter, nil, nil, -1)
    56  		params := ExploreParams{
    57  			NearVector: &searchparams.NearVector{},
    58  			ModuleParams: map[string]interface{}{
    59  				"nearCustomText": nil,
    60  			},
    61  		}
    62  
    63  		_, err := traverser.Explore(context.Background(), nil, params)
    64  		assert.Contains(t, err.Error(), "parameters which are conflicting")
    65  	})
    66  	t.Run("nearCustomText with no movements set", func(t *testing.T) {
    67  		authorizer := &fakeAuthorizer{}
    68  		locks := &fakeLocks{}
    69  		logger, _ := test.NewNullLogger()
    70  		vectorSearcher := &fakeVectorSearcher{}
    71  		log, _ := test.NewNullLogger()
    72  		metrics := &fakeMetrics{}
    73  		explorer := NewExplorer(vectorSearcher, log, getFakeModulesProvider(), metrics, defaultConfig)
    74  		schemaGetter := &fakeSchemaGetter{}
    75  		traverser := NewTraverser(&config.WeaviateConfig{}, locks, logger, authorizer,
    76  			vectorSearcher, explorer, schemaGetter, getFakeModulesProvider(), nil, -1)
    77  		params := ExploreParams{
    78  			ModuleParams: map[string]interface{}{
    79  				"nearCustomText": extractNearCustomTextParam(map[string]interface{}{
    80  					"concepts": []interface{}{"a search term", "another"},
    81  				}),
    82  			},
    83  		}
    84  		vectorSearcher.results = []search.Result{
    85  			{
    86  				ClassName: "BestClass",
    87  				ID:        "123-456-789",
    88  				Certainty: 0.5,
    89  				Dist:      0.5,
    90  				Dims:      128,
    91  			},
    92  			{
    93  				ClassName: "AnAction",
    94  				ID:        "987-654-321",
    95  				Certainty: 0.5,
    96  				Dist:      0.5,
    97  				Dims:      128,
    98  			},
    99  		}
   100  
   101  		metrics.On("AddUsageDimensions", "n/a", "explore_graphql", "nearCustomText", 128)
   102  
   103  		res, err := traverser.Explore(context.Background(), nil, params)
   104  		require.Nil(t, err)
   105  		assert.Equal(t, []search.Result{
   106  			{
   107  				ClassName: "BestClass",
   108  				ID:        "123-456-789",
   109  				Beacon:    "weaviate://localhost/BestClass/123-456-789",
   110  				Certainty: 0.5,
   111  				Dist:      0.5,
   112  				Dims:      128,
   113  			},
   114  			{
   115  				ClassName: "AnAction",
   116  				ID:        "987-654-321",
   117  				Beacon:    "weaviate://localhost/AnAction/987-654-321",
   118  				Certainty: 0.5,
   119  				Dist:      0.5,
   120  				Dims:      128,
   121  			},
   122  		}, res)
   123  
   124  		assert.Equal(t, []float32{1, 2, 3}, vectorSearcher.calledWithVector)
   125  		assert.Equal(t, 20, vectorSearcher.calledWithLimit,
   126  			"uses the default limit if not explicitly set")
   127  	})
   128  
   129  	t.Run("nearCustomText without optional params", func(t *testing.T) {
   130  		authorizer := &fakeAuthorizer{}
   131  		locks := &fakeLocks{}
   132  		logger, _ := test.NewNullLogger()
   133  		vectorSearcher := &fakeVectorSearcher{}
   134  		log, _ := test.NewNullLogger()
   135  		metrics := &fakeMetrics{}
   136  		explorer := NewExplorer(vectorSearcher, log, getFakeModulesProvider(), metrics, defaultConfig)
   137  		schemaGetter := &fakeSchemaGetter{}
   138  		traverser := NewTraverser(&config.WeaviateConfig{}, locks, logger, authorizer,
   139  			vectorSearcher, explorer, schemaGetter, nil, nil, -1)
   140  		params := ExploreParams{
   141  			NearVector: &searchparams.NearVector{
   142  				Vector: []float32{7.8, 9},
   143  			},
   144  		}
   145  		vectorSearcher.results = []search.Result{
   146  			{
   147  				ClassName: "BestClass",
   148  				ID:        "123-456-789",
   149  				Certainty: 0.5,
   150  				Dist:      0.5,
   151  				Dims:      128,
   152  			},
   153  			{
   154  				ClassName: "AnAction",
   155  				ID:        "987-654-321",
   156  				Certainty: 0.5,
   157  				Dist:      0.5,
   158  				Dims:      128,
   159  			},
   160  		}
   161  
   162  		metrics.On("AddUsageDimensions", "n/a", "explore_graphql", "nearVector", 128)
   163  		res, err := traverser.Explore(context.Background(), nil, params)
   164  		require.Nil(t, err)
   165  		assert.Equal(t, []search.Result{
   166  			{
   167  				ClassName: "BestClass",
   168  				ID:        "123-456-789",
   169  				Beacon:    "weaviate://localhost/BestClass/123-456-789",
   170  				Certainty: 0.5,
   171  				Dist:      0.5,
   172  				Dims:      128,
   173  			},
   174  			{
   175  				ClassName: "AnAction",
   176  				ID:        "987-654-321",
   177  				Beacon:    "weaviate://localhost/AnAction/987-654-321",
   178  				Certainty: 0.5,
   179  				Dist:      0.5,
   180  				Dims:      128,
   181  			},
   182  		}, res)
   183  
   184  		assert.Equal(t, []float32{7.8, 9}, vectorSearcher.calledWithVector)
   185  		assert.Equal(t, 20, vectorSearcher.calledWithLimit,
   186  			"uses the default limit if not explicitly set")
   187  	})
   188  
   189  	t.Run("nearObject with id param", func(t *testing.T) {
   190  		authorizer := &fakeAuthorizer{}
   191  		locks := &fakeLocks{}
   192  		logger, _ := test.NewNullLogger()
   193  		vectorSearcher := &fakeVectorSearcher{}
   194  		log, _ := test.NewNullLogger()
   195  		metrics := &fakeMetrics{}
   196  		explorer := NewExplorer(vectorSearcher, log, getFakeModulesProvider(), metrics, defaultConfig)
   197  		schemaGetter := &fakeSchemaGetter{}
   198  		traverser := NewTraverser(&config.WeaviateConfig{}, locks, logger, authorizer,
   199  			vectorSearcher, explorer, schemaGetter, nil, nil, -1)
   200  		params := ExploreParams{
   201  			NearObject: &searchparams.NearObject{
   202  				ID: "bd3d1560-3f0e-4b39-9d62-38b4a3c4f23a",
   203  			},
   204  		}
   205  		searchRes := search.Result{
   206  			ClassName: "BestClass",
   207  			ID:        "bd3d1560-3f0e-4b39-9d62-38b4a3c4f23a",
   208  		}
   209  		vectorSearcher.
   210  			On("ObjectsByID", strfmt.UUID("bd3d1560-3f0e-4b39-9d62-38b4a3c4f23a")).
   211  			Return(search.Results{searchRes}, nil)
   212  		vectorSearcher.results = []search.Result{
   213  			{
   214  				ClassName: "BestClass",
   215  				ID:        "bd3d1560-3f0e-4b39-9d62-38b4a3c4f23a",
   216  				Certainty: 0.5,
   217  				Dist:      0.5,
   218  				Dims:      128,
   219  			},
   220  			{
   221  				ClassName: "AnAction",
   222  				ID:        "bd3d1560-3f0e-4b39-9d62-38b4a3c4f23b",
   223  				Certainty: 0.5,
   224  				Dist:      0.5,
   225  				Dims:      128,
   226  			},
   227  		}
   228  
   229  		metrics.On("AddUsageDimensions", "n/a", "explore_graphql", "nearObject", 128)
   230  		res, err := traverser.Explore(context.Background(), nil, params)
   231  		require.Nil(t, err)
   232  		assert.Equal(t, []search.Result{
   233  			{
   234  				ClassName: "BestClass",
   235  				ID:        "bd3d1560-3f0e-4b39-9d62-38b4a3c4f23a",
   236  				Beacon:    "weaviate://localhost/BestClass/bd3d1560-3f0e-4b39-9d62-38b4a3c4f23a",
   237  				Certainty: 0.5,
   238  				Dist:      0.5,
   239  				Dims:      128,
   240  			},
   241  			{
   242  				ClassName: "AnAction",
   243  				ID:        "bd3d1560-3f0e-4b39-9d62-38b4a3c4f23b",
   244  				Beacon:    "weaviate://localhost/AnAction/bd3d1560-3f0e-4b39-9d62-38b4a3c4f23b",
   245  				Certainty: 0.5,
   246  				Dist:      0.5,
   247  				Dims:      128,
   248  			},
   249  		}, res)
   250  
   251  		assert.Equal(t, 20, vectorSearcher.calledWithLimit,
   252  			"uses the default limit if not explicitly set")
   253  	})
   254  
   255  	t.Run("nearObject with beacon param", func(t *testing.T) {
   256  		authorizer := &fakeAuthorizer{}
   257  		locks := &fakeLocks{}
   258  		logger, _ := test.NewNullLogger()
   259  		vectorSearcher := &fakeVectorSearcher{}
   260  		log, _ := test.NewNullLogger()
   261  		metrics := &fakeMetrics{}
   262  		explorer := NewExplorer(vectorSearcher, log, getFakeModulesProvider(), metrics, defaultConfig)
   263  		schemaGetter := &fakeSchemaGetter{}
   264  		traverser := NewTraverser(&config.WeaviateConfig{}, locks, logger, authorizer,
   265  			vectorSearcher, explorer, schemaGetter, nil, nil, -1)
   266  		params := ExploreParams{
   267  			NearObject: &searchparams.NearObject{
   268  				Beacon: "weaviate://localhost/bd3d1560-3f0e-4b39-9d62-38b4a3c4f23a",
   269  			},
   270  		}
   271  		searchRes := search.Result{
   272  			ClassName: "BestClass",
   273  			ID:        "bd3d1560-3f0e-4b39-9d62-38b4a3c4f23a",
   274  		}
   275  		vectorSearcher.
   276  			On("ObjectsByID", strfmt.UUID("bd3d1560-3f0e-4b39-9d62-38b4a3c4f23a")).
   277  			Return(search.Results{searchRes}, nil)
   278  		vectorSearcher.results = []search.Result{
   279  			{
   280  				ClassName: "BestClass",
   281  				ID:        "bd3d1560-3f0e-4b39-9d62-38b4a3c4f23a",
   282  				Certainty: 0.5,
   283  				Dist:      0.5,
   284  				Dims:      128,
   285  			},
   286  			{
   287  				ClassName: "AnAction",
   288  				ID:        "bd3d1560-3f0e-4b39-9d62-38b4a3c4f23b",
   289  				Certainty: 0.5,
   290  				Dist:      0.5,
   291  				Dims:      128,
   292  			},
   293  		}
   294  
   295  		metrics.On("AddUsageDimensions", "n/a", "explore_graphql", "nearObject", 128)
   296  		res, err := traverser.Explore(context.Background(), nil, params)
   297  		require.Nil(t, err)
   298  		assert.Equal(t, []search.Result{
   299  			{
   300  				ClassName: "BestClass",
   301  				ID:        "bd3d1560-3f0e-4b39-9d62-38b4a3c4f23a",
   302  				Beacon:    "weaviate://localhost/BestClass/bd3d1560-3f0e-4b39-9d62-38b4a3c4f23a",
   303  				Certainty: 0.5,
   304  				Dist:      0.5,
   305  				Dims:      128,
   306  			},
   307  			{
   308  				ClassName: "AnAction",
   309  				ID:        "bd3d1560-3f0e-4b39-9d62-38b4a3c4f23b",
   310  				Beacon:    "weaviate://localhost/AnAction/bd3d1560-3f0e-4b39-9d62-38b4a3c4f23b",
   311  				Certainty: 0.5,
   312  				Dist:      0.5,
   313  				Dims:      128,
   314  			},
   315  		}, res)
   316  
   317  		assert.Equal(t, 20, vectorSearcher.calledWithLimit,
   318  			"uses the default limit if not explicitly set")
   319  	})
   320  
   321  	t.Run("nearCustomText with limit and distance set", func(t *testing.T) {
   322  		authorizer := &fakeAuthorizer{}
   323  		locks := &fakeLocks{}
   324  		logger, _ := test.NewNullLogger()
   325  		vectorSearcher := &fakeVectorSearcher{}
   326  		log, _ := test.NewNullLogger()
   327  		metrics := &fakeMetrics{}
   328  		explorer := NewExplorer(vectorSearcher, log, getFakeModulesProvider(), metrics, defaultConfig)
   329  		schemaGetter := &fakeSchemaGetter{}
   330  		traverser := NewTraverser(&config.WeaviateConfig{}, locks, logger, authorizer,
   331  			vectorSearcher, explorer, schemaGetter, getFakeModulesProvider(), nil, -1)
   332  		params := ExploreParams{
   333  			Limit: 100,
   334  			NearVector: &searchparams.NearVector{
   335  				Vector:       []float32{7.8, 9},
   336  				Distance:     0.2,
   337  				WithDistance: true,
   338  			},
   339  		}
   340  		vectorSearcher.results = []search.Result{
   341  			{
   342  				ClassName: "BestClass",
   343  				ID:        "123-456-789",
   344  				Dist:      0.4,
   345  				Dims:      128,
   346  			},
   347  			{
   348  				ClassName: "AnAction",
   349  				ID:        "987-654-321",
   350  				Dist:      0.4,
   351  				Dims:      128,
   352  			},
   353  		}
   354  
   355  		metrics.On("AddUsageDimensions", "n/a", "explore_graphql", "nearVector", 128)
   356  		res, err := traverser.Explore(context.Background(), nil, params)
   357  		require.Nil(t, err)
   358  		assert.Equal(t, []search.Result{}, res) // certainty not matched
   359  
   360  		assert.Equal(t, []float32{7.8, 9}, vectorSearcher.calledWithVector)
   361  		assert.Equal(t, 100, vectorSearcher.calledWithLimit,
   362  			"uses the default limit if not explicitly set")
   363  	})
   364  
   365  	t.Run("nearCustomText with limit and certainty set", func(t *testing.T) {
   366  		authorizer := &fakeAuthorizer{}
   367  		locks := &fakeLocks{}
   368  		logger, _ := test.NewNullLogger()
   369  		vectorSearcher := &fakeVectorSearcher{}
   370  		log, _ := test.NewNullLogger()
   371  		metrics := &fakeMetrics{}
   372  		explorer := NewExplorer(vectorSearcher, log, getFakeModulesProvider(), metrics, defaultConfig)
   373  		schemaGetter := &fakeSchemaGetter{}
   374  		traverser := NewTraverser(&config.WeaviateConfig{}, locks, logger, authorizer,
   375  			vectorSearcher, explorer, schemaGetter, getFakeModulesProvider(), nil, -1)
   376  		params := ExploreParams{
   377  			Limit: 100,
   378  			NearVector: &searchparams.NearVector{
   379  				Vector:    []float32{7.8, 9},
   380  				Certainty: 0.8,
   381  			},
   382  		}
   383  		vectorSearcher.results = []search.Result{
   384  			{
   385  				ClassName: "BestClass",
   386  				ID:        "123-456-789",
   387  				Dims:      128,
   388  			},
   389  			{
   390  				ClassName: "AnAction",
   391  				ID:        "987-654-321",
   392  				Dims:      128,
   393  			},
   394  		}
   395  
   396  		metrics.On("AddUsageDimensions", "n/a", "explore_graphql", "nearVector", 128)
   397  		res, err := traverser.Explore(context.Background(), nil, params)
   398  		require.Nil(t, err)
   399  		assert.Equal(t, []search.Result{}, res) // certainty not matched
   400  
   401  		assert.Equal(t, []float32{7.8, 9}, vectorSearcher.calledWithVector)
   402  		assert.Equal(t, 100, vectorSearcher.calledWithLimit,
   403  			"uses the default limit if not explicitly set")
   404  	})
   405  
   406  	t.Run("nearCustomText with minimum distance set to 0.4", func(t *testing.T) {
   407  		authorizer := &fakeAuthorizer{}
   408  		locks := &fakeLocks{}
   409  		logger, _ := test.NewNullLogger()
   410  		vectorSearcher := &fakeVectorSearcher{}
   411  		log, _ := test.NewNullLogger()
   412  		metrics := &fakeMetrics{}
   413  		explorer := NewExplorer(vectorSearcher, log, getFakeModulesProvider(), metrics, defaultConfig)
   414  		schemaGetter := &fakeSchemaGetter{}
   415  		traverser := NewTraverser(&config.WeaviateConfig{}, locks, logger, authorizer,
   416  			vectorSearcher, explorer, schemaGetter, getFakeModulesProvider(), nil, -1)
   417  		params := ExploreParams{
   418  			ModuleParams: map[string]interface{}{
   419  				"nearCustomText": extractNearCustomTextParam(map[string]interface{}{
   420  					"concepts": []interface{}{"a search term", "another"},
   421  					"distance": float64(0.4),
   422  				}),
   423  			},
   424  		}
   425  		vectorSearcher.results = []search.Result{}
   426  
   427  		res, err := traverser.Explore(context.Background(), nil, params)
   428  		require.Nil(t, err)
   429  		assert.Equal(t, []search.Result{}, res, "empty result because distance is not met")
   430  		assert.Equal(t, []float32{1, 2, 3}, vectorSearcher.calledWithVector)
   431  		assert.Equal(t, 20, vectorSearcher.calledWithLimit,
   432  			"uses the default limit if not explicitly set")
   433  	})
   434  
   435  	t.Run("nearCustomText with minimum certainty set to 0.6", func(t *testing.T) {
   436  		authorizer := &fakeAuthorizer{}
   437  		locks := &fakeLocks{}
   438  		logger, _ := test.NewNullLogger()
   439  		vectorSearcher := &fakeVectorSearcher{}
   440  		log, _ := test.NewNullLogger()
   441  		metrics := &fakeMetrics{}
   442  		explorer := NewExplorer(vectorSearcher, log, getFakeModulesProvider(), metrics, defaultConfig)
   443  		schemaGetter := &fakeSchemaGetter{}
   444  		traverser := NewTraverser(&config.WeaviateConfig{}, locks, logger, authorizer,
   445  			vectorSearcher, explorer, schemaGetter, getFakeModulesProvider(), nil, -1)
   446  		params := ExploreParams{
   447  			ModuleParams: map[string]interface{}{
   448  				"nearCustomText": extractNearCustomTextParam(map[string]interface{}{
   449  					"concepts":  []interface{}{"a search term", "another"},
   450  					"certainty": float64(0.6),
   451  				}),
   452  			},
   453  		}
   454  		vectorSearcher.results = []search.Result{
   455  			{
   456  				ClassName: "BestClass",
   457  				ID:        "123-456-789",
   458  				Dims:      128,
   459  			},
   460  			{
   461  				ClassName: "AnAction",
   462  				ID:        "987-654-321",
   463  				Dims:      128,
   464  			},
   465  		}
   466  
   467  		metrics.On("AddUsageDimensions", "n/a", "explore_graphql", "nearCustomText", 128)
   468  		res, err := traverser.Explore(context.Background(), nil, params)
   469  		require.Nil(t, err)
   470  		assert.Equal(t, []search.Result{}, res, "empty result because certainty is not met")
   471  		assert.Equal(t, []float32{1, 2, 3}, vectorSearcher.calledWithVector)
   472  		assert.Equal(t, 20, vectorSearcher.calledWithLimit,
   473  			"uses the default limit if not explicitly set")
   474  	})
   475  
   476  	t.Run("near text with movements set", func(t *testing.T) {
   477  		authorizer := &fakeAuthorizer{}
   478  		locks := &fakeLocks{}
   479  		logger, _ := test.NewNullLogger()
   480  		vectorSearcher := &fakeVectorSearcher{}
   481  		log, _ := test.NewNullLogger()
   482  		metrics := &fakeMetrics{}
   483  		explorer := NewExplorer(vectorSearcher, log, getFakeModulesProvider(), metrics, defaultConfig)
   484  		schemaGetter := &fakeSchemaGetter{}
   485  		traverser := NewTraverser(&config.WeaviateConfig{}, locks, logger, authorizer,
   486  			vectorSearcher, explorer, schemaGetter, getFakeModulesProvider(), nil, -1)
   487  		params := ExploreParams{
   488  			Limit: 100,
   489  			ModuleParams: map[string]interface{}{
   490  				"nearCustomText": extractNearCustomTextParam(map[string]interface{}{
   491  					"concepts": []interface{}{"a search term", "another"},
   492  					"moveTo": map[string]interface{}{
   493  						"concepts": []interface{}{"foo"},
   494  						"force":    float64(0.7),
   495  					},
   496  					"moveAwayFrom": map[string]interface{}{
   497  						"concepts": []interface{}{"bar"},
   498  						"force":    float64(0.7),
   499  					},
   500  				}),
   501  			},
   502  		}
   503  		vectorSearcher.results = []search.Result{
   504  			{
   505  				ClassName: "BestClass",
   506  				ID:        "123-456-789",
   507  				Certainty: 0.5,
   508  				Dist:      0.5,
   509  				Dims:      128,
   510  			},
   511  			{
   512  				ClassName: "AnAction",
   513  				ID:        "987-654-321",
   514  				Certainty: 0.5,
   515  				Dist:      0.5,
   516  				Dims:      128,
   517  			},
   518  		}
   519  
   520  		metrics.On("AddUsageDimensions", "n/a", "explore_graphql", "nearCustomText", 128)
   521  		res, err := traverser.Explore(context.Background(), nil, params)
   522  		require.Nil(t, err)
   523  		assert.Equal(t, []search.Result{
   524  			{
   525  				ClassName: "BestClass",
   526  				ID:        "123-456-789",
   527  				Beacon:    "weaviate://localhost/BestClass/123-456-789",
   528  				Certainty: 0.5,
   529  				Dist:      0.5,
   530  				Dims:      128,
   531  			},
   532  			{
   533  				ClassName: "AnAction",
   534  				ID:        "987-654-321",
   535  				Beacon:    "weaviate://localhost/AnAction/987-654-321",
   536  				Certainty: 0.5,
   537  				Dist:      0.5,
   538  				Dims:      128,
   539  			},
   540  		}, res)
   541  
   542  		// see dummy implementation of MoveTo and MoveAway for why the vector should
   543  		// be the way it is
   544  		assert.Equal(t, []float32{1.5, 2.5, 3.5}, vectorSearcher.calledWithVector)
   545  		assert.Equal(t, 100, vectorSearcher.calledWithLimit,
   546  			"limit explicitly set")
   547  	})
   548  
   549  	t.Run("near text with movements and objects set", func(t *testing.T) {
   550  		authorizer := &fakeAuthorizer{}
   551  		locks := &fakeLocks{}
   552  		logger, _ := test.NewNullLogger()
   553  		vectorSearcher := &fakeVectorSearcher{}
   554  		log, _ := test.NewNullLogger()
   555  		metrics := &fakeMetrics{}
   556  		explorer := NewExplorer(vectorSearcher, log, getFakeModulesProvider(), metrics, defaultConfig)
   557  		schemaGetter := &fakeSchemaGetter{}
   558  		traverser := NewTraverser(&config.WeaviateConfig{}, locks, logger, authorizer,
   559  			vectorSearcher, explorer, schemaGetter, getFakeModulesProvider(), nil, -1)
   560  
   561  		params := ExploreParams{
   562  			Limit: 100,
   563  			ModuleParams: map[string]interface{}{
   564  				"nearCustomText": extractNearCustomTextParam(map[string]interface{}{
   565  					"concepts": []interface{}{"a search term", "another"},
   566  					"moveTo": map[string]interface{}{
   567  						"concepts": []interface{}{"foo"},
   568  						"force":    float64(0.7),
   569  						"objects": []interface{}{
   570  							map[string]interface{}{
   571  								"id": "e9c12c22-766f-4bde-b140-d4cf8fd6e041",
   572  							},
   573  						},
   574  					},
   575  					"moveAwayFrom": map[string]interface{}{
   576  						"concepts": []interface{}{"bar"},
   577  						"force":    float64(0.7),
   578  						"objects": []interface{}{
   579  							map[string]interface{}{
   580  								"id": "e9c12c22-766f-4bde-b140-d4cf8fd6e042",
   581  							},
   582  							map[string]interface{}{
   583  								"beacon": "weaviate://localhost/e9c12c22-766f-4bde-b140-d4cf8fd6e043",
   584  							},
   585  							map[string]interface{}{
   586  								"beacon": "weaviate://localhost/e9c12c22-766f-4bde-b140-d4cf8fd6e044",
   587  							},
   588  						},
   589  					},
   590  				}),
   591  			},
   592  		}
   593  		vectorSearcher.results = []search.Result{
   594  			{
   595  				ClassName: "BestClass",
   596  				ID:        "123-456-789",
   597  				Certainty: 0.5,
   598  				Dist:      0.5,
   599  				Dims:      128,
   600  			},
   601  			{
   602  				ClassName: "AnAction",
   603  				ID:        "987-654-321",
   604  				Certainty: 0.5,
   605  				Dist:      0.5,
   606  				Dims:      128,
   607  			},
   608  		}
   609  		searchRes1 := search.Result{
   610  			ClassName: "BestClass",
   611  			ID:        "e9c12c22-766f-4bde-b140-d4cf8fd6e041",
   612  			Dims:      128,
   613  		}
   614  		searchRes2 := search.Result{
   615  			ClassName: "BestClass",
   616  			ID:        "e9c12c22-766f-4bde-b140-d4cf8fd6e042",
   617  			Dims:      128,
   618  		}
   619  		searchRes3 := search.Result{
   620  			ClassName: "BestClass",
   621  			ID:        "e9c12c22-766f-4bde-b140-d4cf8fd6e043",
   622  			Dims:      128,
   623  		}
   624  		searchRes4 := search.Result{
   625  			ClassName: "BestClass",
   626  			ID:        "e9c12c22-766f-4bde-b140-d4cf8fd6e044",
   627  			Dims:      128,
   628  		}
   629  
   630  		vectorSearcher.
   631  			On("ObjectByID", strfmt.UUID("e9c12c22-766f-4bde-b140-d4cf8fd6e041")).
   632  			Return(&searchRes1, nil)
   633  		vectorSearcher.
   634  			On("ObjectByID", strfmt.UUID("e9c12c22-766f-4bde-b140-d4cf8fd6e042")).
   635  			Return(&searchRes2, nil)
   636  		vectorSearcher.
   637  			On("ObjectByID", strfmt.UUID("e9c12c22-766f-4bde-b140-d4cf8fd6e043")).
   638  			Return(&searchRes3, nil)
   639  		vectorSearcher.
   640  			On("ObjectByID", strfmt.UUID("e9c12c22-766f-4bde-b140-d4cf8fd6e044")).
   641  			Return(&searchRes4, nil)
   642  
   643  		metrics.On("AddUsageDimensions", "n/a", "explore_graphql", "nearCustomText", 128)
   644  		res, err := traverser.Explore(context.Background(), nil, params)
   645  		require.Nil(t, err)
   646  		assert.Equal(t, []search.Result{
   647  			{
   648  				ClassName: "BestClass",
   649  				ID:        "123-456-789",
   650  				Beacon:    "weaviate://localhost/BestClass/123-456-789",
   651  				Certainty: 0.5,
   652  				Dist:      0.5,
   653  				Dims:      128,
   654  			},
   655  			{
   656  				ClassName: "AnAction",
   657  				ID:        "987-654-321",
   658  				Beacon:    "weaviate://localhost/AnAction/987-654-321",
   659  				Certainty: 0.5,
   660  				Dist:      0.5,
   661  				Dims:      128,
   662  			},
   663  		}, res)
   664  
   665  		// see dummy implementation of MoveTo and MoveAway for why the vector should
   666  		// be the way it is
   667  		assert.Equal(t, []float32{1.5, 2.5, 3.5}, vectorSearcher.calledWithVector)
   668  		assert.Equal(t, 100, vectorSearcher.calledWithLimit,
   669  			"limit explicitly set")
   670  	})
   671  }