github.com/weaviate/weaviate@v1.24.6/adapters/repos/db/sorter/objects_sorter_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 sorter 13 14 import ( 15 "reflect" 16 "testing" 17 18 "github.com/stretchr/testify/require" 19 "github.com/weaviate/weaviate/entities/filters" 20 "github.com/weaviate/weaviate/entities/storobj" 21 ) 22 23 func TestObjectsSorter(t *testing.T) { 24 tests := []struct { 25 name string 26 sort []filters.Sort 27 limit int 28 wantObjs []*storobj.Object 29 wantDists []float32 30 }{ 31 { 32 name: "sort by string asc", 33 sort: sort1("name", "asc"), 34 limit: 3, 35 wantObjs: []*storobj.Object{cityAmsterdam, cityBerlin, cityNewYork, cityNil, cityNil2, cityWroclaw}, 36 wantDists: []float32{0.4, 0.2, 0.3, 0.0, 0.0, 0.1}, 37 }, 38 { 39 name: "sort by string desc", 40 sort: sort1("name", "desc"), 41 limit: 4, 42 wantObjs: []*storobj.Object{cityWroclaw, cityNil2, cityNil, cityNewYork, cityBerlin, cityAmsterdam}, 43 wantDists: []float32{0.1, 0.0, 0.0, 0.3, 0.2, 0.4}, 44 }, 45 { 46 name: "sort by text asc", 47 sort: sort1("country", "asc"), 48 limit: 5, 49 wantObjs: []*storobj.Object{cityNil2, cityNil, cityBerlin, cityWroclaw, cityAmsterdam, cityNewYork}, 50 wantDists: []float32{0.0, 0.0, 0.2, 0.1, 0.4, 0.3}, 51 }, 52 { 53 name: "sort by text desc", 54 sort: sort1("country", "desc"), 55 limit: 3, 56 wantObjs: []*storobj.Object{cityNewYork, cityAmsterdam, cityWroclaw, cityBerlin, cityNil2, cityNil}, 57 wantDists: []float32{0.3, 0.4, 0.1, 0.2, 0.0, 0.0}, 58 }, 59 { 60 name: "sort by int asc", 61 sort: sort1("population", "asc"), 62 limit: 4, 63 wantObjs: []*storobj.Object{cityNil2, cityNil, cityWroclaw, cityAmsterdam, cityBerlin, cityNewYork}, 64 wantDists: []float32{0.0, 0.0, 0.1, 0.4, 0.2, 0.3}, 65 }, 66 { 67 name: "sort by int desc", 68 sort: sort1("population", "desc"), 69 limit: 5, 70 wantObjs: []*storobj.Object{cityNewYork, cityBerlin, cityAmsterdam, cityWroclaw, cityNil2, cityNil}, 71 wantDists: []float32{0.3, 0.2, 0.4, 0.1, 0.0, 0.0}, 72 }, 73 { 74 name: "sort by number asc", 75 sort: sort1("cityArea", "asc"), 76 limit: 3, 77 wantObjs: []*storobj.Object{cityNil2, cityNil, cityAmsterdam, cityWroclaw, cityBerlin, cityNewYork}, 78 wantDists: []float32{0.0, 0.0, 0.4, 0.1, 0.2, 0.3}, 79 }, 80 { 81 name: "sort by number desc", 82 sort: sort1("cityArea", "desc"), 83 limit: 4, 84 wantObjs: []*storobj.Object{cityNewYork, cityBerlin, cityWroclaw, cityAmsterdam, cityNil2, cityNil}, 85 wantDists: []float32{0.3, 0.2, 0.1, 0.4, 0.0, 0.0}, 86 }, 87 { 88 name: "sort by date asc", 89 sort: sort1("cityRights", "asc"), 90 limit: 5, 91 wantObjs: []*storobj.Object{cityNil2, cityNil, cityAmsterdam, cityWroclaw, cityBerlin, cityNewYork}, 92 wantDists: []float32{0.0, 0.0, 0.4, 0.1, 0.2, 0.3}, 93 }, 94 { 95 name: "sort by date desc", 96 sort: sort1("cityRights", "desc"), 97 limit: 3, 98 wantObjs: []*storobj.Object{cityNewYork, cityBerlin, cityWroclaw, cityAmsterdam, cityNil2, cityNil}, 99 wantDists: []float32{0.3, 0.2, 0.1, 0.4, 0.0, 0.0}, 100 }, 101 { 102 name: "sort by string array asc", 103 sort: sort1("timezones", "asc"), 104 limit: 4, 105 wantObjs: []*storobj.Object{cityNil2, cityNil, cityWroclaw, cityBerlin, cityAmsterdam, cityNewYork}, 106 wantDists: []float32{0.0, 0.0, 0.1, 0.2, 0.4, 0.3}, 107 }, 108 { 109 name: "sort by string array desc", 110 sort: sort1("timezones", "desc"), 111 limit: 5, 112 wantObjs: []*storobj.Object{cityNewYork, cityWroclaw, cityBerlin, cityAmsterdam, cityNil2, cityNil}, 113 wantDists: []float32{0.3, 0.1, 0.2, 0.4, 0.0, 0.0}, 114 }, 115 { 116 name: "sort by text array asc", 117 sort: sort1("timezonesUTC", "asc"), 118 limit: 3, 119 wantObjs: []*storobj.Object{cityNil2, cityNil, cityWroclaw, cityBerlin, cityAmsterdam, cityNewYork}, 120 wantDists: []float32{0.0, 0.0, 0.1, 0.2, 0.4, 0.3}, 121 }, 122 { 123 name: "sort by text array desc", 124 sort: sort1("timezonesUTC", "desc"), 125 limit: 4, 126 wantObjs: []*storobj.Object{cityNewYork, cityWroclaw, cityBerlin, cityAmsterdam, cityNil2, cityNil}, 127 wantDists: []float32{0.3, 0.1, 0.2, 0.4, 0.0, 0.0}, 128 }, 129 { 130 name: "sort by bool asc", 131 sort: sort1("isCapital", "asc"), 132 limit: 5, 133 wantObjs: []*storobj.Object{cityNil2, cityNil, cityWroclaw, cityNewYork, cityBerlin, cityAmsterdam}, 134 wantDists: []float32{0.0, 0.0, 0.1, 0.3, 0.2, 0.4}, 135 }, 136 { 137 name: "sort by bool desc", 138 sort: sort1("isCapital", "desc"), 139 limit: 3, 140 wantObjs: []*storobj.Object{cityBerlin, cityAmsterdam, cityWroclaw, cityNewYork, cityNil2, cityNil}, 141 wantDists: []float32{0.2, 0.4, 0.1, 0.3, 0.0, 0.0}, 142 }, 143 { 144 name: "sort by bool array asc", 145 sort: sort1("isCapitalArray", "asc"), 146 limit: 4, 147 wantObjs: []*storobj.Object{cityNil2, cityNil, cityWroclaw, cityBerlin, cityAmsterdam, cityNewYork}, 148 wantDists: []float32{0.0, 0.0, 0.1, 0.2, 0.4, 0.3}, 149 }, 150 { 151 name: "sort by bool array desc", 152 sort: sort1("isCapitalArray", "desc"), 153 limit: 5, 154 wantObjs: []*storobj.Object{cityNewYork, cityAmsterdam, cityBerlin, cityWroclaw, cityNil2, cityNil}, 155 wantDists: []float32{0.3, 0.4, 0.2, 0.1, 0.0, 0.0}, 156 }, 157 { 158 name: "sort by number array asc", 159 sort: sort1("favoriteNumbers", "asc"), 160 limit: 3, 161 wantObjs: []*storobj.Object{cityNil2, cityNil, cityNewYork, cityWroclaw, cityBerlin, cityAmsterdam}, 162 wantDists: []float32{0.0, 0.0, 0.3, 0.1, 0.2, 0.4}, 163 }, 164 { 165 name: "sort by number array desc", 166 sort: sort1("favoriteNumbers", "desc"), 167 limit: 4, 168 wantObjs: []*storobj.Object{cityAmsterdam, cityBerlin, cityWroclaw, cityNewYork, cityNil2, cityNil}, 169 wantDists: []float32{0.4, 0.2, 0.1, 0.3, 0.0, 0.0}, 170 }, 171 { 172 name: "sort by int array asc", 173 sort: sort1("favoriteInts", "asc"), 174 limit: 5, 175 wantObjs: []*storobj.Object{cityNil2, cityNil, cityNewYork, cityWroclaw, cityBerlin, cityAmsterdam}, 176 wantDists: []float32{0.0, 0.0, 0.3, 0.1, 0.2, 0.4}, 177 }, 178 { 179 name: "sort by int array desc", 180 sort: sort1("favoriteInts", "desc"), 181 limit: 3, 182 wantObjs: []*storobj.Object{cityAmsterdam, cityBerlin, cityWroclaw, cityNewYork, cityNil2, cityNil}, 183 wantDists: []float32{0.4, 0.2, 0.1, 0.3, 0.0, 0.0}, 184 }, 185 { 186 name: "sort by date array asc", 187 sort: sort1("favoriteDates", "asc"), 188 limit: 4, 189 wantObjs: []*storobj.Object{cityNil2, cityNil, cityAmsterdam, cityWroclaw, cityBerlin, cityNewYork}, 190 wantDists: []float32{0.0, 0.0, 0.4, 0.1, 0.2, 0.3}, 191 }, 192 { 193 name: "sort by date array desc", 194 sort: sort1("favoriteDates", "desc"), 195 limit: 5, 196 wantObjs: []*storobj.Object{cityNewYork, cityBerlin, cityWroclaw, cityAmsterdam, cityNil2, cityNil}, 197 wantDists: []float32{0.3, 0.2, 0.1, 0.4, 0.0, 0.0}, 198 }, 199 { 200 name: "sort by phoneNumber asc", 201 sort: sort1("phoneNumber", "asc"), 202 limit: 3, 203 wantObjs: []*storobj.Object{cityNil2, cityNil, cityWroclaw, cityAmsterdam, cityNewYork, cityBerlin}, 204 wantDists: []float32{0.0, 0.0, 0.1, 0.4, 0.3, 0.2}, 205 }, 206 { 207 name: "sort by phoneNumber desc", 208 sort: sort1("phoneNumber", "desc"), 209 limit: 4, 210 wantObjs: []*storobj.Object{cityBerlin, cityNewYork, cityAmsterdam, cityWroclaw, cityNil2, cityNil}, 211 wantDists: []float32{0.2, 0.3, 0.4, 0.1, 0.0, 0.0}, 212 }, 213 { 214 name: "sort by location asc", 215 sort: sort1("location", "asc"), 216 limit: 5, 217 wantObjs: []*storobj.Object{cityNil2, cityNil, cityNewYork, cityAmsterdam, cityBerlin, cityWroclaw}, 218 wantDists: []float32{0.0, 0.0, 0.3, 0.4, 0.2, 0.1}, 219 }, 220 { 221 name: "sort by location desc", 222 sort: sort1("location", "desc"), 223 limit: 3, 224 wantObjs: []*storobj.Object{cityWroclaw, cityBerlin, cityAmsterdam, cityNewYork, cityNil2, cityNil}, 225 wantDists: []float32{0.1, 0.2, 0.4, 0.3, 0.0, 0.0}, 226 }, 227 { 228 name: "sort by special id property asc", 229 sort: sort1("id", "asc"), 230 limit: 4, 231 wantObjs: []*storobj.Object{cityAmsterdam, cityBerlin, cityNewYork, cityNil, cityNil2, cityWroclaw}, 232 wantDists: []float32{0.4, 0.2, 0.3, 0.0, 0.0, 0.1}, 233 }, 234 { 235 name: "sort by special id property desc", 236 sort: sort1("id", "desc"), 237 limit: 5, 238 wantObjs: []*storobj.Object{cityWroclaw, cityNil2, cityNil, cityNewYork, cityBerlin, cityAmsterdam}, 239 wantDists: []float32{0.1, 0.0, 0.0, 0.3, 0.2, 0.4}, 240 }, 241 { 242 name: "sort by special _id property asc", 243 sort: sort1("_id", "asc"), 244 limit: 3, 245 wantObjs: []*storobj.Object{cityAmsterdam, cityBerlin, cityNewYork, cityNil, cityNil2, cityWroclaw}, 246 wantDists: []float32{0.4, 0.2, 0.3, 0.0, 0.0, 0.1}, 247 }, 248 { 249 name: "sort by special _id property desc", 250 sort: sort1("_id", "desc"), 251 limit: 4, 252 wantObjs: []*storobj.Object{cityWroclaw, cityNil2, cityNil, cityNewYork, cityBerlin, cityAmsterdam}, 253 wantDists: []float32{0.1, 0.0, 0.0, 0.3, 0.2, 0.4}, 254 }, 255 { 256 name: "sort by special _creationTimeUnix property asc", 257 sort: sort1("_creationTimeUnix", "asc"), 258 limit: 5, 259 wantObjs: []*storobj.Object{cityAmsterdam, cityBerlin, cityNewYork, cityNil, cityNil2, cityWroclaw}, 260 wantDists: []float32{0.4, 0.2, 0.3, 0.0, 0.0, 0.1}, 261 }, 262 { 263 name: "sort by special _creationTimeUnix property desc", 264 sort: sort1("_creationTimeUnix", "desc"), 265 limit: 3, 266 wantObjs: []*storobj.Object{cityWroclaw, cityNil2, cityNil, cityNewYork, cityBerlin, cityAmsterdam}, 267 wantDists: []float32{0.1, 0.0, 0.0, 0.3, 0.2, 0.4}, 268 }, 269 { 270 name: "sort by special _lastUpdateTimeUnix property asc", 271 sort: sort1("_lastUpdateTimeUnix", "asc"), 272 limit: 4, 273 wantObjs: []*storobj.Object{cityAmsterdam, cityBerlin, cityNewYork, cityNil, cityNil2, cityWroclaw}, 274 wantDists: []float32{0.4, 0.2, 0.3, 0.0, 0.0, 0.1}, 275 }, 276 { 277 name: "sort by special _lastUpdateTimeUnix property desc", 278 sort: sort1("_lastUpdateTimeUnix", "desc"), 279 limit: 5, 280 wantObjs: []*storobj.Object{cityWroclaw, cityNil2, cityNil, cityNewYork, cityBerlin, cityAmsterdam}, 281 wantDists: []float32{0.1, 0.0, 0.0, 0.3, 0.2, 0.4}, 282 }, 283 { 284 name: "sort by isCapital asc & name asc", 285 sort: sort2("isCapital", "asc", "name", "asc"), 286 limit: 3, 287 wantObjs: []*storobj.Object{cityNil, cityNil2, cityNewYork, cityWroclaw, cityAmsterdam, cityBerlin}, 288 wantDists: []float32{0.0, 0.0, 0.3, 0.1, 0.4, 0.2}, 289 }, 290 { 291 name: "sort by isCapital desc & name asc", 292 sort: sort2("isCapital", "desc", "name", "asc"), 293 limit: 4, 294 wantObjs: []*storobj.Object{cityAmsterdam, cityBerlin, cityNewYork, cityWroclaw, cityNil, cityNil2}, 295 wantDists: []float32{0.4, 0.2, 0.3, 0.1, 0.0, 0.0}, 296 }, 297 { 298 name: "sort by timezones desc & name desc", 299 sort: sort2("timezones", "desc", "name", "desc"), 300 limit: 5, 301 wantObjs: []*storobj.Object{cityNewYork, cityWroclaw, cityBerlin, cityAmsterdam, cityNil2, cityNil}, 302 wantDists: []float32{0.3, 0.1, 0.2, 0.4, 0.0, 0.0}, 303 }, 304 { 305 name: "sort by timezones desc & name asc", 306 sort: sort2("timezones", "desc", "name", "asc"), 307 limit: 3, 308 wantObjs: []*storobj.Object{cityNewYork, cityAmsterdam, cityBerlin, cityWroclaw, cityNil, cityNil2}, 309 wantDists: []float32{0.3, 0.4, 0.2, 0.1, 0.0, 0.0}, 310 }, 311 { 312 name: "sort by timezonesUTC asc & timezones desc & isCapital asc & population asc", 313 sort: sort4("timezonesUTC", "asc", "timezones", "desc", "isCapital", "asc", "population", "asc"), 314 limit: 4, 315 wantObjs: []*storobj.Object{cityNil2, cityNil, cityWroclaw, cityAmsterdam, cityBerlin, cityNewYork}, 316 wantDists: []float32{0.0, 0.0, 0.1, 0.4, 0.2, 0.3}, 317 }, 318 { 319 name: "sort by timezonesUTC asc & timezones desc & isCapital desc & population asc", 320 sort: sort4("timezonesUTC", "asc", "timezones", "desc", "isCapital", "desc", "population", "asc"), 321 limit: 5, 322 wantObjs: []*storobj.Object{cityNil2, cityNil, cityAmsterdam, cityBerlin, cityWroclaw, cityNewYork}, 323 wantDists: []float32{0.0, 0.0, 0.4, 0.2, 0.1, 0.3}, 324 }, 325 } 326 327 for _, tt := range tests { 328 t.Run(tt.name, func(t *testing.T) { 329 t.Run("with distance", func(t *testing.T) { 330 sorter := NewObjectsSorter(sorterCitySchema()) 331 gotObjs, gotDists, err := sorter.Sort(sorterCitySchemaObjects(), sorterCitySchemaDistances(), 0, tt.sort) 332 333 require.Nil(t, err) 334 335 if !reflect.DeepEqual(gotObjs, tt.wantObjs) { 336 t.Fatalf("objects got = %v, want %v", 337 extractCityNames(gotObjs), extractCityNames(tt.wantObjs)) 338 } 339 if !reflect.DeepEqual(gotDists, tt.wantDists) { 340 t.Fatalf("distances got = %v, want %v", 341 gotDists, tt.wantDists) 342 } 343 }) 344 345 t.Run("without distance", func(t *testing.T) { 346 sorter := NewObjectsSorter(sorterCitySchema()) 347 gotObjs, gotDists, err := sorter.Sort(sorterCitySchemaObjects(), nil, 0, tt.sort) 348 349 require.Nil(t, err) 350 351 if !reflect.DeepEqual(gotObjs, tt.wantObjs) { 352 t.Fatalf("objects got = %v, want %v", 353 extractCityNames(gotObjs), extractCityNames(tt.wantObjs)) 354 } 355 if gotDists != nil { 356 t.Fatalf("distances got = %v, want nil", 357 gotDists) 358 } 359 }) 360 361 t.Run("with limit", func(t *testing.T) { 362 sorter := NewObjectsSorter(sorterCitySchema()) 363 gotObjs, gotDists, err := sorter.Sort(sorterCitySchemaObjects(), sorterCitySchemaDistances(), tt.limit, tt.sort) 364 365 require.Nil(t, err) 366 367 if !reflect.DeepEqual(gotObjs, tt.wantObjs[:tt.limit]) { 368 t.Fatalf("objects got = %v, want %v", 369 extractCityNames(gotObjs), extractCityNames(tt.wantObjs)) 370 } 371 if !reflect.DeepEqual(gotDists, tt.wantDists[:tt.limit]) { 372 t.Fatalf("distances got = %v, want %v", 373 gotDists, tt.wantDists) 374 } 375 }) 376 }) 377 } 378 } 379 380 func createSort(property, order string) filters.Sort { 381 return filters.Sort{Path: []string{property}, Order: order} 382 } 383 384 func sort1(property, order string) []filters.Sort { 385 return []filters.Sort{createSort(property, order)} 386 } 387 388 func sort2(property1, order1, property2, order2 string) []filters.Sort { 389 return []filters.Sort{ 390 createSort(property1, order1), 391 createSort(property2, order2), 392 } 393 } 394 395 func sort4(property1, order1, property2, order2, property3, order3, property4, order4 string) []filters.Sort { 396 return []filters.Sort{ 397 createSort(property1, order1), 398 createSort(property2, order2), 399 createSort(property3, order3), 400 createSort(property4, order4), 401 } 402 } 403 404 func extractCityNames(in []*storobj.Object) []string { 405 out := make([]string, len(in)) 406 for i := range in { 407 if asMap, ok := in[i].Properties().(map[string]interface{}); ok { 408 for k, v := range asMap { 409 if k == "name" { 410 out[i] = v.(string) 411 } 412 } 413 } 414 } 415 return out 416 }