github.com/milvus-io/milvus-sdk-go/v2@v2.4.1/client/index.go (about) 1 // Copyright (C) 2019-2021 Zilliz. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance 4 // with the License. You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software distributed under the License 9 // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 10 // or implied. See the License for the specific language governing permissions and limitations under the License. 11 12 package client 13 14 import ( 15 "context" 16 "fmt" 17 "strconv" 18 "time" 19 20 "github.com/milvus-io/milvus-proto/go-api/v2/commonpb" 21 "github.com/milvus-io/milvus-proto/go-api/v2/milvuspb" 22 "github.com/milvus-io/milvus-sdk-go/v2/entity" 23 ) 24 25 const ( 26 mmapKey = "mmap.enabled" 27 ) 28 29 func (c *GrpcClient) checkCollField(ctx context.Context, collName string, fieldName string, filters ...func(string, string, *entity.Field) error) error { 30 if err := c.checkCollectionExists(ctx, collName); err != nil { 31 return err 32 } 33 coll, err := c.DescribeCollection(ctx, collName) 34 if err != nil { 35 return err 36 } 37 var f *entity.Field 38 for _, field := range coll.Schema.Fields { 39 if field.Name == fieldName { 40 f = field 41 for _, filter := range filters { 42 if err := filter(collName, fieldName, f); err != nil { 43 return err 44 } 45 } 46 break 47 } 48 } 49 if f == nil { 50 return fmt.Errorf("field %s of collection %s does not exist", fieldName, collName) 51 } 52 return nil 53 } 54 55 func isVectorField(collName, fieldName string, f *entity.Field) error { 56 if f.DataType != entity.FieldTypeFloatVector && f.DataType != entity.FieldTypeBinaryVector { 57 return fmt.Errorf("field %s of collection %s is not vector field", fieldName, collName) 58 } 59 return nil 60 } 61 62 type indexDef struct { 63 name string 64 fieldName string 65 collectionName string 66 params []*commonpb.KeyValuePair 67 MsgBase *commonpb.MsgBase 68 } 69 70 // IndexOption is the predefined function to alter index def. 71 // shared among create, describe, drop indexes operations. 72 type IndexOption func(*indexDef) 73 74 // WithIndexName returns an IndexOption with customized index name. 75 func WithIndexName(name string) IndexOption { 76 return func(def *indexDef) { 77 def.name = name 78 } 79 } 80 81 func WithIndexMsgBase(msgBase *commonpb.MsgBase) IndexOption { 82 return func(def *indexDef) { 83 def.MsgBase = msgBase 84 } 85 } 86 87 func WithMmap(enabled bool) IndexOption { 88 return func(id *indexDef) { 89 id.params = append(id.params, &commonpb.KeyValuePair{ 90 Key: mmapKey, 91 Value: strconv.FormatBool(enabled), 92 }) 93 } 94 } 95 96 func getIndexDef(opts ...IndexOption) indexDef { 97 idxDef := indexDef{} 98 for _, opt := range opts { 99 opt(&idxDef) 100 } 101 return idxDef 102 } 103 104 // CreateIndex create index for collection 105 // Deprecated please use CreateIndexV2 instead. 106 func (c *GrpcClient) CreateIndex(ctx context.Context, collName string, fieldName string, 107 idx entity.Index, async bool, opts ...IndexOption) error { 108 if c.Service == nil { 109 return ErrClientNotReady 110 } 111 if err := c.checkCollField(ctx, collName, fieldName); err != nil { 112 return err 113 } 114 115 idxDef := getIndexDef(opts...) 116 117 req := &milvuspb.CreateIndexRequest{ 118 Base: idxDef.MsgBase, 119 DbName: "", // reserved 120 CollectionName: collName, 121 FieldName: fieldName, 122 IndexName: idxDef.name, 123 ExtraParams: entity.MapKvPairs(idx.Params()), 124 } 125 126 req.ExtraParams = append(req.ExtraParams, idxDef.params...) 127 128 resp, err := c.Service.CreateIndex(ctx, req) 129 if err != nil { 130 return err 131 } 132 if err = handleRespStatus(resp); err != nil { 133 return err 134 } 135 if !async { // sync mode, wait index building result 136 for { 137 idxDesc, err := c.describeIndex(ctx, collName, fieldName, opts...) 138 if err != nil { 139 return err 140 } 141 for _, desc := range idxDesc { 142 if (idxDef.name == "" && desc.GetFieldName() == fieldName) || idxDef.name == desc.GetIndexName() { 143 switch desc.GetState() { 144 case commonpb.IndexState_Finished: 145 return nil 146 case commonpb.IndexState_Failed: 147 return fmt.Errorf("create index failed, reason: %s", desc.GetIndexStateFailReason()) 148 } 149 } 150 } 151 152 time.Sleep(100 * time.Millisecond) // wait 100ms 153 } 154 } 155 return nil 156 } 157 158 // AlterIndex modifies the index params 159 func (c *GrpcClient) AlterIndex(ctx context.Context, collName string, indexName string, opts ...IndexOption) error { 160 if c.Service == nil { 161 return ErrClientNotReady 162 } 163 164 idxDef := getIndexDef(opts...) 165 166 req := &milvuspb.AlterIndexRequest{ 167 Base: idxDef.MsgBase, 168 DbName: "", // reserved 169 CollectionName: collName, 170 IndexName: indexName, 171 ExtraParams: idxDef.params, 172 } 173 174 resp, err := c.Service.AlterIndex(ctx, req) 175 if err != nil { 176 return err 177 } 178 return handleRespStatus(resp) 179 } 180 181 // DescribeIndex describe index 182 func (c *GrpcClient) DescribeIndex(ctx context.Context, collName string, fieldName string, opts ...IndexOption) ([]entity.Index, error) { 183 if c.Service == nil { 184 return []entity.Index{}, ErrClientNotReady 185 } 186 if err := c.checkCollField(ctx, collName, fieldName); err != nil { 187 return []entity.Index{}, err 188 } 189 190 idxDesc, err := c.describeIndex(ctx, collName, fieldName, opts...) 191 if err != nil { 192 return nil, err 193 } 194 195 indexes := make([]entity.Index, 0, len(idxDesc)) 196 for _, info := range idxDesc { 197 if fieldName != "" && info.GetFieldName() != fieldName { 198 continue 199 } 200 params := entity.KvPairsMap(info.Params) 201 it := params["index_type"] // TODO change to const 202 idx := entity.NewGenericIndex( 203 info.IndexName, 204 entity.IndexType(it), 205 params, 206 ) 207 indexes = append(indexes, idx) 208 } 209 return indexes, nil 210 } 211 212 // DropIndex drop index from collection 213 // Deprecate please use DropIndexV2 instead. 214 func (c *GrpcClient) DropIndex(ctx context.Context, collName string, fieldName string, opts ...IndexOption) error { 215 if c.Service == nil { 216 return ErrClientNotReady 217 } 218 219 idxDef := getIndexDef(opts...) 220 req := &milvuspb.DropIndexRequest{ 221 Base: idxDef.MsgBase, 222 DbName: "", //reserved, 223 CollectionName: collName, 224 FieldName: fieldName, 225 IndexName: idxDef.name, 226 } 227 if idxDef.name != "" { 228 req.IndexName = idxDef.name 229 } 230 231 resp, err := c.Service.DropIndex(ctx, req) 232 if err != nil { 233 return err 234 } 235 return handleRespStatus(resp) 236 } 237 238 // GetIndexState get index state 239 func (c *GrpcClient) GetIndexState(ctx context.Context, collName string, fieldName string, opts ...IndexOption) (entity.IndexState, error) { 240 if c.Service == nil { 241 return entity.IndexState(commonpb.IndexState_Failed), ErrClientNotReady 242 } 243 if err := c.checkCollField(ctx, collName, fieldName); err != nil { 244 return entity.IndexState(commonpb.IndexState_IndexStateNone), err 245 } 246 247 idxDef := getIndexDef(opts...) 248 req := &milvuspb.GetIndexStateRequest{ 249 DbName: "", 250 CollectionName: collName, 251 FieldName: fieldName, 252 IndexName: idxDef.name, 253 } 254 resp, err := c.Service.GetIndexState(ctx, req) 255 if err != nil { 256 return entity.IndexState(commonpb.IndexState_IndexStateNone), err 257 } 258 if err := handleRespStatus(resp.GetStatus()); err != nil { 259 return entity.IndexState(commonpb.IndexState_IndexStateNone), err 260 } 261 262 return entity.IndexState(resp.GetState()), nil 263 } 264 265 // GetIndexBuildProgress get index building progress 266 func (c *GrpcClient) GetIndexBuildProgress(ctx context.Context, collName string, fieldName string, opts ...IndexOption) (total, indexed int64, err error) { 267 if c.Service == nil { 268 return 0, 0, ErrClientNotReady 269 } 270 if err := c.checkCollField(ctx, collName, fieldName); err != nil { 271 return 0, 0, err 272 } 273 274 idxDef := getIndexDef(opts...) 275 req := &milvuspb.GetIndexBuildProgressRequest{ 276 DbName: "", 277 CollectionName: collName, 278 FieldName: fieldName, 279 IndexName: idxDef.name, 280 } 281 resp, err := c.Service.GetIndexBuildProgress(ctx, req) 282 if err != nil { 283 return 0, 0, err 284 } 285 if err = handleRespStatus(resp.GetStatus()); err != nil { 286 return 0, 0, err 287 } 288 return resp.GetTotalRows(), resp.GetIndexedRows(), nil 289 } 290 291 func (c *GrpcClient) describeIndex(ctx context.Context, collName string, fieldName string, opts ...IndexOption) ([]*milvuspb.IndexDescription, error) { 292 idxDef := getIndexDef(opts...) 293 req := &milvuspb.DescribeIndexRequest{ 294 CollectionName: collName, 295 FieldName: fieldName, 296 IndexName: idxDef.name, 297 } 298 299 resp, err := c.Service.DescribeIndex(ctx, req) 300 if err != nil { 301 return nil, err 302 } 303 if err := handleRespStatus(resp.GetStatus()); err != nil { 304 return nil, err 305 } 306 307 return resp.GetIndexDescriptions(), nil 308 }