github.com/weaviate/weaviate@v1.24.6/test/acceptance/graphql_resolvers/local_get_with_grouping_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 test
    13  
    14  import (
    15  	"strings"
    16  	"testing"
    17  
    18  	graphqlhelper "github.com/weaviate/weaviate/test/helper/graphql"
    19  
    20  	"github.com/stretchr/testify/assert"
    21  	"github.com/stretchr/testify/require"
    22  	"github.com/weaviate/weaviate/test/helper"
    23  )
    24  
    25  func gettingObjectsWithGrouping(t *testing.T) {
    26  	t.Run("without grouping <- this is the control", func(t *testing.T) {
    27  		query := `
    28  		{
    29  			Get {
    30  				Company {
    31  					name
    32  				}
    33  			}
    34  		}
    35  		`
    36  		result := graphqlhelper.AssertGraphQL(t, helper.RootAuth, query)
    37  		companies := result.Get("Get", "Company").AsSlice()
    38  
    39  		expected := []interface{}{
    40  			map[string]interface{}{"name": "Microsoft Inc."},
    41  			map[string]interface{}{"name": "Microsoft Incorporated"},
    42  			map[string]interface{}{"name": "Microsoft"},
    43  			map[string]interface{}{"name": "Apple Inc."},
    44  			map[string]interface{}{"name": "Apple Incorporated"},
    45  			map[string]interface{}{"name": "Apple"},
    46  			map[string]interface{}{"name": "Google Inc."},
    47  			map[string]interface{}{"name": "Google Incorporated"},
    48  			map[string]interface{}{"name": "Google"},
    49  		}
    50  
    51  		assert.ElementsMatch(t, expected, companies)
    52  	})
    53  
    54  	t.Run("grouping mode set to merge and force to 1.0", func(t *testing.T) {
    55  		query := `
    56  		{
    57  			Get {
    58  				Company(group: {type: merge, force:1.0}) {
    59  					name
    60  					inCity {
    61  						... on City {name}
    62  					}
    63  				}
    64  			}
    65  		}
    66  		`
    67  		result := graphqlhelper.AssertGraphQL(t, helper.RootAuth, query)
    68  		companies := result.Get("Get", "Company").AsSlice()
    69  
    70  		require.Len(t, companies, 1)
    71  
    72  		companyNames := companies[0].(map[string]interface{})["name"].(string)
    73  		assert.NotEmpty(t, companies)
    74  
    75  		mustContain := []string{"Apple", "Google", "Microsoft"}
    76  		for _, companyName := range mustContain {
    77  			if !strings.Contains(companyNames, companyName) {
    78  				t.Errorf("%s not contained in %v", companyName, companyNames)
    79  			}
    80  		}
    81  
    82  		companyCities := companies[0].(map[string]interface{})["inCity"].([]interface{})
    83  		expectedCities := []map[string]interface{}{
    84  			{"name": "Dusseldorf"},
    85  			{"name": "Amsterdam"},
    86  			{"name": "Berlin"},
    87  		}
    88  
    89  		assert.ElementsMatch(t, expectedCities, companyCities)
    90  	})
    91  
    92  	t.Run("grouping mode set to merge and force to 0.0", func(t *testing.T) {
    93  		query := `
    94  		{
    95  			Get {
    96  				Company(group: {type: merge, force:0.0}) {
    97  					name
    98  					inCity {
    99  						... on City {
   100  							name
   101  						}
   102  					}
   103  				}
   104  			}
   105  		}
   106  		`
   107  		result := graphqlhelper.AssertGraphQL(t, helper.RootAuth, query)
   108  		companies := result.Get("Get", "Company").AsSlice()
   109  
   110  		require.Len(t, companies, 9)
   111  
   112  		getName := func(value map[string]interface{}) string {
   113  			return value["name"].(string)
   114  		}
   115  
   116  		getCities := func(value map[string]interface{}) []string {
   117  			inCity := value["inCity"].([]interface{})
   118  			cities := make([]string, len(inCity))
   119  			for i := range inCity {
   120  				cityVal := inCity[i].(map[string]interface{})
   121  				cities[i] = getName(cityVal)
   122  			}
   123  			return cities
   124  		}
   125  
   126  		for _, current := range companies {
   127  			currentMap := current.(map[string]interface{})
   128  			if getName(currentMap) == "Microsoft Incorporated" {
   129  				assert.Len(t, getCities(currentMap), 2)
   130  			}
   131  			if getName(currentMap) == "Microsoft Inc." {
   132  				assert.Len(t, getCities(currentMap), 1)
   133  			}
   134  			if getName(currentMap) == "Microsoft" {
   135  				assert.Len(t, getCities(currentMap), 1)
   136  			}
   137  		}
   138  	})
   139  
   140  	t.Run("grouping mode set to closest and force to 0.1", func(t *testing.T) {
   141  		query := `
   142  			{
   143  				Get {
   144  					Company(group: {type: closest, force:0.1}) {
   145  						name
   146  						inCity {
   147  							... on City {
   148  								name
   149  							}
   150  						}
   151  					}
   152  				}
   153  			}
   154  			`
   155  		result := graphqlhelper.AssertGraphQL(t, helper.RootAuth, query)
   156  		companies := result.Get("Get", "Company").AsSlice()
   157  
   158  		assert.True(t, len(companies) > 0)
   159  	})
   160  
   161  	t.Run("grouping mode set to closest with near text", func(t *testing.T) {
   162  		query := `
   163  			{
   164  				Get {
   165  					Company(nearText: {concepts: "Apple"}, group: {type: closest, force:1.0}) {
   166  						name
   167  					}
   168  				}
   169  			}
   170  			`
   171  		result := graphqlhelper.AssertGraphQL(t, helper.RootAuth, query)
   172  		companies := result.Get("Get", "Company").AsSlice()
   173  
   174  		assert.True(t, len(companies) == 1)
   175  	})
   176  
   177  	t.Run("grouping with where filter", func(t *testing.T) {
   178  		query := `
   179  			{
   180  				Get {
   181  					Company(group:{type:merge force:1.0} where:{path:["id"] operator:Like valueText:"*"}) {
   182  						name
   183  						inCity {
   184  							... on City {
   185  								name
   186  							}
   187  						}
   188  					}
   189  				}
   190  			}
   191  		`
   192  
   193  		result := graphqlhelper.AssertGraphQL(t, helper.RootAuth, query)
   194  		grouped := result.Get("Get", "Company").AsSlice()
   195  		require.Len(t, grouped, 1)
   196  		groupedName := grouped[0].(map[string]interface{})["name"].(string)
   197  		assert.Equal(t, "Microsoft Inc. (Microsoft Incorporated, Microsoft, Apple Inc., "+
   198  			"Apple Incorporated, Apple, Google Inc., Google Incorporated, Google)",
   199  			groupedName)
   200  
   201  		companyCities := grouped[0].(map[string]interface{})["inCity"].([]interface{})
   202  		expectedCities := []map[string]interface{}{
   203  			{"name": "Dusseldorf"},
   204  			{"name": "Amsterdam"},
   205  			{"name": "Berlin"},
   206  		}
   207  
   208  		assert.ElementsMatch(t, expectedCities, companyCities)
   209  
   210  		// this query should yield the same results as the above, as the above where filter will
   211  		// match all records. checking the previous payload with the one below is a sanity check
   212  		// for the sake of validating the fix for [github issue 1958]
   213  		// (https://github.com/weaviate/weaviate/issues/1958)
   214  		// UPDATE: due to introducing roaring bitmaps as set holding docIDs of filtered documents
   215  		// internal order of results returned has changed from property value based to docID based,
   216  		// but set content remain unchanged
   217  		// for that reason grouped name in the following test is different with and without filters,
   218  		// though it still contains the same elements
   219  		queryWithoutWhere := `
   220  			{
   221  				Get {
   222  					Company(group:{type:merge force:1.0}) {
   223  						name
   224  						inCity {
   225  							... on City {
   226  								name
   227  							}
   228  						}
   229  					}
   230  				}
   231  			}
   232  		`
   233  		result = graphqlhelper.AssertGraphQL(t, helper.RootAuth, queryWithoutWhere)
   234  		groupedWithoutWhere := result.Get("Get", "Company").AsSlice()
   235  		groupedWithoutWhereName := groupedWithoutWhere[0].(map[string]interface{})["name"].(string)
   236  		assert.Equal(t, "Apple Inc. (Google Incorporated, Google Inc., Microsoft Incorporated, "+
   237  			"Apple, Apple Incorporated, Google, Microsoft Inc., Microsoft)",
   238  			groupedWithoutWhereName)
   239  
   240  		companyCities = groupedWithoutWhere[0].(map[string]interface{})["inCity"].([]interface{})
   241  		assert.ElementsMatch(t, expectedCities, companyCities)
   242  	})
   243  
   244  	t.Run("grouping with sort", func(t *testing.T) {
   245  		query := `
   246  			{
   247  				Get {
   248  					Company(group:{type:merge force:1.0} sort:{path:["name"]}) {
   249  						name
   250  						inCity {
   251  							... on City {
   252  								name
   253  							}
   254  						}
   255  					}
   256  				}
   257  			}
   258  		`
   259  
   260  		result := graphqlhelper.AssertGraphQL(t, helper.RootAuth, query)
   261  		grouped := result.Get("Get", "Company").AsSlice()
   262  		require.Len(t, grouped, 1)
   263  		groupedName := grouped[0].(map[string]interface{})["name"].(string)
   264  		assert.Equal(t, "Apple (Apple Inc., Apple Incorporated, Google, Google Inc., "+
   265  			"Google Incorporated, Microsoft, Microsoft Inc., Microsoft Incorporated)",
   266  			groupedName)
   267  
   268  		groupedCities := grouped[0].(map[string]interface{})["inCity"].([]interface{})
   269  		expectedCities := []map[string]interface{}{
   270  			{"name": "Dusseldorf"},
   271  			{"name": "Amsterdam"},
   272  			{"name": "Berlin"},
   273  		}
   274  
   275  		assert.ElementsMatch(t, expectedCities, groupedCities)
   276  	})
   277  
   278  	// temporarily removed due to
   279  	// https://github.com/weaviate/weaviate/issues/1302
   280  	// t.Run("grouping mode set to closest", func(t *testing.T) {
   281  	// 	query := `
   282  	// 	{
   283  	// 		Get {
   284  	// 			Company(group: {type: closest, force:0.10}) {
   285  	// 				name
   286  	// 			}
   287  	// 		}
   288  	// 	}
   289  	// 	`
   290  	// 	result := graphqlhelper.AssertGraphQL(t, helper.RootAuth, query)
   291  	// 	companies := result.Get("Get", "Company").AsSlice()
   292  
   293  	// 	assert.Len(t, companies, 3)
   294  	// 	mustContain := []string{"Apple", "Microsoft", "Google"}
   295  	// outer:
   296  	// 	for _, toContain := range mustContain {
   297  	// 		for _, current := range companies {
   298  	// 			if strings.Contains(current.(map[string]interface{})["name"].(string), toContain) {
   299  	// 				continue outer
   300  	// 			}
   301  	// 		}
   302  
   303  	// 		t.Errorf("%s not contained in %v", toContain, companies)
   304  	// 	}
   305  	// })
   306  
   307  	// ignore as 0.16.0 contextionaries aren't compatible with this test
   308  	// t.Run("grouping mode set to merge", func(t *testing.T) {
   309  	// 	query := `
   310  	// 	{
   311  	// 		Get {
   312  	// 				Company(group: {type: merge, force:0.1}) {
   313  	// 					name
   314  	// 					inCity {
   315  	// 					  ... on City {
   316  	// 						  name
   317  	// 						}
   318  	// 					}
   319  	// 				}
   320  	// 		}
   321  	// 	}
   322  	// 	`
   323  	// 	result := graphqlhelper.AssertGraphQL(t, helper.RootAuth, query)
   324  	// 	companies := result.Get("Get", "Company").AsSlice()
   325  
   326  	// 	assert.Len(t, companies, 3)
   327  	// 	mustContain := [][]string{
   328  	// 		[]string{"Apple", "Apple Inc.", "Apple Incorporated"},
   329  	// 		[]string{"Microsoft", "Microsoft Inc.", "Microsoft Incorporated"},
   330  	// 		[]string{"Google", "Google Inc.", "Google Incorporated"},
   331  	// 	}
   332  
   333  	// 	allContained := func(current map[string]interface{}, toContains []string) bool {
   334  	// 		for _, toContain := range toContains {
   335  	// 			if !strings.Contains(current["name"].(string), toContain) {
   336  	// 				return false
   337  	// 			}
   338  	// 		}
   339  	// 		return true
   340  	// 	}
   341  
   342  	// outer:
   343  	// 	for _, toContain := range mustContain {
   344  	// 		for _, current := range companies {
   345  	// 			if allContained(current.(map[string]interface{}), toContain) {
   346  	// 				continue outer
   347  	// 			}
   348  	// 		}
   349  
   350  	// 		t.Errorf("%s not contained in %v", toContain, companies)
   351  	// 	}
   352  	// })
   353  }