github.com/weaviate/weaviate@v1.24.6/adapters/handlers/grpc/v1/prepare_reply_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 v1 13 14 import ( 15 "encoding/binary" 16 "encoding/json" 17 "math" 18 "math/big" 19 "strings" 20 "testing" 21 "time" 22 23 "github.com/pkg/errors" 24 25 pb "github.com/weaviate/weaviate/grpc/generated/protocol/v1" 26 27 "github.com/weaviate/weaviate/entities/additional" 28 "github.com/weaviate/weaviate/entities/models" 29 "github.com/weaviate/weaviate/entities/schema" 30 "github.com/weaviate/weaviate/entities/search" 31 "github.com/weaviate/weaviate/entities/searchparams" 32 33 "github.com/go-openapi/strfmt" 34 "github.com/stretchr/testify/require" 35 "github.com/weaviate/weaviate/entities/dto" 36 "github.com/weaviate/weaviate/usecases/modulecomponents/additional/generate" 37 addModels "github.com/weaviate/weaviate/usecases/modulecomponents/additional/models" 38 "google.golang.org/protobuf/encoding/protojson" 39 "google.golang.org/protobuf/types/known/structpb" 40 ) 41 42 const ( 43 UUID1 = strfmt.UUID("a4de3ca0-6975-464f-b23b-adddd83630d7") 44 UUID2 = strfmt.UUID("7e10ec81-a26d-4ac7-8264-3e3e05397ddc") 45 ) 46 47 func newStruct(t *testing.T, values map[string]interface{}) *structpb.Struct { 48 b, err := json.Marshal(values) 49 require.Nil(t, err) 50 s := &structpb.Struct{} 51 err = protojson.Unmarshal(b, s) 52 require.Nil(t, err) 53 return s 54 } 55 56 func ignoreError[T any](val T, err error) T { 57 return val 58 } 59 60 func byteVector(vec []float32) []byte { 61 vector := make([]byte, len(vec)*4) 62 63 for i := 0; i < len(vec); i++ { 64 binary.LittleEndian.PutUint32(vector[i*4:i*4+4], math.Float32bits(vec[i])) 65 } 66 67 return vector 68 } 69 70 func idByte(id string) []byte { 71 hexInteger, _ := new(big.Int).SetString(strings.Replace(id, "-", "", -1), 16) 72 return hexInteger.Bytes() 73 } 74 75 func TestGRPCReply(t *testing.T) { 76 allAdditional := dto.GetParams{AdditionalProperties: additional.Properties{ 77 Vector: true, 78 Certainty: true, 79 ID: true, 80 Distance: true, 81 CreationTimeUnix: true, 82 LastUpdateTimeUnix: true, 83 ExplainScore: true, 84 Score: true, 85 IsConsistent: true, 86 }} 87 truePointer := true 88 89 someFloat64 := float64(0.1) 90 refClass1 := "RefClass1" 91 refClass2 := "RefClass2" 92 className := "className" 93 objClass := "objClass" 94 NamedVecClass := "NamedVecs" 95 scheme := schema.Schema{ 96 Objects: &models.Schema{ 97 Classes: []*models.Class{ 98 { 99 Class: className, 100 Properties: []*models.Property{ 101 {Name: "word", DataType: schema.DataTypeText.PropString()}, 102 {Name: "other", DataType: []string{"int"}}, 103 {Name: "age", DataType: []string{"int"}}, 104 {Name: "nums", DataType: schema.DataTypeIntArray.PropString()}, 105 {Name: "ref", DataType: []string{refClass1}}, 106 {Name: "multiRef", DataType: []string{refClass1, refClass2}}, 107 { 108 Name: "nested", 109 DataType: schema.DataTypeObject.PropString(), 110 NestedProperties: []*models.NestedProperty{ 111 {Name: "text", DataType: schema.DataTypeText.PropString()}, 112 {Name: "text2", DataType: schema.DataTypeText.PropString()}, 113 }, 114 }, 115 }, 116 }, 117 { 118 Class: refClass1, 119 Properties: []*models.Property{ 120 {Name: "something", DataType: schema.DataTypeText.PropString()}, 121 {Name: "nums", DataType: schema.DataTypeIntArray.PropString()}, 122 {Name: "ref2", DataType: []string{refClass2}}, 123 }, 124 }, 125 { 126 Class: refClass2, 127 Properties: []*models.Property{ 128 {Name: "else", DataType: schema.DataTypeText.PropString()}, 129 {Name: "ref3", DataType: []string{refClass2}}, 130 }, 131 }, 132 { 133 Class: NamedVecClass, 134 Properties: []*models.Property{ 135 {Name: "name", DataType: schema.DataTypeText.PropString()}, 136 }, 137 VectorConfig: map[string]models.VectorConfig{ 138 "custom": { 139 VectorIndexType: "hnsw", 140 Vectorizer: map[string]interface{}{"none": map[string]interface{}{}}, 141 }, 142 "first": { 143 VectorIndexType: "flat", 144 Vectorizer: map[string]interface{}{"text2vec-contextionary": map[string]interface{}{}}, 145 }, 146 }, 147 }, 148 { 149 Class: objClass, 150 Properties: []*models.Property{ 151 { 152 Name: "something", 153 DataType: schema.DataTypeObject.PropString(), 154 NestedProperties: []*models.NestedProperty{ 155 { 156 Name: "name", 157 DataType: schema.DataTypeText.PropString(), 158 }, 159 { 160 Name: "names", 161 DataType: schema.DataTypeTextArray.PropString(), 162 }, 163 { 164 Name: "else", 165 DataType: schema.DataTypeObject.PropString(), 166 NestedProperties: []*models.NestedProperty{ 167 { 168 Name: "name", 169 DataType: schema.DataTypeText.PropString(), 170 }, 171 { 172 Name: "names", 173 DataType: schema.DataTypeTextArray.PropString(), 174 }, 175 }, 176 }, 177 { 178 Name: "objs", 179 DataType: schema.DataTypeObjectArray.PropString(), 180 NestedProperties: []*models.NestedProperty{{ 181 Name: "name", 182 DataType: schema.DataTypeText.PropString(), 183 }}, 184 }, 185 }, 186 }, 187 }, 188 }, 189 }, 190 }, 191 } 192 193 tests := []struct { 194 name string 195 res []any 196 searchParams dto.GetParams // only a few things are needed to control what is returned 197 outSearch []*pb.SearchResult 198 outGenerative string 199 outGroup []*pb.GroupByResult 200 usesWeaviateStruct bool 201 hasError bool 202 }{ 203 { 204 name: "vector only", 205 res: []interface{}{ 206 map[string]interface{}{ 207 "_additional": map[string]interface{}{"vector": []float32{1}}, 208 }, 209 map[string]interface{}{ 210 "_additional": map[string]interface{}{"vector": []float32{2}}, 211 }, 212 }, 213 searchParams: dto.GetParams{AdditionalProperties: additional.Properties{Vector: true}}, 214 outSearch: []*pb.SearchResult{ 215 {Metadata: &pb.MetadataResult{Vector: []float32{1}, VectorBytes: byteVector([]float32{1})}, Properties: &pb.PropertiesResult{}}, 216 {Metadata: &pb.MetadataResult{Vector: []float32{2}, VectorBytes: byteVector([]float32{2})}, Properties: &pb.PropertiesResult{}}, 217 }, 218 usesWeaviateStruct: true, 219 }, 220 { 221 name: "named vector only", 222 res: []interface{}{ 223 map[string]interface{}{ 224 "_additional": map[string]interface{}{"vectors": map[string][]float32{"custom": {1}, "first": {2}}}, 225 }, 226 }, 227 searchParams: dto.GetParams{AdditionalProperties: additional.Properties{Vectors: []string{"custom", "first"}}}, 228 outSearch: []*pb.SearchResult{ 229 {Metadata: &pb.MetadataResult{Vectors: []*pb.Vectors{ 230 {Name: "custom", VectorBytes: byteVector([]float32{1})}, 231 {Name: "first", VectorBytes: byteVector([]float32{2})}, 232 }}, Properties: &pb.PropertiesResult{}}, 233 }, 234 usesWeaviateStruct: true, 235 }, 236 { 237 name: "all additional", 238 res: []interface{}{ 239 map[string]interface{}{ 240 "id": UUID1, 241 "_additional": map[string]interface{}{ 242 "vector": []float32{1}, 243 "certainty": 0.4, 244 "distance": float32(0.01), 245 "creationTimeUnix": int64(123), 246 "lastUpdateTimeUnix": int64(345), 247 "explainScore": "other text", 248 "score": float32(0.25), 249 "isConsistent": true, 250 }, 251 }, 252 map[string]interface{}{ 253 "id": UUID2, 254 "_additional": map[string]interface{}{ 255 "vector": []float32{2}, 256 "certainty": 0.5, 257 "distance": float32(0.1), 258 "creationTimeUnix": int64(456), 259 "lastUpdateTimeUnix": int64(789), 260 "explainScore": "some text", 261 "score": float32(0.45), 262 "isConsistent": true, 263 }, 264 }, 265 }, 266 searchParams: allAdditional, 267 outSearch: []*pb.SearchResult{ 268 { 269 Metadata: &pb.MetadataResult{ 270 Vector: []float32{1}, 271 Id: string(UUID1), 272 Certainty: 0.4, 273 CertaintyPresent: true, 274 Distance: 0.01, 275 DistancePresent: true, 276 CreationTimeUnix: 123, 277 CreationTimeUnixPresent: true, 278 LastUpdateTimeUnix: 345, 279 LastUpdateTimeUnixPresent: true, 280 ExplainScore: "other text", 281 ExplainScorePresent: true, 282 Score: 0.25, 283 ScorePresent: true, 284 IsConsistent: &truePointer, 285 IsConsistentPresent: true, 286 VectorBytes: byteVector([]float32{1}), 287 IdAsBytes: idByte(string(UUID1)), 288 }, 289 Properties: &pb.PropertiesResult{}, 290 }, 291 { 292 Metadata: &pb.MetadataResult{ 293 Vector: []float32{2}, 294 Id: string(UUID2), 295 Certainty: 0.5, 296 CertaintyPresent: true, 297 Distance: 0.1, 298 DistancePresent: true, 299 CreationTimeUnix: 456, 300 CreationTimeUnixPresent: true, 301 LastUpdateTimeUnix: 789, 302 LastUpdateTimeUnixPresent: true, 303 ExplainScore: "some text", 304 ExplainScorePresent: true, 305 Score: 0.45, 306 ScorePresent: true, 307 IsConsistent: &truePointer, 308 IsConsistentPresent: true, 309 VectorBytes: byteVector([]float32{2}), 310 IdAsBytes: idByte(string(UUID2)), 311 }, 312 Properties: &pb.PropertiesResult{}, 313 }, 314 }, 315 }, 316 { 317 name: "primitive properties deprecated", 318 res: []interface{}{ 319 map[string]interface{}{ 320 "word": "word", 321 "age": 21, 322 }, 323 map[string]interface{}{ 324 "word": "other", 325 "age": 26, 326 }, 327 }, 328 searchParams: dto.GetParams{ 329 ClassName: className, 330 Properties: search.SelectProperties{{Name: "word", IsPrimitive: true}, {Name: "age", IsPrimitive: true}}, 331 }, 332 outSearch: []*pb.SearchResult{ 333 { 334 Metadata: &pb.MetadataResult{}, 335 Properties: &pb.PropertiesResult{ 336 TargetCollection: className, 337 NonRefProperties: newStruct(t, map[string]interface{}{ 338 "word": "word", 339 "age": 21, 340 }), 341 RefProps: []*pb.RefPropertiesResult{}, 342 RefPropsRequested: false, 343 }, 344 }, 345 { 346 Metadata: &pb.MetadataResult{}, 347 Properties: &pb.PropertiesResult{ 348 TargetCollection: className, 349 NonRefProperties: newStruct(t, map[string]interface{}{ 350 "word": "other", 351 "age": 26, 352 }), 353 RefProps: []*pb.RefPropertiesResult{}, 354 RefPropsRequested: false, 355 }, 356 }, 357 }, 358 }, 359 { 360 name: "primitive properties", 361 res: []interface{}{ 362 map[string]interface{}{ 363 "word": "word", 364 "age": float64(21), 365 }, 366 map[string]interface{}{ 367 "word": "other", 368 "age": float64(26), 369 }, 370 }, 371 searchParams: dto.GetParams{ 372 ClassName: className, 373 Properties: search.SelectProperties{{Name: "word", IsPrimitive: true}, {Name: "age", IsPrimitive: true}}, 374 }, 375 outSearch: []*pb.SearchResult{ 376 { 377 Metadata: &pb.MetadataResult{}, 378 Properties: &pb.PropertiesResult{ 379 TargetCollection: className, 380 NonRefProps: &pb.Properties{ 381 Fields: map[string]*pb.Value{ 382 "word": {Kind: &pb.Value_StringValue{StringValue: "word"}}, 383 "age": {Kind: &pb.Value_IntValue{IntValue: 21}}, 384 }, 385 }, 386 RefProps: []*pb.RefPropertiesResult{}, 387 RefPropsRequested: false, 388 }, 389 }, 390 { 391 Metadata: &pb.MetadataResult{}, 392 Properties: &pb.PropertiesResult{ 393 TargetCollection: className, 394 NonRefProps: &pb.Properties{ 395 Fields: map[string]*pb.Value{ 396 "word": {Kind: &pb.Value_StringValue{StringValue: "other"}}, 397 "age": {Kind: &pb.Value_IntValue{IntValue: 26}}, 398 }, 399 }, 400 RefProps: []*pb.RefPropertiesResult{}, 401 RefPropsRequested: false, 402 }, 403 }, 404 }, 405 usesWeaviateStruct: true, 406 }, 407 { 408 name: "request property with nil value", 409 res: []interface{}{ 410 map[string]interface{}{ 411 "word": "word", 412 }, 413 }, 414 searchParams: dto.GetParams{ 415 ClassName: className, 416 Properties: search.SelectProperties{{Name: "word", IsPrimitive: true}, {Name: "age", IsPrimitive: true}}, 417 }, 418 outSearch: []*pb.SearchResult{ 419 { 420 Metadata: &pb.MetadataResult{}, 421 Properties: &pb.PropertiesResult{ 422 TargetCollection: className, 423 NonRefProps: &pb.Properties{ 424 Fields: map[string]*pb.Value{ 425 "word": {Kind: &pb.Value_StringValue{StringValue: "word"}}, 426 "age": {Kind: &pb.Value_NullValue{}}, 427 }, 428 }, 429 RefProps: []*pb.RefPropertiesResult{}, 430 RefPropsRequested: false, 431 }, 432 }, 433 }, 434 usesWeaviateStruct: true, 435 }, 436 { 437 name: "array properties", 438 res: []interface{}{ 439 map[string]interface{}{"nums": []float64{1, 2, 3}}, // ints are encoded as float64 in json 440 }, 441 searchParams: dto.GetParams{ 442 ClassName: className, 443 Properties: search.SelectProperties{{Name: "nums", IsPrimitive: true}}, 444 }, 445 outSearch: []*pb.SearchResult{ 446 { 447 Metadata: &pb.MetadataResult{}, 448 Properties: &pb.PropertiesResult{ 449 TargetCollection: className, 450 NonRefProps: &pb.Properties{ 451 Fields: map[string]*pb.Value{ 452 "nums": {Kind: &pb.Value_ListValue{ListValue: ignoreError(NewPrimitiveList([]float64{1, 2, 3}, schema.DataTypeInt))}}, 453 }, 454 }, 455 }, 456 }, 457 }, 458 usesWeaviateStruct: true, 459 }, 460 { 461 name: "array properties deprecated", 462 res: []interface{}{ 463 map[string]interface{}{"nums": []float64{1, 2, 3}}, // ints are encoded as float64 in json 464 }, 465 searchParams: dto.GetParams{ 466 ClassName: className, 467 Properties: search.SelectProperties{{Name: "nums", IsPrimitive: true}}, 468 }, 469 outSearch: []*pb.SearchResult{ 470 { 471 Metadata: &pb.MetadataResult{}, 472 Properties: &pb.PropertiesResult{ 473 TargetCollection: className, 474 NonRefProperties: newStruct(t, map[string]interface{}{}), 475 IntArrayProperties: []*pb.IntArrayProperties{{ 476 PropName: "nums", 477 Values: []int64{1, 2, 3}, 478 }}, 479 }, 480 }, 481 }, 482 usesWeaviateStruct: false, 483 }, 484 { 485 name: "nested object properties", 486 res: []interface{}{ 487 map[string]interface{}{ 488 "something": map[string]interface{}{ 489 "name": "Bob", 490 "names": []string{"Jo", "Jill"}, 491 "else": map[string]interface{}{ 492 "name": "Bill", 493 "names": []string{"Jo", "Jill"}, 494 }, 495 "objs": []interface{}{ 496 map[string]interface{}{"name": "Bill"}, 497 }, 498 }, 499 }, 500 }, 501 searchParams: dto.GetParams{ 502 ClassName: objClass, 503 Properties: search.SelectProperties{{ 504 Name: "something", 505 IsPrimitive: false, 506 IsObject: true, 507 Props: []search.SelectProperty{ 508 { 509 Name: "name", 510 IsPrimitive: true, 511 }, 512 { 513 Name: "names", 514 IsPrimitive: true, 515 }, 516 { 517 Name: "else", 518 IsPrimitive: false, 519 IsObject: true, 520 Props: []search.SelectProperty{ 521 { 522 Name: "name", 523 IsPrimitive: true, 524 }, 525 { 526 Name: "names", 527 IsPrimitive: true, 528 }, 529 }, 530 }, 531 { 532 Name: "objs", 533 IsPrimitive: false, 534 IsObject: true, 535 Props: []search.SelectProperty{{ 536 Name: "name", 537 IsPrimitive: true, 538 }}, 539 }, 540 }, 541 }}, 542 }, 543 outSearch: []*pb.SearchResult{ 544 { 545 Metadata: &pb.MetadataResult{}, 546 Properties: &pb.PropertiesResult{ 547 TargetCollection: objClass, 548 NonRefProps: &pb.Properties{ 549 Fields: map[string]*pb.Value{ 550 "something": {Kind: &pb.Value_ObjectValue{ 551 ObjectValue: &pb.Properties{ 552 Fields: map[string]*pb.Value{ 553 "name": {Kind: &pb.Value_StringValue{StringValue: "Bob"}}, 554 "names": {Kind: &pb.Value_ListValue{ListValue: ignoreError(NewPrimitiveList([]string{"Jo", "Jill"}, schema.DataTypeString))}}, 555 "else": {Kind: &pb.Value_ObjectValue{ 556 ObjectValue: &pb.Properties{ 557 Fields: map[string]*pb.Value{ 558 "name": {Kind: &pb.Value_StringValue{StringValue: "Bill"}}, 559 "names": {Kind: &pb.Value_ListValue{ListValue: ignoreError(NewPrimitiveList([]string{"Jo", "Jill"}, schema.DataTypeString))}}, 560 }, 561 }, 562 }}, 563 "objs": {Kind: &pb.Value_ListValue{ListValue: &pb.ListValue{ 564 Values: []*pb.Value{{Kind: &pb.Value_ObjectValue{ 565 ObjectValue: &pb.Properties{ 566 Fields: map[string]*pb.Value{ 567 "name": {Kind: &pb.Value_StringValue{StringValue: "Bill"}}, 568 }, 569 }, 570 }}}, 571 }}}, 572 }, 573 }, 574 }}, 575 }, 576 }, 577 }, 578 }, 579 }, 580 usesWeaviateStruct: true, 581 }, 582 { 583 name: "nested object properties with missing values", 584 res: []interface{}{ 585 map[string]interface{}{ 586 "something": map[string]interface{}{ 587 "name": "Bob", 588 "names": []string{"Jo", "Jill"}, 589 "else": map[string]interface{}{ 590 "names": []string{"Jo", "Jill"}, 591 }, 592 "objs": []interface{}{ 593 map[string]interface{}{"name": "Bill"}, 594 }, 595 }, 596 }, 597 }, 598 searchParams: dto.GetParams{ 599 ClassName: objClass, 600 Properties: search.SelectProperties{{ 601 Name: "something", 602 IsPrimitive: false, 603 IsObject: true, 604 Props: []search.SelectProperty{ 605 { 606 Name: "name", 607 IsPrimitive: true, 608 }, 609 { 610 Name: "names", 611 IsPrimitive: true, 612 }, 613 { 614 Name: "else", 615 IsPrimitive: false, 616 IsObject: true, 617 Props: []search.SelectProperty{ 618 { 619 Name: "name", 620 IsPrimitive: true, 621 }, 622 { 623 Name: "names", 624 IsPrimitive: true, 625 }, 626 }, 627 }, 628 { 629 Name: "objs", 630 IsPrimitive: false, 631 IsObject: true, 632 Props: []search.SelectProperty{{ 633 Name: "name", 634 IsPrimitive: true, 635 }}, 636 }, 637 }, 638 }}, 639 }, 640 outSearch: []*pb.SearchResult{ 641 { 642 Metadata: &pb.MetadataResult{}, 643 Properties: &pb.PropertiesResult{ 644 TargetCollection: objClass, 645 NonRefProps: &pb.Properties{ 646 Fields: map[string]*pb.Value{ 647 "something": {Kind: &pb.Value_ObjectValue{ 648 ObjectValue: &pb.Properties{ 649 Fields: map[string]*pb.Value{ 650 "name": {Kind: &pb.Value_StringValue{StringValue: "Bob"}}, 651 "names": {Kind: &pb.Value_ListValue{ListValue: ignoreError(NewPrimitiveList([]string{"Jo", "Jill"}, schema.DataTypeString))}}, 652 "else": {Kind: &pb.Value_ObjectValue{ 653 ObjectValue: &pb.Properties{ 654 Fields: map[string]*pb.Value{ 655 "names": {Kind: &pb.Value_ListValue{ListValue: ignoreError(NewPrimitiveList([]string{"Jo", "Jill"}, schema.DataTypeString))}}, 656 }, 657 }, 658 }}, 659 "objs": {Kind: &pb.Value_ListValue{ListValue: &pb.ListValue{ 660 Values: []*pb.Value{{Kind: &pb.Value_ObjectValue{ 661 ObjectValue: &pb.Properties{ 662 Fields: map[string]*pb.Value{ 663 "name": {Kind: &pb.Value_StringValue{StringValue: "Bill"}}, 664 }, 665 }, 666 }}}, 667 }}}, 668 }, 669 }, 670 }}, 671 }, 672 }, 673 }, 674 }, 675 }, 676 usesWeaviateStruct: true, 677 }, 678 { 679 name: "nested object properties deprecated", 680 res: []interface{}{ 681 map[string]interface{}{ 682 "something": map[string]interface{}{ 683 "name": "Bob", 684 "names": []string{"Jo", "Jill"}, 685 "else": map[string]interface{}{ 686 "name": "Bill", 687 "names": []string{"Jo", "Jill"}, 688 }, 689 "objs": []interface{}{ 690 map[string]interface{}{"name": "Bill"}, 691 }, 692 }, 693 }, 694 }, 695 searchParams: dto.GetParams{ 696 ClassName: objClass, 697 Properties: search.SelectProperties{{ 698 Name: "something", 699 IsPrimitive: false, 700 IsObject: true, 701 Props: []search.SelectProperty{ 702 { 703 Name: "name", 704 IsPrimitive: true, 705 }, 706 { 707 Name: "names", 708 IsPrimitive: true, 709 }, 710 { 711 Name: "else", 712 IsPrimitive: false, 713 IsObject: true, 714 Props: []search.SelectProperty{ 715 { 716 Name: "name", 717 IsPrimitive: true, 718 }, 719 { 720 Name: "names", 721 IsPrimitive: true, 722 }, 723 }, 724 }, 725 { 726 Name: "objs", 727 IsPrimitive: false, 728 IsObject: true, 729 Props: []search.SelectProperty{{ 730 Name: "name", 731 IsPrimitive: true, 732 }}, 733 }, 734 }, 735 }}, 736 }, 737 outSearch: []*pb.SearchResult{ 738 { 739 Metadata: &pb.MetadataResult{}, 740 Properties: &pb.PropertiesResult{ 741 TargetCollection: objClass, 742 ObjectProperties: []*pb.ObjectProperties{ 743 { 744 PropName: "something", 745 Value: &pb.ObjectPropertiesValue{ 746 NonRefProperties: newStruct(t, map[string]interface{}{ 747 "name": "Bob", 748 }), 749 TextArrayProperties: []*pb.TextArrayProperties{{ 750 PropName: "names", 751 Values: []string{"Jo", "Jill"}, 752 }}, 753 ObjectProperties: []*pb.ObjectProperties{{ 754 PropName: "else", 755 Value: &pb.ObjectPropertiesValue{ 756 NonRefProperties: newStruct(t, map[string]interface{}{ 757 "name": "Bill", 758 }), 759 TextArrayProperties: []*pb.TextArrayProperties{{ 760 PropName: "names", 761 Values: []string{"Jo", "Jill"}, 762 }}, 763 }, 764 }}, 765 ObjectArrayProperties: []*pb.ObjectArrayProperties{{ 766 PropName: "objs", 767 Values: []*pb.ObjectPropertiesValue{{ 768 NonRefProperties: newStruct(t, map[string]interface{}{ 769 "name": "Bill", 770 }), 771 }}, 772 }}, 773 }, 774 }, 775 }, 776 }, 777 }, 778 }, 779 usesWeaviateStruct: false, 780 }, 781 { 782 name: "primitive and ref properties with no references", 783 res: []interface{}{ 784 map[string]interface{}{ 785 "word": "word", 786 }, 787 map[string]interface{}{ 788 "word": "other", 789 }, 790 }, 791 searchParams: dto.GetParams{ 792 ClassName: className, 793 Properties: search.SelectProperties{ 794 {Name: "word", IsPrimitive: true}, 795 {Name: "ref", IsPrimitive: false, Refs: []search.SelectClass{ 796 { 797 ClassName: refClass1, 798 RefProperties: search.SelectProperties{{Name: "something", IsPrimitive: true}}, 799 AdditionalProperties: additional.Properties{Vector: true}, 800 }, 801 }}, 802 }, 803 }, 804 outSearch: []*pb.SearchResult{ 805 { 806 Metadata: &pb.MetadataResult{}, 807 Properties: &pb.PropertiesResult{ 808 TargetCollection: className, 809 NonRefProps: &pb.Properties{ 810 Fields: map[string]*pb.Value{ 811 "word": {Kind: &pb.Value_StringValue{StringValue: "word"}}, 812 }, 813 }, 814 RefProps: []*pb.RefPropertiesResult{}, 815 RefPropsRequested: true, 816 }, 817 }, 818 { 819 Metadata: &pb.MetadataResult{}, 820 Properties: &pb.PropertiesResult{ 821 TargetCollection: className, 822 NonRefProps: &pb.Properties{ 823 Fields: map[string]*pb.Value{ 824 "word": {Kind: &pb.Value_StringValue{StringValue: "other"}}, 825 }, 826 }, 827 RefProps: []*pb.RefPropertiesResult{}, 828 RefPropsRequested: true, 829 }, 830 }, 831 }, 832 usesWeaviateStruct: true, 833 }, 834 { 835 name: "primitive and ref properties", 836 res: []interface{}{ 837 map[string]interface{}{ 838 "word": "word", 839 "ref": []interface{}{ 840 search.LocalRef{ 841 Class: refClass1, 842 Fields: map[string]interface{}{ 843 "something": "other", 844 "_additional": map[string]interface{}{"vector": []float32{3}}, 845 }, 846 }, 847 }, 848 }, 849 map[string]interface{}{ 850 "word": "other", 851 "ref": []interface{}{ 852 search.LocalRef{ 853 Class: refClass1, 854 Fields: map[string]interface{}{ 855 "something": "thing", 856 "_additional": map[string]interface{}{"vector": []float32{4}}, 857 }, 858 }, 859 }, 860 }, 861 }, 862 searchParams: dto.GetParams{ 863 ClassName: className, 864 Properties: search.SelectProperties{ 865 {Name: "word", IsPrimitive: true}, 866 {Name: "ref", IsPrimitive: false, Refs: []search.SelectClass{ 867 { 868 ClassName: refClass1, 869 RefProperties: search.SelectProperties{{Name: "something", IsPrimitive: true}}, 870 AdditionalProperties: additional.Properties{Vector: true}, 871 }, 872 }}, 873 }, 874 }, 875 outSearch: []*pb.SearchResult{ 876 { 877 Metadata: &pb.MetadataResult{}, 878 Properties: &pb.PropertiesResult{ 879 TargetCollection: className, 880 NonRefProps: &pb.Properties{ 881 Fields: map[string]*pb.Value{ 882 "word": {Kind: &pb.Value_StringValue{StringValue: "word"}}, 883 }, 884 }, 885 RefProps: []*pb.RefPropertiesResult{{ 886 PropName: "ref", 887 Properties: []*pb.PropertiesResult{ 888 { 889 TargetCollection: refClass1, 890 Metadata: &pb.MetadataResult{Vector: []float32{3}, VectorBytes: byteVector([]float32{3})}, 891 NonRefProps: &pb.Properties{ 892 Fields: map[string]*pb.Value{ 893 "something": {Kind: &pb.Value_StringValue{StringValue: "other"}}, 894 }, 895 }, 896 }, 897 }, 898 }}, 899 RefPropsRequested: true, 900 }, 901 }, 902 { 903 Metadata: &pb.MetadataResult{}, 904 Properties: &pb.PropertiesResult{ 905 TargetCollection: className, 906 NonRefProps: &pb.Properties{ 907 Fields: map[string]*pb.Value{ 908 "word": {Kind: &pb.Value_StringValue{StringValue: "other"}}, 909 }, 910 }, 911 RefProps: []*pb.RefPropertiesResult{{ 912 PropName: "ref", 913 Properties: []*pb.PropertiesResult{ 914 { 915 TargetCollection: refClass1, 916 Metadata: &pb.MetadataResult{Vector: []float32{4}, VectorBytes: byteVector([]float32{4})}, 917 NonRefProps: &pb.Properties{ 918 Fields: map[string]*pb.Value{ 919 "something": {Kind: &pb.Value_StringValue{StringValue: "thing"}}, 920 }, 921 }, 922 }, 923 }, 924 }}, 925 RefPropsRequested: true, 926 }, 927 }, 928 }, 929 usesWeaviateStruct: true, 930 }, 931 { 932 name: "nested ref properties", 933 res: []interface{}{ 934 map[string]interface{}{ 935 "word": "word", 936 "ref": []interface{}{ 937 search.LocalRef{ 938 Class: refClass1, 939 Fields: map[string]interface{}{ 940 "something": "other", 941 "ref2": []interface{}{ 942 search.LocalRef{ 943 Class: refClass2, 944 Fields: map[string]interface{}{ 945 "else": "thing", 946 }, 947 }, 948 }, 949 }, 950 }, 951 }, 952 }, 953 }, 954 searchParams: dto.GetParams{ 955 ClassName: className, 956 Properties: search.SelectProperties{ 957 {Name: "word", IsPrimitive: true}, 958 { 959 Name: "ref", IsPrimitive: false, Refs: []search.SelectClass{ 960 { 961 ClassName: refClass1, 962 RefProperties: search.SelectProperties{ 963 {Name: "something", IsPrimitive: true}, 964 { 965 Name: "ref2", IsPrimitive: false, Refs: []search.SelectClass{{ 966 ClassName: refClass2, 967 RefProperties: search.SelectProperties{{Name: "else", IsPrimitive: true}}, 968 }}, 969 }, 970 }, 971 }, 972 }, 973 }, 974 }, 975 }, 976 outSearch: []*pb.SearchResult{ 977 { 978 Metadata: &pb.MetadataResult{}, 979 Properties: &pb.PropertiesResult{ 980 TargetCollection: className, 981 NonRefProps: &pb.Properties{ 982 Fields: map[string]*pb.Value{ 983 "word": {Kind: &pb.Value_StringValue{StringValue: "word"}}, 984 }, 985 }, 986 RefProps: []*pb.RefPropertiesResult{{ 987 PropName: "ref", 988 Properties: []*pb.PropertiesResult{ 989 { 990 TargetCollection: refClass1, 991 Metadata: &pb.MetadataResult{}, 992 NonRefProps: &pb.Properties{ 993 Fields: map[string]*pb.Value{ 994 "something": {Kind: &pb.Value_StringValue{StringValue: "other"}}, 995 }, 996 }, 997 RefProps: []*pb.RefPropertiesResult{{ 998 PropName: "ref2", 999 Properties: []*pb.PropertiesResult{{ 1000 TargetCollection: refClass2, 1001 Metadata: &pb.MetadataResult{}, 1002 NonRefProps: &pb.Properties{ 1003 Fields: map[string]*pb.Value{ 1004 "else": {Kind: &pb.Value_StringValue{StringValue: "thing"}}, 1005 }, 1006 }, 1007 RefProps: []*pb.RefPropertiesResult{}, 1008 RefPropsRequested: false, 1009 }}, 1010 }}, 1011 RefPropsRequested: true, 1012 }, 1013 }, 1014 }}, 1015 RefPropsRequested: true, 1016 }, 1017 }, 1018 }, 1019 usesWeaviateStruct: true, 1020 }, 1021 { 1022 name: "nested ref properties with no references", 1023 res: []interface{}{ 1024 map[string]interface{}{ 1025 "word": "word", 1026 "ref": []interface{}{ 1027 search.LocalRef{ 1028 Class: refClass1, 1029 Fields: map[string]interface{}{ 1030 "something": "other", 1031 }, 1032 }, 1033 }, 1034 }, 1035 }, 1036 searchParams: dto.GetParams{ 1037 ClassName: className, 1038 Properties: search.SelectProperties{ 1039 {Name: "word", IsPrimitive: true}, 1040 { 1041 Name: "ref", IsPrimitive: false, Refs: []search.SelectClass{ 1042 { 1043 ClassName: refClass1, 1044 RefProperties: search.SelectProperties{ 1045 {Name: "something", IsPrimitive: true}, 1046 { 1047 Name: "ref2", IsPrimitive: false, Refs: []search.SelectClass{{ 1048 ClassName: refClass2, 1049 RefProperties: search.SelectProperties{{Name: "else", IsPrimitive: true}}, 1050 }}, 1051 }, 1052 }, 1053 }, 1054 }, 1055 }, 1056 }, 1057 }, 1058 outSearch: []*pb.SearchResult{ 1059 { 1060 Metadata: &pb.MetadataResult{}, 1061 Properties: &pb.PropertiesResult{ 1062 TargetCollection: className, 1063 NonRefProps: &pb.Properties{ 1064 Fields: map[string]*pb.Value{ 1065 "word": {Kind: &pb.Value_StringValue{StringValue: "word"}}, 1066 }, 1067 }, 1068 RefProps: []*pb.RefPropertiesResult{{ 1069 PropName: "ref", 1070 Properties: []*pb.PropertiesResult{ 1071 { 1072 TargetCollection: refClass1, 1073 Metadata: &pb.MetadataResult{}, 1074 NonRefProps: &pb.Properties{ 1075 Fields: map[string]*pb.Value{ 1076 "something": {Kind: &pb.Value_StringValue{StringValue: "other"}}, 1077 }, 1078 }, 1079 RefProps: []*pb.RefPropertiesResult{}, 1080 RefPropsRequested: true, 1081 }, 1082 }, 1083 }}, 1084 RefPropsRequested: true, 1085 }, 1086 }, 1087 }, 1088 usesWeaviateStruct: true, 1089 }, 1090 { 1091 name: "primitive and ref array properties", 1092 res: []interface{}{ 1093 map[string]interface{}{ 1094 "word": "word", 1095 "ref": []interface{}{ 1096 search.LocalRef{ 1097 Class: refClass1, 1098 Fields: map[string]interface{}{ 1099 "nums": []float64{1, 2, 3}, // ints are encoded as float64 in json 1100 "_additional": map[string]interface{}{"vector": []float32{3}}, 1101 }, 1102 }, 1103 }, 1104 }, 1105 }, 1106 searchParams: dto.GetParams{ 1107 ClassName: className, 1108 Properties: search.SelectProperties{ 1109 {Name: "word", IsPrimitive: true}, 1110 {Name: "ref", IsPrimitive: false, Refs: []search.SelectClass{ 1111 { 1112 ClassName: refClass1, 1113 RefProperties: search.SelectProperties{{Name: "nums", IsPrimitive: true}}, 1114 AdditionalProperties: additional.Properties{Vector: true}, 1115 }, 1116 }}, 1117 }, 1118 }, 1119 outSearch: []*pb.SearchResult{ 1120 { 1121 Metadata: &pb.MetadataResult{}, 1122 Properties: &pb.PropertiesResult{ 1123 TargetCollection: className, 1124 NonRefProps: &pb.Properties{ 1125 Fields: map[string]*pb.Value{ 1126 "word": {Kind: &pb.Value_StringValue{StringValue: "word"}}, 1127 }, 1128 }, 1129 RefProps: []*pb.RefPropertiesResult{{ 1130 PropName: "ref", 1131 Properties: []*pb.PropertiesResult{ 1132 { 1133 TargetCollection: refClass1, 1134 Metadata: &pb.MetadataResult{Vector: []float32{3}, VectorBytes: byteVector([]float32{3})}, 1135 NonRefProps: &pb.Properties{ 1136 Fields: map[string]*pb.Value{ 1137 "nums": {Kind: &pb.Value_ListValue{ListValue: ignoreError(NewPrimitiveList([]float64{1, 2, 3}, schema.DataTypeInt))}}, 1138 }, 1139 }, 1140 }, 1141 }, 1142 }}, 1143 RefPropsRequested: true, 1144 }, 1145 }, 1146 }, 1147 usesWeaviateStruct: true, 1148 }, 1149 { 1150 name: "primitive and ref array properties deprecated", 1151 res: []interface{}{ 1152 map[string]interface{}{ 1153 "word": "word", 1154 "ref": []interface{}{ 1155 search.LocalRef{ 1156 Class: refClass1, 1157 Fields: map[string]interface{}{ 1158 "nums": []float64{1, 2, 3}, // ints are encoded as float64 in json 1159 "_additional": map[string]interface{}{"vector": []float32{3}}, 1160 }, 1161 }, 1162 }, 1163 }, 1164 }, 1165 searchParams: dto.GetParams{ 1166 ClassName: className, 1167 Properties: search.SelectProperties{ 1168 {Name: "word", IsPrimitive: true}, 1169 {Name: "ref", IsPrimitive: false, Refs: []search.SelectClass{ 1170 { 1171 ClassName: refClass1, 1172 RefProperties: search.SelectProperties{{Name: "nums", IsPrimitive: true}}, 1173 AdditionalProperties: additional.Properties{Vector: true}, 1174 }, 1175 }}, 1176 }, 1177 }, 1178 outSearch: []*pb.SearchResult{ 1179 { 1180 Metadata: &pb.MetadataResult{}, 1181 Properties: &pb.PropertiesResult{ 1182 TargetCollection: className, 1183 NonRefProperties: newStruct(t, map[string]interface{}{ 1184 "word": "word", 1185 }), 1186 RefProps: []*pb.RefPropertiesResult{{ 1187 PropName: "ref", 1188 Properties: []*pb.PropertiesResult{ 1189 { 1190 TargetCollection: refClass1, 1191 Metadata: &pb.MetadataResult{Vector: []float32{3}, VectorBytes: byteVector([]float32{3})}, 1192 NonRefProperties: newStruct(t, map[string]interface{}{}), 1193 IntArrayProperties: []*pb.IntArrayProperties{{ 1194 PropName: "nums", 1195 Values: []int64{1, 2, 3}, 1196 }}, 1197 }, 1198 }, 1199 }}, 1200 }, 1201 }, 1202 }, 1203 usesWeaviateStruct: false, 1204 }, 1205 { 1206 name: "generative single only with ID", 1207 res: []interface{}{ 1208 map[string]interface{}{ 1209 "_additional": map[string]interface{}{ 1210 "id": UUID1, // different place for generative 1211 "generate": &addModels.GenerateResult{SingleResult: &refClass1}, // just use some string 1212 }, 1213 }, 1214 map[string]interface{}{ 1215 "_additional": map[string]interface{}{ 1216 "id": UUID2, 1217 "generate": &addModels.GenerateResult{SingleResult: &refClass2}, 1218 }, 1219 }, 1220 }, 1221 searchParams: dto.GetParams{AdditionalProperties: additional.Properties{ 1222 ID: true, 1223 ModuleParams: map[string]interface{}{ 1224 "generate": &generate.Params{ 1225 Prompt: &refClass1, 1226 }, 1227 }, 1228 }}, 1229 outSearch: []*pb.SearchResult{ 1230 { 1231 Metadata: &pb.MetadataResult{ 1232 Id: string(UUID1), 1233 Generative: refClass1, 1234 GenerativePresent: true, 1235 IdAsBytes: idByte(UUID1.String()), 1236 }, 1237 Properties: &pb.PropertiesResult{}, 1238 }, 1239 { 1240 Metadata: &pb.MetadataResult{ 1241 Id: string(UUID2), 1242 Generative: refClass2, 1243 GenerativePresent: true, 1244 IdAsBytes: idByte(UUID2.String()), 1245 }, 1246 Properties: &pb.PropertiesResult{}, 1247 }, 1248 }, 1249 }, 1250 { 1251 name: "generative single only without ID", 1252 res: []interface{}{ 1253 map[string]interface{}{ 1254 "_additional": map[string]interface{}{ // different place for generative 1255 "generate": &addModels.GenerateResult{SingleResult: &refClass1}, // just use some string 1256 }, 1257 }, 1258 map[string]interface{}{ 1259 "_additional": map[string]interface{}{ 1260 "generate": &addModels.GenerateResult{SingleResult: &refClass2}, 1261 }, 1262 }, 1263 }, 1264 searchParams: dto.GetParams{AdditionalProperties: additional.Properties{ 1265 ModuleParams: map[string]interface{}{ 1266 "generate": &generate.Params{ 1267 Prompt: &refClass1, 1268 }, 1269 }, 1270 }}, 1271 outSearch: []*pb.SearchResult{ 1272 { 1273 Metadata: &pb.MetadataResult{ 1274 Generative: refClass1, 1275 GenerativePresent: true, 1276 }, 1277 Properties: &pb.PropertiesResult{}, 1278 }, 1279 { 1280 Metadata: &pb.MetadataResult{ 1281 Generative: refClass2, 1282 GenerativePresent: true, 1283 }, 1284 Properties: &pb.PropertiesResult{}, 1285 }, 1286 }, 1287 }, 1288 { 1289 name: "generative with error", 1290 res: []interface{}{ 1291 map[string]interface{}{ 1292 "_additional": map[string]interface{}{ // different place for generative 1293 "generate": &addModels.GenerateResult{Error: errors.New("error")}, 1294 }, 1295 }, 1296 }, 1297 searchParams: dto.GetParams{AdditionalProperties: additional.Properties{ 1298 ModuleParams: map[string]interface{}{ 1299 "generate": &generate.Params{ 1300 Prompt: &refClass1, 1301 }, 1302 }, 1303 }}, 1304 hasError: true, 1305 }, 1306 { 1307 name: "generative group only", 1308 res: []interface{}{ 1309 map[string]interface{}{ 1310 "_additional": map[string]interface{}{ 1311 "id": UUID1, // different place for generative 1312 "generate": &addModels.GenerateResult{GroupedResult: &refClass1}, // just use some string 1313 }, 1314 }, 1315 map[string]interface{}{ 1316 "_additional": map[string]interface{}{ 1317 "id": UUID2, 1318 "generate": &addModels.GenerateResult{}, 1319 }, 1320 }, 1321 }, 1322 searchParams: dto.GetParams{AdditionalProperties: additional.Properties{ 1323 ID: true, 1324 ModuleParams: map[string]interface{}{ 1325 "generate": &generate.Params{ 1326 Task: &refClass1, 1327 }, 1328 }, 1329 }}, 1330 outSearch: []*pb.SearchResult{ 1331 { 1332 Metadata: &pb.MetadataResult{ 1333 Id: string(UUID1), 1334 IdAsBytes: idByte(UUID1.String()), 1335 }, 1336 Properties: &pb.PropertiesResult{}, 1337 }, 1338 { 1339 Metadata: &pb.MetadataResult{ 1340 Id: string(UUID2), 1341 IdAsBytes: idByte(UUID2.String()), 1342 }, 1343 Properties: &pb.PropertiesResult{}, 1344 }, 1345 }, 1346 outGenerative: refClass1, 1347 }, 1348 { 1349 name: "group by", 1350 res: []interface{}{ 1351 map[string]interface{}{ 1352 "_additional": map[string]interface{}{ 1353 "id": UUID2, 1354 "group": &additional.Group{ 1355 ID: 1, 1356 MinDistance: 0.1, 1357 MaxDistance: 0.2, 1358 Count: 3, 1359 GroupedBy: &additional.GroupedBy{Value: "GroupByValue1", Path: []string{"some_prop"}}, 1360 Hits: []map[string]interface{}{ 1361 { 1362 "word": "word", 1363 "ref": []interface{}{ 1364 search.LocalRef{ 1365 Class: refClass1, 1366 Fields: map[string]interface{}{ 1367 "something": "other", 1368 "_additional": map[string]interface{}{"vector": []float32{2}, "id": UUID1}, 1369 }, 1370 }, 1371 }, 1372 "_additional": &additional.GroupHitAdditional{Vector: []float32{3}, ID: UUID2}, 1373 }, 1374 { 1375 "word": "other", 1376 "_additional": &additional.GroupHitAdditional{Vector: []float32{4}, ID: UUID1}, 1377 }, 1378 }, 1379 }, 1380 }, 1381 }, 1382 }, 1383 searchParams: dto.GetParams{AdditionalProperties: additional.Properties{ 1384 ID: true, 1385 Vector: true, 1386 }, GroupBy: &searchparams.GroupBy{Groups: 3, ObjectsPerGroup: 4, Property: "name"}}, 1387 outGroup: []*pb.GroupByResult{{ 1388 Name: "GroupByValue1", 1389 MaxDistance: 0.2, 1390 MinDistance: 0.1, 1391 NumberOfObjects: 3, 1392 Objects: []*pb.SearchResult{ 1393 { 1394 Properties: &pb.PropertiesResult{ 1395 NonRefProperties: newStruct(t, map[string]interface{}{"word": "word"}), 1396 RefProps: []*pb.RefPropertiesResult{ 1397 { 1398 PropName: "other", 1399 Properties: []*pb.PropertiesResult{ 1400 { 1401 NonRefProperties: newStruct(t, map[string]interface{}{"something": "other"}), 1402 Metadata: &pb.MetadataResult{Vector: []float32{2}, Id: UUID1.String()}, 1403 }, 1404 }, 1405 }, 1406 }, 1407 RefPropsRequested: true, 1408 }, 1409 Metadata: &pb.MetadataResult{ 1410 Id: string(UUID2), 1411 Vector: []float32{3}, 1412 }, 1413 }, 1414 { 1415 Properties: &pb.PropertiesResult{ 1416 NonRefProperties: newStruct(t, map[string]interface{}{"word": "other"}), 1417 }, 1418 Metadata: &pb.MetadataResult{ 1419 Id: string(UUID1), 1420 Vector: []float32{4}, 1421 }, 1422 }, 1423 }, 1424 }}, 1425 }, 1426 { 1427 name: "rerank only", 1428 res: []interface{}{ 1429 map[string]interface{}{ 1430 "_additional": map[string]interface{}{ 1431 "id": UUID1, 1432 "rerank": []*addModels.RankResult{{Score: &someFloat64}}, 1433 }, 1434 }, 1435 }, 1436 searchParams: dto.GetParams{AdditionalProperties: additional.Properties{ 1437 ID: true, 1438 ModuleParams: map[string]interface{}{"rerank": "must be present for extraction"}, 1439 }}, 1440 outSearch: []*pb.SearchResult{ 1441 { 1442 Metadata: &pb.MetadataResult{ 1443 Id: string(UUID1), 1444 RerankScore: someFloat64, 1445 RerankScorePresent: true, 1446 IdAsBytes: idByte(UUID1.String()), 1447 }, 1448 Properties: &pb.PropertiesResult{}, 1449 }, 1450 }, 1451 }, 1452 { 1453 name: "generate, group by, & rerank", 1454 res: []interface{}{ 1455 map[string]interface{}{ 1456 "_additional": map[string]interface{}{ 1457 "id": UUID2, 1458 "generate": &addModels.GenerateResult{ 1459 SingleResult: &refClass1, 1460 GroupedResult: &refClass2, 1461 }, 1462 "rerank": []*addModels.RankResult{{Score: &someFloat64}}, 1463 "group": &additional.Group{ 1464 ID: 1, 1465 MinDistance: 0.1, 1466 MaxDistance: 0.2, 1467 Count: 3, 1468 GroupedBy: &additional.GroupedBy{Value: "GroupByValue1", Path: []string{"some_prop"}}, 1469 Hits: []map[string]interface{}{ 1470 { 1471 "word": "word", 1472 "ref": []interface{}{ 1473 search.LocalRef{ 1474 Class: refClass1, 1475 Fields: map[string]interface{}{ 1476 "something": "other", 1477 "_additional": map[string]interface{}{"vector": []float32{2}, "id": UUID1}, 1478 }, 1479 }, 1480 }, 1481 "_additional": &additional.GroupHitAdditional{Vector: []float32{3}, ID: UUID2}, 1482 }, 1483 { 1484 "word": "other", 1485 "_additional": &additional.GroupHitAdditional{Vector: []float32{4}, ID: UUID1}, 1486 }, 1487 }, 1488 }, 1489 }, 1490 }, 1491 }, 1492 searchParams: dto.GetParams{ 1493 AdditionalProperties: additional.Properties{ 1494 ID: true, 1495 Vector: true, 1496 ModuleParams: map[string]interface{}{ 1497 "generate": &generate.Params{ 1498 Prompt: &refClass1, 1499 Task: &refClass2, 1500 }, 1501 "rerank": "must be present for extraction", 1502 }, 1503 }, 1504 GroupBy: &searchparams.GroupBy{Groups: 3, ObjectsPerGroup: 4, Property: "name"}, 1505 }, 1506 outGroup: []*pb.GroupByResult{{ 1507 Name: "GroupByValue1", 1508 MaxDistance: 0.2, 1509 MinDistance: 0.1, 1510 NumberOfObjects: 3, 1511 Generative: &pb.GenerativeReply{Result: refClass1}, 1512 Rerank: &pb.RerankReply{Score: someFloat64}, 1513 Objects: []*pb.SearchResult{ 1514 { 1515 Properties: &pb.PropertiesResult{ 1516 NonRefProperties: newStruct(t, map[string]interface{}{"word": "word"}), 1517 RefProps: []*pb.RefPropertiesResult{ 1518 { 1519 PropName: "other", 1520 Properties: []*pb.PropertiesResult{ 1521 { 1522 NonRefProperties: newStruct(t, map[string]interface{}{"something": "other"}), 1523 Metadata: &pb.MetadataResult{Vector: []float32{2}, Id: UUID1.String()}, 1524 }, 1525 }, 1526 }, 1527 }, 1528 RefPropsRequested: true, 1529 }, 1530 Metadata: &pb.MetadataResult{ 1531 Id: string(UUID2), 1532 Vector: []float32{3}, 1533 }, 1534 }, 1535 { 1536 Properties: &pb.PropertiesResult{ 1537 NonRefProperties: newStruct(t, map[string]interface{}{"word": "other"}), 1538 }, 1539 Metadata: &pb.MetadataResult{ 1540 Id: string(UUID1), 1541 Vector: []float32{4}, 1542 }, 1543 }, 1544 }, 1545 }}, 1546 outGenerative: refClass2, 1547 }, 1548 } 1549 1550 for _, tt := range tests { 1551 t.Run(tt.name, func(t *testing.T) { 1552 out, err := searchResultsToProto(tt.res, time.Now(), tt.searchParams, scheme, tt.usesWeaviateStruct) 1553 if tt.hasError { 1554 require.NotNil(t, err) 1555 } else { 1556 require.Nil(t, err) 1557 for i := range tt.outSearch { 1558 require.Equal(t, tt.outSearch[i].Properties.String(), out.Results[i].Properties.String()) 1559 // order of the vectors is not guaranteed, doesn't matter for results 1560 vectorsOut := out.Results[i].Metadata.Vectors 1561 vectorsExpected := tt.outSearch[i].Metadata.Vectors 1562 require.ElementsMatch(t, vectorsOut, vectorsExpected) 1563 1564 out.Results[i].Metadata.Vectors = nil 1565 tt.outSearch[i].Metadata.Vectors = nil 1566 require.Equal(t, tt.outSearch[i].Metadata.String(), out.Results[i].Metadata.String()) 1567 } 1568 require.Equal(t, tt.outGenerative, *out.GenerativeGroupedResult) 1569 } 1570 }) 1571 } 1572 }