results.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. // Licensed to the LF AI & Data foundation under one
  2. // or more contributor license agreements. See the NOTICE file
  3. // distributed with this work for additional information
  4. // regarding copyright ownership. The ASF licenses this file
  5. // to you under the Apache License, Version 2.0 (the
  6. // "License"); you may not use this file except in compliance
  7. // with the License. You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. package client
  17. import (
  18. "reflect"
  19. "runtime/debug"
  20. "github.com/cockroachdb/errors"
  21. "github.com/milvus-io/milvus/client/v2/column"
  22. "github.com/milvus-io/milvus/client/v2/entity"
  23. "github.com/milvus-io/milvus/client/v2/row"
  24. )
  25. // ResultSet is struct for search result set.
  26. type ResultSet struct {
  27. // internal schema for unmarshaling
  28. sch *entity.Schema
  29. ResultCount int // the returning entry count
  30. GroupByValue column.Column
  31. IDs column.Column // auto generated id, can be mapped to the columns from `Insert` API
  32. Fields DataSet // output field data
  33. Scores []float32 // distance to the target vector
  34. Err error // search error if any
  35. }
  36. // GetColumn returns column with provided field name.
  37. func (rs *ResultSet) GetColumn(fieldName string) column.Column {
  38. for _, column := range rs.Fields {
  39. if column.Name() == fieldName {
  40. return column
  41. }
  42. }
  43. return nil
  44. }
  45. // Unmarshal puts dataset into receiver in row based way.
  46. // `receiver` shall be a slice of pointer of model struct
  47. // eg, []*Records, in which type `Record` defines the row data.
  48. // note that distance/score is not unmarshaled here.
  49. func (sr *ResultSet) Unmarshal(receiver any) (err error) {
  50. err = sr.Fields.Unmarshal(receiver)
  51. if err != nil {
  52. return err
  53. }
  54. return sr.fillPKEntry(receiver)
  55. }
  56. func (sr *ResultSet) fillPKEntry(receiver any) (err error) {
  57. defer func() {
  58. if x := recover(); x != nil {
  59. err = errors.Newf("failed to unmarshal result set: %v, stack: %v", x, string(debug.Stack()))
  60. }
  61. }()
  62. rr := reflect.ValueOf(receiver)
  63. if rr.Kind() == reflect.Ptr {
  64. if rr.IsNil() && rr.CanAddr() {
  65. rr.Set(reflect.New(rr.Type().Elem()))
  66. }
  67. rr = rr.Elem()
  68. }
  69. rt := rr.Type()
  70. rv := rr
  71. switch rt.Kind() {
  72. case reflect.Slice:
  73. pkField := sr.sch.PKField()
  74. et := rt.Elem()
  75. for et.Kind() == reflect.Ptr {
  76. et = et.Elem()
  77. }
  78. candidates := row.ParseCandidate(et)
  79. candi, ok := candidates[pkField.Name]
  80. if !ok {
  81. // pk field not found in struct, skip
  82. return nil
  83. }
  84. for i := 0; i < sr.IDs.Len(); i++ {
  85. row := rv.Index(i)
  86. for row.Kind() == reflect.Ptr {
  87. row = row.Elem()
  88. }
  89. val, err := sr.IDs.Get(i)
  90. if err != nil {
  91. return err
  92. }
  93. row.Field(candi).Set(reflect.ValueOf(val))
  94. }
  95. rr.Set(rv)
  96. default:
  97. return errors.Newf("receiver need to be slice or array but get %v", rt.Kind())
  98. }
  99. return nil
  100. }
  101. // DataSet is an alias type for column slice.
  102. // Returned by query API.
  103. type DataSet []column.Column
  104. // Len returns the row count of dataset.
  105. // if there is no column, it shall return 0.
  106. func (ds DataSet) Len() int {
  107. if len(ds) == 0 {
  108. return 0
  109. }
  110. return ds[0].Len()
  111. }
  112. // Unmarshal puts dataset into receiver in row based way.
  113. // `receiver` shall be a slice of pointer of model struct
  114. // eg, []*Records, in which type `Record` defines the row data.
  115. func (ds DataSet) Unmarshal(receiver any) (err error) {
  116. defer func() {
  117. if x := recover(); x != nil {
  118. err = errors.Newf("failed to unmarshal result set: %v, stack: %v", x, string(debug.Stack()))
  119. }
  120. }()
  121. rr := reflect.ValueOf(receiver)
  122. if rr.Kind() == reflect.Ptr {
  123. if rr.IsNil() && rr.CanAddr() {
  124. rr.Set(reflect.New(rr.Type().Elem()))
  125. }
  126. rr = rr.Elem()
  127. }
  128. rt := rr.Type()
  129. rv := rr
  130. switch rt.Kind() {
  131. // TODO maybe support Array and just fill data
  132. // case reflect.Array:
  133. case reflect.Slice:
  134. et := rt.Elem()
  135. if et.Kind() != reflect.Ptr {
  136. return errors.Newf("receiver must be slice of pointers but get: %v", et.Kind())
  137. }
  138. for et.Kind() == reflect.Ptr {
  139. et = et.Elem()
  140. }
  141. for i := 0; i < ds.Len(); i++ {
  142. data := reflect.New(et)
  143. err := ds.fillData(data.Elem(), et, i)
  144. if err != nil {
  145. return err
  146. }
  147. rv = reflect.Append(rv, data)
  148. }
  149. rr.Set(rv)
  150. default:
  151. return errors.Newf("receiver need to be slice or array but get %v", rt.Kind())
  152. }
  153. return nil
  154. }
  155. func (ds DataSet) fillData(data reflect.Value, dataType reflect.Type, idx int) error {
  156. m := row.ParseCandidate(dataType)
  157. for i := 0; i < len(ds); i++ {
  158. name := ds[i].Name()
  159. fidx, ok := m[name]
  160. if !ok {
  161. // if target is not found, the behavior here is to ignore the column
  162. // `strict` mode could be added in the future to return error if any column missing
  163. continue
  164. }
  165. val, err := ds[i].Get(idx)
  166. if err != nil {
  167. return err
  168. }
  169. // TODO check datatype, return error here instead of reflect panicking & recover
  170. data.Field(fidx).Set(reflect.ValueOf(val))
  171. }
  172. return nil
  173. }