Browse Source

DescribeIndex enhancement (#957)

Signed-off-by: yhmo <yihua.mo@zilliz.com>
groot 1 year ago
parent
commit
260ec00d63

+ 2 - 1
src/main/java/io/milvus/client/AbstractMilvusGrpcClient.java

@@ -1401,7 +1401,8 @@ public abstract class AbstractMilvusGrpcClient implements MilvusClient {
         try {
             DescribeIndexRequest.Builder builder = DescribeIndexRequest.newBuilder()
                     .setCollectionName(requestParam.getCollectionName())
-                    .setIndexName(requestParam.getIndexName());
+                    .setIndexName(requestParam.getIndexName())
+                    .setFieldName(requestParam.getFieldName());
 
             if (StringUtils.isNotEmpty(requestParam.getDatabaseName())) {
                 builder.setDbName(requestParam.getDatabaseName());

+ 0 - 2
src/main/java/io/milvus/common/clientenum/ConsistencyLevelEnum.java

@@ -49,6 +49,4 @@ public enum ConsistencyLevelEnum {
         }
         return null;
     }
-
-
 }

+ 10 - 0
src/main/java/io/milvus/param/IndexBuildState.java

@@ -0,0 +1,10 @@
+package io.milvus.param;
+
+public enum IndexBuildState {
+    IndexStateNone,
+    Unissued,
+    InProgress,
+    Finished,
+    Failed,
+    Retry,
+}

+ 15 - 0
src/main/java/io/milvus/param/index/DescribeIndexParam.java

@@ -37,11 +37,13 @@ public class DescribeIndexParam {
     private final String databaseName;
     private final String collectionName;
     private final String indexName;
+    private final String fieldName;
 
     private DescribeIndexParam(@NonNull Builder builder) {
         this.databaseName = builder.databaseName;
         this.collectionName = builder.collectionName;
         this.indexName = builder.indexName;
+        this.fieldName = builder.fieldName;
     }
 
     public static Builder newBuilder() {
@@ -55,6 +57,7 @@ public class DescribeIndexParam {
         private String databaseName;
         private String collectionName;
         private String indexName = "";
+        private String fieldName = "";
 
         private Builder() {
         }
@@ -87,11 +90,23 @@ public class DescribeIndexParam {
          * @param indexName field name
          * @return <code>Builder</code>
          */
+        @Deprecated
         public Builder withIndexName(String indexName) {
             this.indexName = indexName;
             return this;
         }
 
+        /**
+         * Sets the target field name. Field name can be empty or null.
+         * If no field name is specified, then return all this collection indexes.
+         * @param fieldName field name
+         * @return <code>Builder</code>
+         */
+        public Builder withFieldName(String fieldName) {
+            this.fieldName = fieldName;
+            return this;
+        }
+
         /**
          * Verifies parameters and creates a new {@link DescribeIndexParam} instance.
          *

+ 31 - 10
src/main/java/io/milvus/response/DescCollResponseWrapper.java

@@ -19,6 +19,7 @@
 
 package io.milvus.response;
 
+import io.milvus.common.clientenum.ConsistencyLevelEnum;
 import io.milvus.exception.ParamException;
 import io.milvus.grpc.*;
 import io.milvus.param.ParamUtils;
@@ -26,10 +27,7 @@ import io.milvus.param.collection.CollectionSchemaParam;
 import io.milvus.param.collection.FieldType;
 import lombok.NonNull;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 /**
  * Util class to wrap response of <code>describeCollection</code> interface.
@@ -41,11 +39,6 @@ public class DescCollResponseWrapper {
         this.response = response;
     }
 
-    public boolean getEnableDynamicField() {
-        CollectionSchema schema = response.getSchema();
-        return schema.getEnableDynamicField();
-    }
-
     /**
      * Get name of the collection.
      *
@@ -56,6 +49,15 @@ public class DescCollResponseWrapper {
         return schema.getName();
     }
 
+    /**
+     * Get database name of the collection.
+     *
+     * @return <code>String</code> name of the database
+     */
+    public String getDatabaseName() {
+        return response.getDbName();
+    }
+
     /**
      * Get description of the collection.
      *
@@ -84,6 +86,16 @@ public class DescCollResponseWrapper {
         return response.getShardsNum();
     }
 
+    /**
+     * Get consistency level of the collection.
+     *
+     * @return <code>ConsistencyLevelEnum</code> consistency level of the collection
+     */
+    public ConsistencyLevelEnum getConsistencyLevel() {
+        // may throw IllegalArgumentException
+        return ConsistencyLevelEnum.valueOf(response.getConsistencyLevel().name().toUpperCase());
+    }
+
     /**
      * Get utc timestamp when collection created.
      *
@@ -140,6 +152,13 @@ public class DescCollResponseWrapper {
         return null;
     }
 
+    // duplicated with isDynamicFieldEnabled()
+    @Deprecated
+    public boolean getEnableDynamicField() {
+        CollectionSchema schema = response.getSchema();
+        return schema.getEnableDynamicField();
+    }
+
     /**
      * Get whether the collection dynamic field is enabled
      *
@@ -245,7 +264,7 @@ public class DescCollResponseWrapper {
     public CollectionSchemaParam getSchema() {
         return CollectionSchemaParam.newBuilder()
                 .withFieldTypes(getFields())
-                .withEnableDynamicField(getEnableDynamicField())
+                .withEnableDynamicField(isDynamicFieldEnabled())
                 .build();
     }
 
@@ -258,6 +277,7 @@ public class DescCollResponseWrapper {
     public String toString() {
         return "Collection Description{" +
                 "name:'" + getCollectionName() + '\'' +
+                ", databaseName:'" + getDatabaseName() + '\'' +
                 ", description:'" + getCollectionDescription() + '\'' +
                 ", id:" + getCollectionID() +
                 ", shardNumber:" + getShardNumber() +
@@ -265,6 +285,7 @@ public class DescCollResponseWrapper {
                 ", aliases:" + getAliases().toString() +
                 ", fields:" + getFields().toString() +
                 ", isDynamicFieldEnabled:" + isDynamicFieldEnabled() +
+                ", consistencyLevel:" + getConsistencyLevel().name() +
                 ", properties:" + getProperties() +
                 '}';
     }

+ 41 - 27
src/main/java/io/milvus/response/DescIndexResponseWrapper.java

@@ -24,9 +24,11 @@ import io.milvus.grpc.DescribeIndexResponse;
 
 import io.milvus.param.Constant;
 import io.milvus.param.IndexType;
+import io.milvus.param.IndexBuildState;
 import io.milvus.param.MetricType;
 import lombok.Getter;
 import lombok.NonNull;
+import lombok.ToString;
 
 import java.util.*;
 
@@ -49,8 +51,7 @@ public class DescIndexResponseWrapper {
         List<IndexDesc> results = new ArrayList<>();
         List<IndexDescription> descriptions = response.getIndexDescriptionsList();
         descriptions.forEach((desc)->{
-            IndexDesc res = new IndexDesc(desc.getFieldName(), desc.getIndexName(), desc.getIndexID());
-            desc.getParamsList().forEach((kv)-> res.addParam(kv.getKey(), kv.getValue()));
+            IndexDesc res = convertIndexDescInternal(desc);
             results.add(res);
         });
 
@@ -65,28 +66,60 @@ public class DescIndexResponseWrapper {
      * @return {@link IndexDesc} description of the index
      */
     public IndexDesc getIndexDescByFieldName(@NonNull String fieldName) {
-        for (int i = 0; i < response.getIndexDescriptionsCount(); ++i) {
-            IndexDescription desc = response.getIndexDescriptions(i);
+        for (IndexDescription desc : response.getIndexDescriptionsList()) {
             if (fieldName.compareTo(desc.getFieldName()) == 0) {
-                IndexDesc res = new IndexDesc(desc.getFieldName(), desc.getIndexName(), desc.getIndexID());
-                desc.getParamsList().forEach((kv)-> res.addParam(kv.getKey(), kv.getValue()));
-                return res;
+                return convertIndexDescInternal(desc);
             }
         }
 
         return null;
     }
 
+    /**
+     * Get index description by index name.
+     * Return null if the index doesn't exist
+     *
+     * @param indexName index name to get index description
+     * @return {@link IndexDesc} description of the index
+     */
+    public IndexDesc getIndexDescByIndexName(@NonNull String indexName) {
+        for (IndexDescription desc : response.getIndexDescriptionsList()) {
+            if (indexName.compareTo(desc.getIndexName()) == 0) {
+                return convertIndexDescInternal(desc);
+            }
+        }
+
+        return null;
+    }
+
+    private IndexDesc convertIndexDescInternal(IndexDescription desc) {
+        IndexDesc res = new IndexDesc(desc.getFieldName(), desc.getIndexName(), desc.getIndexID());
+        res.indexedRows = desc.getIndexedRows();
+        res.totalRows = desc.getTotalRows();
+        res.pendingIndexRows = desc.getPendingIndexRows();
+        res.indexState = IndexBuildState.valueOf(desc.getState().name());
+        res.indexFailedReason = desc.getIndexStateFailReason();
+        desc.getParamsList().forEach((kv)-> res.addParam(kv.getKey(), kv.getValue()));
+        return res;
+    }
+
     /**
      * Internal-use class to wrap response of <code>describeIndex</code> interface.
      */
     @Getter
+    @ToString
     public static final class IndexDesc {
         private final String fieldName;
         private final String indexName;
         private final long id;
         private final Map<String, String> params = new HashMap<>();
 
+        long indexedRows = 0;
+        long totalRows = 0;
+        long pendingIndexRows = 0;
+        private IndexBuildState indexState = IndexBuildState.IndexStateNone;
+        String indexFailedReason = "";
+
         public IndexDesc(@NonNull String fieldName, @NonNull String indexName, long id) {
             this.fieldName = fieldName;
             this.indexName = indexName;
@@ -100,7 +133,7 @@ public class DescIndexResponseWrapper {
         public IndexType getIndexType() {
             if (this.params.containsKey(Constant.INDEX_TYPE)) {
                 // may throw IllegalArgumentException
-                return IndexType.valueOf(params.get(Constant.INDEX_TYPE).toUpperCase(Locale.ROOT));
+                return IndexType.valueOf(params.get(Constant.INDEX_TYPE).toUpperCase());
             }
 
             return IndexType.None;
@@ -123,24 +156,5 @@ public class DescIndexResponseWrapper {
 
             return "";
         }
-
-        @Override
-        public String toString() {
-            return "IndexDesc(fieldName: " + getFieldName() + " indexName: " + getIndexName() +
-                    " id: " + getId() + " indexType: " + getIndexType().name() + " metricType: " +
-                    getMetricType().name() + " extraParam: " + getExtraParam() + ")";
-        }
-    }
-
-    /**
-     * Construct a <code>String</code> by {@link DescIndexResponseWrapper} instance.
-     *
-     * @return <code>String</code>
-     */
-    @Override
-    public String toString() {
-        return "Index description{" +
-                getIndexDescriptions().toString() +
-                '}';
     }
 }

+ 10 - 0
src/main/java/io/milvus/v2/common/IndexBuildState.java

@@ -0,0 +1,10 @@
+package io.milvus.v2.common;
+
+public enum IndexBuildState {
+    IndexStateNone,
+    Unissued,
+    InProgress,
+    Finished,
+    Failed,
+    Retry,
+}

+ 2 - 0
src/main/java/io/milvus/v2/service/collection/CollectionService.java

@@ -210,6 +210,7 @@ public class CollectionService extends BaseService {
     public static DescribeCollectionResp convertDescCollectionResp(DescribeCollectionResponse response) {
         DescribeCollectionResp describeCollectionResp = DescribeCollectionResp.builder()
                 .collectionName(response.getCollectionName())
+                .databaseName(response.getDbName())
                 .description(response.getSchema().getDescription())
                 .numOfPartitions(response.getNumPartitions())
                 .collectionSchema(SchemaUtils.convertFromGrpcCollectionSchema(response.getSchema()))
@@ -219,6 +220,7 @@ public class CollectionService extends BaseService {
                 .vectorFieldNames(response.getSchema().getFieldsList().stream().filter(fieldSchema -> ParamUtils.isVectorDataType(fieldSchema.getDataType())).map(FieldSchema::getName).collect(java.util.stream.Collectors.toList()))
                 .primaryFieldName(response.getSchema().getFieldsList().stream().filter(FieldSchema::getIsPrimaryKey).map(FieldSchema::getName).collect(java.util.stream.Collectors.toList()).get(0))
                 .createTime(response.getCreatedTimestamp())
+                .consistencyLevel(io.milvus.v2.common.ConsistencyLevel.valueOf(response.getConsistencyLevel().name().toUpperCase()))
                 .build();
         return describeCollectionResp;
     }

+ 3 - 0
src/main/java/io/milvus/v2/service/collection/response/DescribeCollectionResp.java

@@ -19,6 +19,7 @@
 
 package io.milvus.v2.service.collection.response;
 
+import io.milvus.v2.common.ConsistencyLevel;
 import io.milvus.v2.service.collection.request.CreateCollectionReq;
 import lombok.Data;
 import lombok.experimental.SuperBuilder;
@@ -29,6 +30,7 @@ import java.util.List;
 @SuperBuilder
 public class DescribeCollectionResp {
     private String collectionName;
+    private String databaseName;
     private String description;
     private Long numOfPartitions;
 
@@ -40,4 +42,5 @@ public class DescribeCollectionResp {
 
     private CreateCollectionReq.CollectionSchema collectionSchema;
     private Long createTime;
+    private ConsistencyLevel consistencyLevel;
 }

+ 1 - 2
src/main/java/io/milvus/v2/service/index/IndexService.java

@@ -125,8 +125,7 @@ public class IndexService extends BaseService {
         } else if (indexs.size() > 1) {
             throw new MilvusClientException(ErrorCode.SERVER_ERROR, "More than one index found");
         }
-        return convertUtils.convertToDescribeIndexResp(indexs.get(0));
-
+        return convertUtils.convertToDescribeIndexResp(indexs);
     }
 
     public List<String> listIndexes(MilvusServiceGrpc.MilvusServiceBlockingStub blockingStub, ListIndexesReq request) {

+ 53 - 5
src/main/java/io/milvus/v2/service/index/response/DescribeIndexResp.java

@@ -19,17 +19,65 @@
 
 package io.milvus.v2.service.index.response;
 
+import io.milvus.grpc.IndexDescription;
+import io.milvus.response.DescIndexResponseWrapper;
+import io.milvus.v2.common.IndexBuildState;
+import io.milvus.v2.common.IndexParam;
+import lombok.Builder;
 import lombok.Data;
+import lombok.NonNull;
 import lombok.experimental.SuperBuilder;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 @Data
 @SuperBuilder
 public class DescribeIndexResp {
-    private String indexName;
-    private String indexType;
-    private String metricType;
-    private String fieldName;
-    private Map<String, Object> extraParams;
+    @Builder.Default
+    List<IndexDesc> indexDescriptions = new ArrayList<>();
+
+    public IndexDesc getIndexDescByFieldName(@NonNull String fieldName) {
+        for (IndexDesc desc : indexDescriptions) {
+            if (desc.fieldName.equals(fieldName)) {
+                return desc;
+            }
+        }
+        return null;
+    }
+
+    public IndexDesc getIndexDescByIndexName(@NonNull String indexName) {
+        for (IndexDesc desc : indexDescriptions) {
+            if (desc.indexName.equals(indexName)) {
+                return desc;
+            }
+        }
+        return null;
+    }
+
+    @Data
+    @SuperBuilder
+    public static final class IndexDesc {
+        private String fieldName;
+        private String indexName;
+        private long id;
+        @Builder.Default
+        private IndexParam.IndexType indexType = IndexParam.IndexType.None;
+        @Builder.Default
+        private IndexParam.MetricType metricType = IndexParam.MetricType.INVALID;
+        @Builder.Default
+        private Map<String, String> extraParams = new HashMap<>();
+        @Builder.Default
+        long indexedRows = 0;
+        @Builder.Default
+        long totalRows = 0;
+        @Builder.Default
+        long pendingIndexRows = 0;
+        @Builder.Default
+        private IndexBuildState indexState = IndexBuildState.IndexStateNone;
+        @Builder.Default
+        String indexFailedReason = "";
+    }
 }

+ 37 - 16
src/main/java/io/milvus/v2/utils/ConvertUtils.java

@@ -20,8 +20,11 @@
 package io.milvus.v2.utils;
 
 import io.milvus.grpc.*;
+import io.milvus.param.Constant;
 import io.milvus.response.QueryResultsWrapper;
 import io.milvus.response.SearchResultsWrapper;
+import io.milvus.v2.common.IndexBuildState;
+import io.milvus.v2.common.IndexParam;
 import io.milvus.v2.service.index.response.DescribeIndexResp;
 import io.milvus.v2.service.vector.response.QueryResp;
 import io.milvus.v2.service.vector.response.SearchResp;
@@ -72,23 +75,41 @@ public class ConvertUtils {
         return searchResults;
     }
 
-    public DescribeIndexResp convertToDescribeIndexResp(IndexDescription response) {
-        DescribeIndexResp describeIndexResp = DescribeIndexResp.builder()
-                .indexName(response.getIndexName())
-                .fieldName(response.getFieldName())
-                .build();
-        Map<String, Object> extraParams = new HashMap<>();
-        List<KeyValuePair> params = response.getParamsList();
-        for(KeyValuePair param : params) {
-            if (param.getKey().equals("index_type")) {
-                describeIndexResp.setIndexType(param.getValue());
-            } else if (param.getKey().equals("metric_type")) {
-                describeIndexResp.setMetricType(param.getValue());
-            } else {
-                extraParams.put(param.getKey(), param.getValue());
+    public DescribeIndexResp convertToDescribeIndexResp(List<IndexDescription> response) {
+        List<DescribeIndexResp.IndexDesc> descs = new ArrayList<>();
+        for (IndexDescription description : response) {
+            Map<String, String> extraParams = new HashMap<>();
+            List<KeyValuePair> params = description.getParamsList();
+            IndexParam.IndexType indexType = IndexParam.IndexType.None;
+            IndexParam.MetricType metricType = IndexParam.MetricType.INVALID;
+            for(KeyValuePair param : params) {
+                if (param.getKey().equals(Constant.INDEX_TYPE)) {
+                    // may throw IllegalArgumentException
+                    indexType = IndexParam.IndexType.valueOf(param.getValue().toUpperCase());
+                } else if (param.getKey().equals(Constant.METRIC_TYPE)) {
+                    // may throw IllegalArgumentException
+                    metricType = IndexParam.MetricType.valueOf(param.getValue());
+                } else {
+                    extraParams.put(param.getKey(), param.getValue());
+                }
             }
+
+            DescribeIndexResp.IndexDesc desc = DescribeIndexResp.IndexDesc.builder()
+                    .indexName(description.getIndexName())
+                    .fieldName(description.getFieldName())
+                    .id(description.getIndexID())
+                    .indexType(indexType)
+                    .metricType(metricType)
+                    .totalRows(description.getTotalRows())
+                    .indexedRows(description.getIndexedRows())
+                    .pendingIndexRows(description.getPendingIndexRows())
+                    .indexState(IndexBuildState.valueOf(description.getState().name()))
+                    .indexFailedReason(description.getIndexStateFailReason())
+                    .extraParams(extraParams)
+                    .build();
+            descs.add(desc);
         }
-        describeIndexResp.setExtraParams(extraParams);
-        return describeIndexResp;
+
+        return DescribeIndexResp.builder().indexDescriptions(descs).build();
     }
 }

+ 70 - 28
src/test/java/io/milvus/client/MilvusClientDockerTest.java

@@ -153,7 +153,6 @@ class MilvusClientDockerTest {
             vectors.add(vector);
         }
         return vectors;
-
     }
 
     protected List<SortedMap<Long, Float>> generateSparseVectors(int count) {
@@ -168,7 +167,6 @@ class MilvusClientDockerTest {
             vectors.add(sparse);
         }
         return vectors;
-
     }
 
     @Test
@@ -220,6 +218,8 @@ class MilvusClientDockerTest {
                 .withCollectionName(randomCollectionName)
                 .withDescription("test")
                 .withFieldTypes(fieldsSchema)
+                .withShardsNum(3)
+                .withConsistencyLevel(ConsistencyLevelEnum.EVENTUALLY)
                 .build();
 
         R<RpcStatus> createR = client.createCollection(createParam);
@@ -229,8 +229,19 @@ class MilvusClientDockerTest {
                 .withCollectionName(randomCollectionName)
                 .build());
 
-        DescCollResponseWrapper desc = new DescCollResponseWrapper(response.getData());
-        System.out.println(desc.toString());
+        DescCollResponseWrapper collDescWrapper = new DescCollResponseWrapper(response.getData());
+        Assertions.assertEquals(randomCollectionName, collDescWrapper.getCollectionName());
+        Assertions.assertEquals("default", collDescWrapper.getDatabaseName());
+        Assertions.assertEquals("test", collDescWrapper.getCollectionDescription());
+        Assertions.assertEquals(3, collDescWrapper.getShardNumber());
+        Assertions.assertEquals(fieldsSchema.size(), collDescWrapper.getFields().size());
+        Assertions.assertEquals(1, collDescWrapper.getVectorFields().size());
+        FieldType primaryField = collDescWrapper.getPrimaryField();
+        Assertions.assertFalse(primaryField.isAutoID());
+        CollectionSchemaParam schema = collDescWrapper.getSchema();
+        Assertions.assertFalse(schema.isEnableDynamicField());
+        Assertions.assertEquals(ConsistencyLevelEnum.EVENTUALLY, collDescWrapper.getConsistencyLevel());
+        System.out.println(collDescWrapper);
 
         R<ShowPartitionsResponse> spResp = client.showPartitions(ShowPartitionsParam.newBuilder()
                 .withCollectionName(randomCollectionName)
@@ -295,6 +306,7 @@ class MilvusClientDockerTest {
         Assertions.assertEquals(R.Status.Success.getCode(), statPartR.getStatus().intValue());
 
         GetPartStatResponseWrapper statPart = new GetPartStatResponseWrapper(statPartR.getData());
+        Assertions.assertEquals(rowCount, statPart.getRowCount());
         System.out.println("Partition row count: " + statPart.getRowCount());
 
         // create index on scalar field
@@ -332,7 +344,17 @@ class MilvusClientDockerTest {
         R<DescribeIndexResponse> descIndexR = client.describeIndex(descIndexParam);
         Assertions.assertEquals(R.Status.Success.getCode(), descIndexR.getStatus().intValue());
 
-        DescIndexResponseWrapper indexDesc = new DescIndexResponseWrapper(descIndexR.getData());
+        DescIndexResponseWrapper indexDescWrapper = new DescIndexResponseWrapper(descIndexR.getData());
+        DescIndexResponseWrapper.IndexDesc indexDesc = indexDescWrapper.getIndexDescByFieldName(field2Name);
+        Assertions.assertNotNull(indexDesc);
+        Assertions.assertEquals(field2Name, indexDesc.getFieldName());
+        Assertions.assertEquals("abv", indexDesc.getIndexName());
+        Assertions.assertEquals(IndexType.HNSW, indexDesc.getIndexType());
+        Assertions.assertEquals(MetricType.L2, indexDesc.getMetricType());
+        Assertions.assertEquals(rowCount, indexDesc.getTotalRows());
+        Assertions.assertEquals(rowCount, indexDesc.getIndexedRows());
+        Assertions.assertEquals(0L, indexDesc.getPendingIndexRows());
+        Assertions.assertTrue(indexDesc.getIndexFailedReason().isEmpty());
         System.out.println("Index description: " + indexDesc.toString());
 
         // load collection
@@ -528,7 +550,7 @@ class MilvusClientDockerTest {
     }
 
     @Test
-    void testBinaryVectors() {
+    void testBinaryVectors() throws InterruptedException {
         String randomCollectionName = generator.generate(10);
 
         // collection schema
@@ -560,6 +582,21 @@ class MilvusClientDockerTest {
         R<RpcStatus> createR = client.createCollection(createParam);
         Assertions.assertEquals(R.Status.Success.getCode(), createR.getStatus().intValue());
 
+        // create index
+        CreateIndexParam indexParam2 = CreateIndexParam.newBuilder()
+                .withCollectionName(randomCollectionName)
+                .withFieldName(field2Name)
+                .withIndexType(IndexType.BIN_IVF_FLAT)
+                .withExtraParam("{\"nlist\":64}")
+                .withMetricType(MetricType.JACCARD)
+                .withSyncMode(Boolean.TRUE)
+                .withSyncWaitingInterval(500L)
+                .withSyncWaitingTimeout(30L)
+                .build();
+
+        R<RpcStatus> createIndexR2 = client.createIndex(indexParam2);
+        Assertions.assertEquals(R.Status.Success.getCode(), createIndexR2.getStatus().intValue());
+
         int rowCount = 10000;
         List<ByteBuffer> vectors = generateBinaryVectors(rowCount);
         // insert data by columns
@@ -610,20 +647,33 @@ class MilvusClientDockerTest {
         System.out.println("Collection row count: " + stat.getRowCount());
         Assertions.assertEquals(rowCount, stat.getRowCount());
 
-        // create index
-        CreateIndexParam indexParam2 = CreateIndexParam.newBuilder()
-                .withCollectionName(randomCollectionName)
-                .withFieldName(field2Name)
-                .withIndexType(IndexType.BIN_IVF_FLAT)
-                .withExtraParam("{\"nlist\":64}")
-                .withMetricType(MetricType.JACCARD)
-                .withSyncMode(Boolean.TRUE)
-                .withSyncWaitingInterval(500L)
-                .withSyncWaitingTimeout(30L)
-                .build();
-
-        R<RpcStatus> createIndexR2 = client.createIndex(indexParam2);
-        Assertions.assertEquals(R.Status.Success.getCode(), createIndexR2.getStatus().intValue());
+        // check index
+        while(true) {
+            DescribeIndexParam descIndexParam = DescribeIndexParam.newBuilder()
+                    .withCollectionName(randomCollectionName)
+                    .withFieldName(field2Name)
+                    .build();
+            R<DescribeIndexResponse> descIndexR = client.describeIndex(descIndexParam);
+            Assertions.assertEquals(R.Status.Success.getCode(), descIndexR.getStatus().intValue());
+
+            DescIndexResponseWrapper indexDescWrapper = new DescIndexResponseWrapper(descIndexR.getData());
+            DescIndexResponseWrapper.IndexDesc indexDesc = indexDescWrapper.getIndexDescByFieldName(field2Name);
+            Assertions.assertNotNull(indexDesc);
+            if (indexDesc.getTotalRows() != indexDesc.getIndexedRows()) {
+                System.out.println("Waiting index to be finished...");
+                TimeUnit.SECONDS.sleep(1);
+                continue;
+            }
+            Assertions.assertEquals(field2Name, indexDesc.getFieldName());
+            Assertions.assertEquals(IndexType.BIN_IVF_FLAT, indexDesc.getIndexType());
+            Assertions.assertEquals(MetricType.JACCARD, indexDesc.getMetricType());
+            Assertions.assertEquals(rowCount, indexDesc.getTotalRows());
+            Assertions.assertEquals(rowCount, indexDesc.getIndexedRows());
+            Assertions.assertEquals(0L, indexDesc.getPendingIndexRows());
+            Assertions.assertTrue(indexDesc.getIndexFailedReason().isEmpty());
+            System.out.println("Index description: " + indexDesc);
+            break;
+        }
 
         // load collection
         R<RpcStatus> loadR = client.loadCollection(LoadCollectionParam.newBuilder()
@@ -701,14 +751,6 @@ class MilvusClientDockerTest {
         R<RpcStatus> createIndexR = client.createIndex(indexParam);
         Assertions.assertEquals(R.Status.Success.getCode(), createIndexR.getStatus().intValue());
 
-        // get index description
-        DescribeIndexParam descIndexParam = DescribeIndexParam.newBuilder()
-                .withCollectionName(randomCollectionName)
-                .withIndexName(indexParam.getIndexName())
-                .build();
-        R<DescribeIndexResponse> descIndexR = client.describeIndex(descIndexParam);
-        Assertions.assertEquals(R.Status.Success.getCode(), descIndexR.getStatus().intValue());
-
         // load collection
         R<RpcStatus> loadR2 = client.loadCollection(LoadCollectionParam.newBuilder()
                 .withCollectionName(randomCollectionName)

+ 15 - 7
src/test/java/io/milvus/v2/client/MilvusClientV2DockerTest.java

@@ -31,6 +31,7 @@ import io.milvus.param.Constant;
 import io.milvus.response.QueryResultsWrapper;
 import io.milvus.v2.common.ConsistencyLevel;
 import io.milvus.v2.common.DataType;
+import io.milvus.v2.common.IndexBuildState;
 import io.milvus.v2.common.IndexParam;
 import io.milvus.v2.exception.MilvusClientException;
 import io.milvus.v2.service.collection.request.*;
@@ -60,6 +61,7 @@ import org.testcontainers.milvus.MilvusContainer;
 
 import java.nio.ByteBuffer;
 import java.util.*;
+import java.util.concurrent.TimeUnit;
 
 @Testcontainers(disabledWithoutDocker = true)
 class MilvusClientV2DockerTest {
@@ -578,7 +580,7 @@ class MilvusClientV2DockerTest {
     }
 
     @Test
-    void testBinaryVectors() {
+    void testBinaryVectors() throws InterruptedException {
         String randomCollectionName = generator.generate(10);
 
         String vectorFieldName = "binary_vector";
@@ -1197,13 +1199,16 @@ class MilvusClientV2DockerTest {
                 .collectionName(randomCollectionName)
                 .fieldName("vector")
                 .build());
-        Assertions.assertEquals(IndexParam.IndexType.AUTOINDEX.name(), descResp.getIndexType());
+        DescribeIndexResp.IndexDesc desc = descResp.getIndexDescByFieldName("vector");
+        Assertions.assertEquals("vector", desc.getFieldName());
+        Assertions.assertFalse(desc.getIndexName().isEmpty());
+        Assertions.assertEquals(IndexParam.IndexType.AUTOINDEX, desc.getIndexType());
 
         properties.clear();
         properties.put(Constant.MMAP_ENABLED, "true");
         client.alterIndex(AlterIndexReq.builder()
                 .collectionName(randomCollectionName)
-                .indexName(descResp.getIndexName())
+                .indexName(desc.getIndexName())
                 .properties(properties)
                 .build());
 
@@ -1229,10 +1234,13 @@ class MilvusClientV2DockerTest {
                 .collectionName(randomCollectionName)
                 .fieldName("vector")
                 .build());
-        Assertions.assertEquals("XXX", descResp.getIndexName());
-        Assertions.assertEquals(IndexParam.IndexType.IVF_FLAT.name(), descResp.getIndexType());
-        Assertions.assertEquals(IndexParam.MetricType.COSINE.name(), descResp.getMetricType());
-        Map<String, Object> extraParams = descResp.getExtraParams();
+
+        desc = descResp.getIndexDescByFieldName("vector");
+        Assertions.assertEquals("vector", desc.getFieldName());
+        Assertions.assertEquals("XXX", desc.getIndexName());
+        Assertions.assertEquals(IndexParam.IndexType.IVF_FLAT, desc.getIndexType());
+        Assertions.assertEquals(IndexParam.MetricType.COSINE, desc.getMetricType());
+        Map<String, String> extraParams = desc.getExtraParams();
         Assertions.assertTrue(extraParams.containsKey("nlist"));
         Assertions.assertEquals("64", extraParams.get("nlist"));
     }