Spaces:
Sleeping
Sleeping
| // _ _ | |
| // __ _____ __ ___ ___ __ _| |_ ___ | |
| // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ | |
| // \ V V / __/ (_| |\ V /| | (_| | || __/ | |
| // \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| | |
| // | |
| // Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. | |
| // | |
| // CONTACT: [email protected] | |
| // | |
| package modcontextionary | |
| import ( | |
| "testing" | |
| "github.com/stretchr/testify/assert" | |
| "github.com/stretchr/testify/require" | |
| "github.com/tailor-inc/graphql/language/ast" | |
| "github.com/weaviate/weaviate/entities/additional" | |
| "github.com/weaviate/weaviate/entities/dto" | |
| "github.com/weaviate/weaviate/entities/filters" | |
| "github.com/weaviate/weaviate/entities/search" | |
| "github.com/weaviate/weaviate/modules/text2vec-contextionary/additional/models" | |
| helper "github.com/weaviate/weaviate/test/helper" | |
| "github.com/weaviate/weaviate/usecases/traverser" | |
| ) | |
| type testCase struct { | |
| name string | |
| query string | |
| expectedParamsToTraverser traverser.ExploreParams | |
| resolverReturn []search.Result | |
| expectedResults []result | |
| } | |
| type testCases []testCase | |
| type result struct { | |
| pathToField []string | |
| expectedValue interface{} | |
| } | |
| func TestExtractAdditionalFields(t *testing.T) { | |
| // We don't need to explicitly test every subselection as we did on | |
| // phoneNumber as these fields have fixed keys. So we can simply check for | |
| // the prop | |
| type test struct { | |
| name string | |
| query string | |
| expectedParams dto.GetParams | |
| resolverReturn interface{} | |
| expectedResult interface{} | |
| } | |
| tests := []test{ | |
| { | |
| name: "with _additional certainty", | |
| query: "{ Get { SomeAction { _additional { certainty distance } } } }", | |
| expectedParams: dto.GetParams{ | |
| ClassName: "SomeAction", | |
| AdditionalProperties: additional.Properties{ | |
| Certainty: true, | |
| Distance: true, | |
| }, | |
| }, | |
| resolverReturn: []interface{}{ | |
| map[string]interface{}{ | |
| "_additional": map[string]interface{}{ | |
| "certainty": 0.69, | |
| "distance": helper.CertaintyToDist(t, 0.69), | |
| }, | |
| }, | |
| }, | |
| expectedResult: map[string]interface{}{ | |
| "_additional": map[string]interface{}{ | |
| "certainty": 0.69, | |
| "distance": helper.CertaintyToDist(t, 0.69), | |
| }, | |
| }, | |
| }, | |
| { | |
| name: "with _additional interpretation", | |
| query: "{ Get { SomeAction { _additional { interpretation { source { concept weight occurrence } } } } } }", | |
| expectedParams: dto.GetParams{ | |
| ClassName: "SomeAction", | |
| AdditionalProperties: additional.Properties{ | |
| ModuleParams: map[string]interface{}{ | |
| "interpretation": true, | |
| }, | |
| }, | |
| }, | |
| resolverReturn: []interface{}{ | |
| map[string]interface{}{ | |
| "_additional": map[string]interface{}{ | |
| "interpretation": &models.Interpretation{ | |
| Source: []*models.InterpretationSource{ | |
| { | |
| Concept: "foo", | |
| Weight: 0.6, | |
| Occurrence: 1200, | |
| }, | |
| { | |
| Concept: "bar", | |
| Weight: 0.9, | |
| Occurrence: 800, | |
| }, | |
| }, | |
| }, | |
| }, | |
| }, | |
| }, | |
| expectedResult: map[string]interface{}{ | |
| "_additional": map[string]interface{}{ | |
| "interpretation": map[string]interface{}{ | |
| "source": []interface{}{ | |
| map[string]interface{}{ | |
| "concept": "foo", | |
| "weight": 0.6, | |
| "occurrence": 1200, | |
| }, | |
| map[string]interface{}{ | |
| "concept": "bar", | |
| "weight": 0.9, | |
| "occurrence": 800, | |
| }, | |
| }, | |
| }, | |
| }, | |
| }, | |
| }, | |
| { | |
| name: "with _additional nearestNeighbors", | |
| query: "{ Get { SomeAction { _additional { nearestNeighbors { neighbors { concept distance } } } } } }", | |
| expectedParams: dto.GetParams{ | |
| ClassName: "SomeAction", | |
| AdditionalProperties: additional.Properties{ | |
| ModuleParams: map[string]interface{}{ | |
| "nearestNeighbors": true, | |
| }, | |
| }, | |
| }, | |
| resolverReturn: []interface{}{ | |
| map[string]interface{}{ | |
| "_additional": map[string]interface{}{ | |
| "nearestNeighbors": &models.NearestNeighbors{ | |
| Neighbors: []*models.NearestNeighbor{ | |
| { | |
| Concept: "foo", | |
| Distance: 0.1, | |
| }, | |
| { | |
| Concept: "bar", | |
| Distance: 0.2, | |
| }, | |
| }, | |
| }, | |
| }, | |
| }, | |
| }, | |
| expectedResult: map[string]interface{}{ | |
| "_additional": map[string]interface{}{ | |
| "nearestNeighbors": map[string]interface{}{ | |
| "neighbors": []interface{}{ | |
| map[string]interface{}{ | |
| "concept": "foo", | |
| "distance": float32(0.1), | |
| }, | |
| map[string]interface{}{ | |
| "concept": "bar", | |
| "distance": float32(0.2), | |
| }, | |
| }, | |
| }, | |
| }, | |
| }, | |
| }, | |
| { | |
| name: "with _additional featureProjection without any optional parameters", | |
| query: "{ Get { SomeAction { _additional { featureProjection { vector } } } } }", | |
| expectedParams: dto.GetParams{ | |
| ClassName: "SomeAction", | |
| AdditionalProperties: additional.Properties{ | |
| ModuleParams: map[string]interface{}{ | |
| "featureProjection": extractAdditionalParam("featureProjection", nil), | |
| }, | |
| }, | |
| }, | |
| resolverReturn: []interface{}{ | |
| map[string]interface{}{ | |
| "_additional": map[string]interface{}{ | |
| "featureProjection": &models.FeatureProjection{ | |
| Vector: []float32{0.0, 1.1, 2.2}, | |
| }, | |
| }, | |
| }, | |
| }, | |
| expectedResult: map[string]interface{}{ | |
| "_additional": map[string]interface{}{ | |
| "featureProjection": map[string]interface{}{ | |
| "vector": []interface{}{float32(0.0), float32(1.1), float32(2.2)}, | |
| }, | |
| }, | |
| }, | |
| }, | |
| { | |
| name: "with _additional featureProjection with optional parameters", | |
| query: `{ Get { SomeAction { _additional { featureProjection(algorithm: "tsne", dimensions: 3, learningRate: 15, iterations: 100, perplexity: 10) { vector } } } } }`, | |
| expectedParams: dto.GetParams{ | |
| ClassName: "SomeAction", | |
| AdditionalProperties: additional.Properties{ | |
| ModuleParams: map[string]interface{}{ | |
| "featureProjection": extractAdditionalParam("featureProjection", | |
| []*ast.Argument{ | |
| createArg("algorithm", "tsne"), | |
| createArg("dimensions", "3"), | |
| createArg("iterations", "100"), | |
| createArg("learningRate", "15"), | |
| createArg("perplexity", "10"), | |
| }, | |
| ), | |
| }, | |
| }, | |
| }, | |
| resolverReturn: []interface{}{ | |
| map[string]interface{}{ | |
| "_additional": map[string]interface{}{ | |
| "featureProjection": &models.FeatureProjection{ | |
| Vector: []float32{0.0, 1.1, 2.2}, | |
| }, | |
| }, | |
| }, | |
| }, | |
| expectedResult: map[string]interface{}{ | |
| "_additional": map[string]interface{}{ | |
| "featureProjection": map[string]interface{}{ | |
| "vector": []interface{}{float32(0.0), float32(1.1), float32(2.2)}, | |
| }, | |
| }, | |
| }, | |
| }, | |
| { | |
| name: "with _additional semanticPath set", | |
| query: `{ Get { SomeAction { _additional { semanticPath { path { concept distanceToQuery distanceToResult distanceToPrevious distanceToNext } } } } } }`, | |
| expectedParams: dto.GetParams{ | |
| ClassName: "SomeAction", | |
| AdditionalProperties: additional.Properties{ | |
| ModuleParams: map[string]interface{}{ | |
| "semanticPath": extractAdditionalParam("semanticPath", nil), | |
| }, | |
| }, | |
| }, | |
| resolverReturn: []interface{}{ | |
| map[string]interface{}{ | |
| "_additional": map[string]interface{}{ | |
| "semanticPath": &models.SemanticPath{ | |
| Path: []*models.SemanticPathElement{ | |
| { | |
| Concept: "foo", | |
| DistanceToNext: ptFloat32(0.5), | |
| DistanceToPrevious: nil, | |
| DistanceToQuery: 0.1, | |
| DistanceToResult: 0.1, | |
| }, | |
| { | |
| Concept: "bar", | |
| DistanceToPrevious: ptFloat32(0.5), | |
| DistanceToNext: nil, | |
| DistanceToQuery: 0.1, | |
| DistanceToResult: 0.1, | |
| }, | |
| }, | |
| }, | |
| }, | |
| }, | |
| }, | |
| expectedResult: map[string]interface{}{ | |
| "_additional": map[string]interface{}{ | |
| "semanticPath": map[string]interface{}{ | |
| "path": []interface{}{ | |
| map[string]interface{}{ | |
| "concept": "foo", | |
| "distanceToNext": float32(0.5), | |
| "distanceToPrevious": nil, | |
| "distanceToQuery": float32(0.1), | |
| "distanceToResult": float32(0.1), | |
| }, | |
| map[string]interface{}{ | |
| "concept": "bar", | |
| "distanceToPrevious": float32(0.5), | |
| "distanceToNext": nil, | |
| "distanceToQuery": float32(0.1), | |
| "distanceToResult": float32(0.1), | |
| }, | |
| }, | |
| }, | |
| }, | |
| }, | |
| }, | |
| } | |
| for _, test := range tests { | |
| t.Run(test.name, func(t *testing.T) { | |
| resolver := newMockResolver() | |
| resolver.On("GetClass", test.expectedParams). | |
| Return(test.resolverReturn, nil).Once() | |
| result := resolver.AssertResolve(t, test.query) | |
| assert.Equal(t, test.expectedResult, result.Get("Get", "SomeAction").Result.([]interface{})[0]) | |
| }) | |
| } | |
| } | |
| func TestNearTextRanker(t *testing.T) { | |
| t.Parallel() | |
| resolver := newMockResolver() | |
| t.Run("for actions", func(t *testing.T) { | |
| query := `{ Get { SomeAction(nearText: { | |
| concepts: ["c1", "c2", "c3"], | |
| moveTo: { | |
| concepts:["positive"], | |
| force: 0.5 | |
| }, | |
| moveAwayFrom: { | |
| concepts:["epic"], | |
| force: 0.25 | |
| } | |
| }) { intField } } }` | |
| expectedParams := dto.GetParams{ | |
| ClassName: "SomeAction", | |
| Properties: []search.SelectProperty{{Name: "intField", IsPrimitive: true}}, | |
| ModuleParams: map[string]interface{}{ | |
| "nearText": extractNearTextParam(map[string]interface{}{ | |
| "concepts": []interface{}{"c1", "c2", "c3"}, | |
| "moveTo": map[string]interface{}{ | |
| "concepts": []interface{}{"positive"}, | |
| "force": float64(0.5), | |
| }, | |
| "moveAwayFrom": map[string]interface{}{ | |
| "concepts": []interface{}{"epic"}, | |
| "force": float64(0.25), | |
| }, | |
| }), | |
| }, | |
| } | |
| resolver.On("GetClass", expectedParams). | |
| Return([]interface{}{}, nil).Once() | |
| resolver.AssertResolve(t, query) | |
| }) | |
| t.Run("for a class that does not have a text2vec module", func(t *testing.T) { | |
| query := `{ Get { CustomVectorClass(nearText: { | |
| concepts: ["c1", "c2", "c3"], | |
| moveTo: { | |
| concepts:["positive"], | |
| force: 0.5 | |
| }, | |
| moveAwayFrom: { | |
| concepts:["epic"], | |
| force: 0.25 | |
| } | |
| }) { intField } } }` | |
| res := resolver.Resolve(query) | |
| require.Len(t, res.Errors, 1) | |
| assert.Contains(t, res.Errors[0].Message, "Unknown argument \"nearText\" on field \"CustomVectorClass\"") | |
| }) | |
| t.Run("for things with optional distance set", func(t *testing.T) { | |
| query := `{ Get { SomeThing(nearText: { | |
| concepts: ["c1", "c2", "c3"], | |
| distance: 0.6, | |
| moveTo: { | |
| concepts:["positive"], | |
| force: 0.5 | |
| }, | |
| moveAwayFrom: { | |
| concepts:["epic"], | |
| force: 0.25 | |
| } | |
| }) { intField } } }` | |
| expectedParams := dto.GetParams{ | |
| ClassName: "SomeThing", | |
| Properties: []search.SelectProperty{{Name: "intField", IsPrimitive: true}}, | |
| Pagination: &filters.Pagination{Limit: filters.LimitFlagSearchByDist}, | |
| ModuleParams: map[string]interface{}{ | |
| "nearText": extractNearTextParam(map[string]interface{}{ | |
| "concepts": []interface{}{"c1", "c2", "c3"}, | |
| "distance": float64(0.6), | |
| "moveTo": map[string]interface{}{ | |
| "concepts": []interface{}{"positive"}, | |
| "force": float64(0.5), | |
| }, | |
| "moveAwayFrom": map[string]interface{}{ | |
| "concepts": []interface{}{"epic"}, | |
| "force": float64(0.25), | |
| }, | |
| }), | |
| }, | |
| } | |
| resolver.On("GetClass", expectedParams). | |
| Return([]interface{}{}, nil).Once() | |
| resolver.AssertResolve(t, query) | |
| }) | |
| t.Run("for things with optional certainty set", func(t *testing.T) { | |
| query := `{ Get { SomeThing(nearText: { | |
| concepts: ["c1", "c2", "c3"], | |
| certainty: 0.4, | |
| moveTo: { | |
| concepts:["positive"], | |
| force: 0.5 | |
| }, | |
| moveAwayFrom: { | |
| concepts:["epic"], | |
| force: 0.25 | |
| } | |
| }) { intField } } }` | |
| expectedParams := dto.GetParams{ | |
| ClassName: "SomeThing", | |
| Properties: []search.SelectProperty{{Name: "intField", IsPrimitive: true}}, | |
| Pagination: &filters.Pagination{Limit: filters.LimitFlagSearchByDist}, | |
| ModuleParams: map[string]interface{}{ | |
| "nearText": extractNearTextParam(map[string]interface{}{ | |
| "concepts": []interface{}{"c1", "c2", "c3"}, | |
| "certainty": float64(0.4), | |
| "moveTo": map[string]interface{}{ | |
| "concepts": []interface{}{"positive"}, | |
| "force": float64(0.5), | |
| }, | |
| "moveAwayFrom": map[string]interface{}{ | |
| "concepts": []interface{}{"epic"}, | |
| "force": float64(0.25), | |
| }, | |
| }), | |
| }, | |
| } | |
| resolver.On("GetClass", expectedParams). | |
| Return([]interface{}{}, nil).Once() | |
| resolver.AssertResolve(t, query) | |
| }) | |
| t.Run("for things with optional distance and objects set", func(t *testing.T) { | |
| query := `{ Get { SomeThing(nearText: { | |
| concepts: ["c1", "c2", "c3"], | |
| distance: 0.4, | |
| moveTo: { | |
| concepts:["positive"], | |
| force: 0.5 | |
| objects: [ | |
| { id: "moveTo-uuid1" } | |
| { beacon: "weaviate://localhost/moveTo-uuid3" } | |
| ] | |
| }, | |
| moveAwayFrom: { | |
| concepts:["epic"], | |
| force: 0.25 | |
| objects: [ | |
| { id: "moveAway-uuid1" } | |
| { beacon: "weaviate://localhost/moveAway-uuid2" } | |
| { beacon: "weaviate://localhost/moveAway-uuid3" } | |
| ] | |
| } | |
| }) { intField } } }` | |
| expectedParams := dto.GetParams{ | |
| ClassName: "SomeThing", | |
| Properties: []search.SelectProperty{{Name: "intField", IsPrimitive: true}}, | |
| Pagination: &filters.Pagination{Limit: filters.LimitFlagSearchByDist}, | |
| ModuleParams: map[string]interface{}{ | |
| "nearText": extractNearTextParam(map[string]interface{}{ | |
| "concepts": []interface{}{"c1", "c2", "c3"}, | |
| "distance": float64(0.4), | |
| "moveTo": map[string]interface{}{ | |
| "concepts": []interface{}{"positive"}, | |
| "force": float64(0.5), | |
| "objects": []interface{}{ | |
| map[string]interface{}{ | |
| "id": "moveTo-uuid1", | |
| }, | |
| map[string]interface{}{ | |
| "beacon": "weaviate://localhost/moveTo-uuid3", | |
| }, | |
| }, | |
| }, | |
| "moveAwayFrom": map[string]interface{}{ | |
| "concepts": []interface{}{"epic"}, | |
| "force": float64(0.25), | |
| "objects": []interface{}{ | |
| map[string]interface{}{ | |
| "id": "moveAway-uuid1", | |
| }, | |
| map[string]interface{}{ | |
| "beacon": "weaviate://localhost/moveAway-uuid2", | |
| }, | |
| map[string]interface{}{ | |
| "beacon": "weaviate://localhost/moveAway-uuid3", | |
| }, | |
| }, | |
| }, | |
| }), | |
| }, | |
| } | |
| resolver.On("GetClass", expectedParams). | |
| Return([]interface{}{}, nil).Once() | |
| resolver.AssertResolve(t, query) | |
| }) | |
| t.Run("for things with optional certainty and objects set", func(t *testing.T) { | |
| query := `{ Get { SomeThing(nearText: { | |
| concepts: ["c1", "c2", "c3"], | |
| certainty: 0.4, | |
| moveTo: { | |
| concepts:["positive"], | |
| force: 0.5 | |
| objects: [ | |
| { id: "moveTo-uuid1" } | |
| { beacon: "weaviate://localhost/moveTo-uuid3" } | |
| ] | |
| }, | |
| moveAwayFrom: { | |
| concepts:["epic"], | |
| force: 0.25 | |
| objects: [ | |
| { id: "moveAway-uuid1" } | |
| { beacon: "weaviate://localhost/moveAway-uuid2" } | |
| { beacon: "weaviate://localhost/moveAway-uuid3" } | |
| ] | |
| } | |
| }) { intField } } }` | |
| expectedParams := dto.GetParams{ | |
| ClassName: "SomeThing", | |
| Properties: []search.SelectProperty{{Name: "intField", IsPrimitive: true}}, | |
| Pagination: &filters.Pagination{Limit: filters.LimitFlagSearchByDist}, | |
| ModuleParams: map[string]interface{}{ | |
| "nearText": extractNearTextParam(map[string]interface{}{ | |
| "concepts": []interface{}{"c1", "c2", "c3"}, | |
| "certainty": float64(0.4), | |
| "moveTo": map[string]interface{}{ | |
| "concepts": []interface{}{"positive"}, | |
| "force": float64(0.5), | |
| "objects": []interface{}{ | |
| map[string]interface{}{ | |
| "id": "moveTo-uuid1", | |
| }, | |
| map[string]interface{}{ | |
| "beacon": "weaviate://localhost/moveTo-uuid3", | |
| }, | |
| }, | |
| }, | |
| "moveAwayFrom": map[string]interface{}{ | |
| "concepts": []interface{}{"epic"}, | |
| "force": float64(0.25), | |
| "objects": []interface{}{ | |
| map[string]interface{}{ | |
| "id": "moveAway-uuid1", | |
| }, | |
| map[string]interface{}{ | |
| "beacon": "weaviate://localhost/moveAway-uuid2", | |
| }, | |
| map[string]interface{}{ | |
| "beacon": "weaviate://localhost/moveAway-uuid3", | |
| }, | |
| }, | |
| }, | |
| }), | |
| }, | |
| } | |
| resolver.On("GetClass", expectedParams). | |
| Return([]interface{}{}, nil).Once() | |
| resolver.AssertResolve(t, query) | |
| }) | |
| } | |
| func Test_ResolveExplore(t *testing.T) { | |
| t.Parallel() | |
| testsNearText := testCases{ | |
| testCase{ | |
| name: "Resolve Explore with nearText", | |
| query: ` | |
| { | |
| Explore(nearText: {concepts: ["car", "best brand"]}) { | |
| beacon className certainty distance | |
| } | |
| }`, | |
| expectedParamsToTraverser: traverser.ExploreParams{ | |
| ModuleParams: map[string]interface{}{ | |
| "nearText": extractNearTextParam(map[string]interface{}{ | |
| "concepts": []interface{}{"car", "best brand"}, | |
| }), | |
| }, | |
| WithCertaintyProp: true, | |
| }, | |
| resolverReturn: []search.Result{ | |
| { | |
| Beacon: "weaviate://localhost/some-uuid", | |
| ClassName: "bestClass", | |
| Certainty: 0.7, | |
| Dist: helper.CertaintyToDist(t, 0.7), | |
| }, | |
| }, | |
| expectedResults: []result{{ | |
| pathToField: []string{"Explore"}, | |
| expectedValue: []interface{}{ | |
| map[string]interface{}{ | |
| "beacon": "weaviate://localhost/some-uuid", | |
| "className": "bestClass", | |
| "certainty": float32(0.7), | |
| "distance": helper.CertaintyToDist(t, 0.7), | |
| }, | |
| }, | |
| }}, | |
| }, | |
| testCase{ | |
| name: "with nearText with optional limit and distance set", | |
| query: ` | |
| { | |
| Explore( | |
| nearText: {concepts: ["car", "best brand"], distance: 0.6}, limit: 17 | |
| ){ | |
| beacon className | |
| } | |
| }`, | |
| expectedParamsToTraverser: traverser.ExploreParams{ | |
| ModuleParams: map[string]interface{}{ | |
| "nearText": extractNearTextParam(map[string]interface{}{ | |
| "concepts": []interface{}{"car", "best brand"}, | |
| "distance": float64(0.6), | |
| }), | |
| }, | |
| Limit: 17, | |
| }, | |
| resolverReturn: []search.Result{ | |
| { | |
| Beacon: "weaviate://localhost/some-uuid", | |
| ClassName: "bestClass", | |
| Dist: 0.6, | |
| }, | |
| }, | |
| expectedResults: []result{{ | |
| pathToField: []string{"Explore"}, | |
| expectedValue: []interface{}{ | |
| map[string]interface{}{ | |
| "beacon": "weaviate://localhost/some-uuid", | |
| "className": "bestClass", | |
| }, | |
| }, | |
| }}, | |
| }, | |
| testCase{ | |
| name: "with nearText with optional limit and certainty set", | |
| query: ` | |
| { | |
| Explore( | |
| nearText: {concepts: ["car", "best brand"], certainty: 0.6}, limit: 17 | |
| ){ | |
| beacon className | |
| } | |
| }`, | |
| expectedParamsToTraverser: traverser.ExploreParams{ | |
| ModuleParams: map[string]interface{}{ | |
| "nearText": extractNearTextParam(map[string]interface{}{ | |
| "concepts": []interface{}{"car", "best brand"}, | |
| "certainty": float64(0.6), | |
| }), | |
| }, | |
| Limit: 17, | |
| }, | |
| resolverReturn: []search.Result{ | |
| { | |
| Beacon: "weaviate://localhost/some-uuid", | |
| ClassName: "bestClass", | |
| }, | |
| }, | |
| expectedResults: []result{{ | |
| pathToField: []string{"Explore"}, | |
| expectedValue: []interface{}{ | |
| map[string]interface{}{ | |
| "beacon": "weaviate://localhost/some-uuid", | |
| "className": "bestClass", | |
| }, | |
| }, | |
| }}, | |
| }, | |
| testCase{ | |
| name: "with moveTo set", | |
| query: ` | |
| { | |
| Explore( | |
| limit: 17 | |
| nearText: { | |
| concepts: ["car", "best brand"] | |
| moveTo: { | |
| concepts: ["mercedes"] | |
| force: 0.7 | |
| } | |
| } | |
| ) { | |
| beacon className | |
| } | |
| }`, | |
| expectedParamsToTraverser: traverser.ExploreParams{ | |
| Limit: 17, | |
| ModuleParams: map[string]interface{}{ | |
| "nearText": extractNearTextParam(map[string]interface{}{ | |
| "concepts": []interface{}{"car", "best brand"}, | |
| "moveTo": map[string]interface{}{ | |
| "concepts": []interface{}{"mercedes"}, | |
| "force": float64(0.7), | |
| }, | |
| }), | |
| }, | |
| }, | |
| resolverReturn: []search.Result{ | |
| { | |
| Beacon: "weaviate://localhost/some-uuid", | |
| ClassName: "bestClass", | |
| }, | |
| }, | |
| expectedResults: []result{{ | |
| pathToField: []string{"Explore"}, | |
| expectedValue: []interface{}{ | |
| map[string]interface{}{ | |
| "beacon": "weaviate://localhost/some-uuid", | |
| "className": "bestClass", | |
| }, | |
| }, | |
| }}, | |
| }, | |
| testCase{ | |
| name: "with moveTo and moveAwayFrom set", | |
| query: ` | |
| { | |
| Explore( | |
| limit: 17 | |
| nearText: { | |
| concepts: ["car", "best brand"] | |
| moveTo: { | |
| concepts: ["mercedes"] | |
| force: 0.7 | |
| } | |
| moveAwayFrom: { | |
| concepts: ["van"] | |
| force: 0.7 | |
| } | |
| } | |
| ) { | |
| beacon className | |
| } | |
| }`, | |
| expectedParamsToTraverser: traverser.ExploreParams{ | |
| Limit: 17, | |
| ModuleParams: map[string]interface{}{ | |
| "nearText": extractNearTextParam(map[string]interface{}{ | |
| "concepts": []interface{}{"car", "best brand"}, | |
| "moveTo": map[string]interface{}{ | |
| "concepts": []interface{}{"mercedes"}, | |
| "force": float64(0.7), | |
| }, | |
| "moveAwayFrom": map[string]interface{}{ | |
| "concepts": []interface{}{"van"}, | |
| "force": float64(0.7), | |
| }, | |
| }), | |
| }, | |
| }, | |
| resolverReturn: []search.Result{ | |
| { | |
| Beacon: "weaviate://localhost/some-uuid", | |
| ClassName: "bestClass", | |
| }, | |
| }, | |
| expectedResults: []result{{ | |
| pathToField: []string{"Explore"}, | |
| expectedValue: []interface{}{ | |
| map[string]interface{}{ | |
| "beacon": "weaviate://localhost/some-uuid", | |
| "className": "bestClass", | |
| }, | |
| }, | |
| }}, | |
| }, | |
| testCase{ | |
| name: "with moveTo and objects set", | |
| query: ` | |
| { | |
| Explore( | |
| limit: 17 | |
| nearText: { | |
| concepts: ["car", "best brand"] | |
| moveTo: { | |
| concepts: ["mercedes"] | |
| force: 0.7 | |
| objects: [ | |
| {id: "moveto-uuid"}, | |
| {beacon: "weaviate://localhost/other-moveto-uuid"}, | |
| ] | |
| } | |
| } | |
| ) { | |
| beacon className | |
| } | |
| }`, | |
| expectedParamsToTraverser: traverser.ExploreParams{ | |
| Limit: 17, | |
| ModuleParams: map[string]interface{}{ | |
| "nearText": extractNearTextParam(map[string]interface{}{ | |
| "concepts": []interface{}{"car", "best brand"}, | |
| "moveTo": map[string]interface{}{ | |
| "concepts": []interface{}{"mercedes"}, | |
| "force": float64(0.7), | |
| "objects": []interface{}{ | |
| map[string]interface{}{ | |
| "id": "moveto-uuid", | |
| }, | |
| map[string]interface{}{ | |
| "beacon": "weaviate://localhost/other-moveto-uuid", | |
| }, | |
| }, | |
| }, | |
| }), | |
| }, | |
| }, | |
| resolverReturn: []search.Result{ | |
| { | |
| Beacon: "weaviate://localhost/some-uuid", | |
| ClassName: "bestClass", | |
| }, | |
| }, | |
| expectedResults: []result{{ | |
| pathToField: []string{"Explore"}, | |
| expectedValue: []interface{}{ | |
| map[string]interface{}{ | |
| "beacon": "weaviate://localhost/some-uuid", | |
| "className": "bestClass", | |
| }, | |
| }, | |
| }}, | |
| }, | |
| testCase{ | |
| name: "with moveTo and moveAwayFrom and objects set", | |
| query: ` | |
| { | |
| Explore( | |
| limit: 17 | |
| nearText: { | |
| concepts: ["car", "best brand"] | |
| moveTo: { | |
| concepts: ["mercedes"] | |
| force: 0.7 | |
| objects: [ | |
| {id: "moveto-uuid1"}, | |
| {beacon: "weaviate://localhost/moveto-uuid2"}, | |
| ] | |
| } | |
| moveAwayFrom: { | |
| concepts: ["van"] | |
| force: 0.7 | |
| objects: [ | |
| {id: "moveAway-uuid1"}, | |
| {beacon: "weaviate://localhost/moveAway-uuid2"}, | |
| {id: "moveAway-uuid3"}, | |
| {id: "moveAway-uuid4"}, | |
| ] | |
| } | |
| } | |
| ) { | |
| beacon className | |
| } | |
| }`, | |
| expectedParamsToTraverser: traverser.ExploreParams{ | |
| Limit: 17, | |
| ModuleParams: map[string]interface{}{ | |
| "nearText": extractNearTextParam(map[string]interface{}{ | |
| "concepts": []interface{}{"car", "best brand"}, | |
| "moveTo": map[string]interface{}{ | |
| "concepts": []interface{}{"mercedes"}, | |
| "force": float64(0.7), | |
| "objects": []interface{}{ | |
| map[string]interface{}{ | |
| "id": "moveto-uuid1", | |
| }, | |
| map[string]interface{}{ | |
| "beacon": "weaviate://localhost/moveto-uuid2", | |
| }, | |
| }, | |
| }, | |
| "moveAwayFrom": map[string]interface{}{ | |
| "concepts": []interface{}{"van"}, | |
| "force": float64(0.7), | |
| "objects": []interface{}{ | |
| map[string]interface{}{ | |
| "id": "moveAway-uuid1", | |
| }, | |
| map[string]interface{}{ | |
| "beacon": "weaviate://localhost/moveAway-uuid2", | |
| }, | |
| map[string]interface{}{ | |
| "id": "moveAway-uuid3", | |
| }, | |
| map[string]interface{}{ | |
| "id": "moveAway-uuid4", | |
| }, | |
| }, | |
| }, | |
| }), | |
| }, | |
| }, | |
| resolverReturn: []search.Result{ | |
| { | |
| Beacon: "weaviate://localhost/some-uuid", | |
| ClassName: "bestClass", | |
| }, | |
| }, | |
| expectedResults: []result{{ | |
| pathToField: []string{"Explore"}, | |
| expectedValue: []interface{}{ | |
| map[string]interface{}{ | |
| "beacon": "weaviate://localhost/some-uuid", | |
| "className": "bestClass", | |
| }, | |
| }, | |
| }}, | |
| }, | |
| } | |
| testsNearText.AssertExtraction(t, newExploreMockResolver()) | |
| } | |
| func (tests testCases) AssertExtraction(t *testing.T, resolver *mockResolver) { | |
| for _, testCase := range tests { | |
| t.Run(testCase.name, func(t *testing.T) { | |
| resolver.On("Explore", testCase.expectedParamsToTraverser). | |
| Return(testCase.resolverReturn, nil).Once() | |
| result := resolver.AssertResolve(t, testCase.query) | |
| for _, expectedResult := range testCase.expectedResults { | |
| value := result.Get(expectedResult.pathToField...).Result | |
| assert.Equal(t, expectedResult.expectedValue, value) | |
| } | |
| }) | |
| } | |
| } | |
| func ptFloat32(in float32) *float32 { | |
| return &in | |
| } | |