Browse Source

Merge pull request #134 from thirstycrow/simplify

Simplify the client code
Xiaohai Xu 4 years ago
parent
commit
b109096104
38 changed files with 1399 additions and 3595 deletions
  1. 4 9
      examples/pom.xml
  2. 86 162
      examples/src/main/java/MilvusClientExample.java
  3. 22 45
      pom.xml
  4. 99 92
      src/main/java/io/milvus/client/CollectionMapping.java
  5. 11 39
      src/main/java/io/milvus/client/CompactParam.java
  6. 0 28
      src/main/java/io/milvus/client/ConnectFailedException.java
  7. 1 13
      src/main/java/io/milvus/client/ConnectParam.java
  8. 0 55
      src/main/java/io/milvus/client/CountEntitiesResponse.java
  9. 0 68
      src/main/java/io/milvus/client/FieldBuilder.java
  10. 0 63
      src/main/java/io/milvus/client/GetCollectionInfoResponse.java
  11. 0 36
      src/main/java/io/milvus/client/GetEntityByIDResponse.java
  12. 0 54
      src/main/java/io/milvus/client/HasCollectionResponse.java
  13. 0 54
      src/main/java/io/milvus/client/HasPartitionResponse.java
  14. 61 65
      src/main/java/io/milvus/client/Index.java
  15. 19 0
      src/main/java/io/milvus/client/IndexType.java
  16. 72 104
      src/main/java/io/milvus/client/InsertParam.java
  17. 0 54
      src/main/java/io/milvus/client/InsertResponse.java
  18. 0 19
      src/main/java/io/milvus/client/JsonBuilder.java
  19. 0 56
      src/main/java/io/milvus/client/ListCollectionsResponse.java
  20. 0 30
      src/main/java/io/milvus/client/ListIDInSegmentResponse.java
  21. 0 57
      src/main/java/io/milvus/client/ListPartitionsResponse.java
  22. 80 0
      src/main/java/io/milvus/client/LoggingAdapter.java
  23. 11 0
      src/main/java/io/milvus/client/MetricType.java
  24. 57 107
      src/main/java/io/milvus/client/MilvusClient.java
  25. 325 1465
      src/main/java/io/milvus/client/MilvusGrpcClient.java
  26. 0 115
      src/main/java/io/milvus/client/Response.java
  27. 128 106
      src/main/java/io/milvus/client/SearchParam.java
  28. 0 150
      src/main/java/io/milvus/client/SearchResponse.java
  29. 72 0
      src/main/java/io/milvus/client/SearchResult.java
  30. 16 0
      src/main/java/io/milvus/client/exception/ClientSideMilvusException.java
  31. 0 7
      src/main/java/io/milvus/client/exception/InitializationException.java
  32. 15 0
      src/main/java/io/milvus/client/exception/InvalidDsl.java
  33. 14 8
      src/main/java/io/milvus/client/exception/MilvusException.java
  34. 33 0
      src/main/java/io/milvus/client/exception/ServerSideMilvusException.java
  35. 7 0
      src/main/java/io/milvus/client/exception/UnsupportedDataType.java
  36. 6 8
      src/main/java/io/milvus/client/exception/UnsupportedServerVersion.java
  37. 260 526
      src/test/java/io/milvus/client/MilvusGrpcClientTest.java
  38. 0 0
      src/test/resources/log4j2-test.xml

+ 4 - 9
examples/pom.xml

@@ -25,7 +25,7 @@
 
     <groupId>io.milvus</groupId>
     <artifactId>milvus-sdk-java-examples</artifactId>
-    <version>0.9.0</version>
+    <version>0.9.0-SNAPSHOT</version>
     <build>
         <plugins>
             <plugin>
@@ -66,14 +66,9 @@
             <version>0.9.0-SNAPSHOT</version>
         </dependency>
         <dependency>
-            <groupId>com.google.code.gson</groupId>
-            <artifactId>gson</artifactId>
-            <version>2.8.6</version>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-api</artifactId>
-            <version>1.7.30</version>
+            <groupId>org.testcontainers</groupId>
+            <artifactId>testcontainers</artifactId>
+            <version>1.14.3</version>
         </dependency>
     </dependencies>
 

+ 86 - 162
examples/src/main/java/MilvusClientExample.java

@@ -17,17 +17,18 @@
  * under the License.
  */
 
+import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import io.milvus.client.*;
+import org.testcontainers.containers.GenericContainer;
+
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.SplittableRandom;
-import java.util.concurrent.ExecutionException;
 import java.util.stream.Collectors;
 import java.util.stream.DoubleStream;
-import org.json.JSONObject;
+import java.util.stream.LongStream;
 
 // This is a simple example demonstrating how to use Milvus Java SDK v0.9.0.
 // For detailed API documentation, please refer to
@@ -58,147 +59,88 @@ public class MilvusClientExample {
     return vector;
   }
 
-  // Helper function that generates default fields list for a collection
-  // In this example, we have 3 fields with names "int64", "float" and "float_vec".
-  // Their DataType must also be defined.
-  static List<Map<String, Object>> generateDefaultFields(int dimension) {
-    List<Map<String, Object>> fieldList = new ArrayList<>();
-    Map<String, Object> intField = new HashMap<>();
-    intField.put("field", "int64");
-    intField.put("type", DataType.INT64);
-
-    Map<String, Object> floatField = new HashMap<>();
-    floatField.put("field", "float");
-    floatField.put("type", DataType.FLOAT);
-
-    Map<String, Object> vecField = new HashMap<>();
-    vecField.put("field", "float_vec");
-    vecField.put("type", DataType.VECTOR_FLOAT);
-    JSONObject jsonObject = new JSONObject();
-    jsonObject.put("dim", dimension);
-    vecField.put("params", jsonObject.toString());
-
-    fieldList.add(intField);
-    fieldList.add(floatField);
-    fieldList.add(vecField);
-    return fieldList;
-  }
-
-  // Helper function that generates entity field values for inserting into a collection
-  // This corresponds to the above function that initializes fields.
-  static List<Map<String, Object>> generateDefaultFieldValues(int vectorCount, List<List<Float>> vectors) {
-    List<Map<String, Object>> fieldList = new ArrayList<>();
-    Map<String, Object> intField = new HashMap<>();
-    intField.put("field", "int64");
-    intField.put("type", DataType.INT64);
-
-    Map<String, Object> floatField = new HashMap<>();
-    floatField.put("field", "float");
-    floatField.put("type", DataType.FLOAT);
-
-    Map<String, Object> vecField = new HashMap<>();
-    vecField.put("field", "float_vec");
-    vecField.put("type", DataType.VECTOR_FLOAT);
-
-    List<Long> intValues = new ArrayList<>(vectorCount);
-    List<Float> floatValues = new ArrayList<>(vectorCount);
-    for (int i = 0; i < vectorCount; i++) {
-      intValues.add((long) i);
-      floatValues.add((float) i);
+  public static void main(String[] args) throws InterruptedException {
+    String dockerImage = System.getProperty("docker_image_name", "milvusdb/milvus:0.11.0-cpu");
+    try (GenericContainer milvusContainer = new GenericContainer(dockerImage).withExposedPorts(19530)) {
+      milvusContainer.start();
+      ConnectParam connectParam = new ConnectParam.Builder()
+          .withHost("localhost")
+          .withPort(milvusContainer.getFirstMappedPort())
+          .build();
+      run(connectParam);
     }
-    intField.put("values", intValues);
-    floatField.put("values", floatValues);
-    vecField.put("values", vectors);
-
-    fieldList.add(intField);
-    fieldList.add(floatField);
-    fieldList.add(vecField);
-    return fieldList;
   }
 
-  public static void main(String[] args) throws InterruptedException, ConnectFailedException {
-
-    // You may need to change the following to the host and port of your Milvus server
-    String host = "localhost";
-    int port = 19530;
-    if (args.length >= 2) {
-      host = args[0];
-      port = Integer.parseInt(args[1]);
-    }
-
+  public static void run(ConnectParam connectParam) {
     // Create Milvus client
-    MilvusClient client = new MilvusGrpcClient();
-
-    // Connect to Milvus server
-    ConnectParam connectParam = new ConnectParam.Builder().withHost(host).withPort(port).build();
-    try {
-      Response connectResponse = client.connect(connectParam);
-    } catch (ConnectFailedException e) {
-      System.out.println("Failed to connect to Milvus server: " + e.toString());
-      throw e;
-    }
+    MilvusClient client = new MilvusGrpcClient(connectParam).withLogging();
 
     // Create a collection with the following collection mapping
     final String collectionName = "example"; // collection name
     final int dimension = 128; // dimension of each vector
     // we choose IP (Inner Product) as our metric type
-    CollectionMapping collectionMapping =
-        new CollectionMapping.Builder(collectionName)
-            .withFields(generateDefaultFields(dimension))
-            .withParamsInJson("{\"segment_row_limit\": 50000, \"auto_id\": true}")
-            .build();
-    Response createCollectionResponse = client.createCollection(collectionMapping);
+    CollectionMapping collectionMapping = CollectionMapping
+        .create(collectionName)
+        .addField("int64", DataType.INT64)
+        .addField("float", DataType.FLOAT)
+        .addVectorField("float_vec", DataType.VECTOR_FLOAT, dimension)
+        .setParamsInJson("{\"segment_row_limit\": 50000, \"auto_id\": true}");
+
+    client.createCollection(collectionMapping);
+
+    if (!client.hasCollection(collectionName)) {
+      throw new AssertionError("Collection not found");
+    }
 
-    // Check whether the collection exists
-    HasCollectionResponse hasCollectionResponse = client.hasCollection(collectionName);
+    System.out.println(collectionMapping.toString());
 
     // Get collection info
-    GetCollectionInfoResponse getCollectionInfoResponse = client.getCollectionInfo(collectionName);
+    CollectionMapping collectionInfo = client.getCollectionInfo(collectionName);
 
     // Insert randomly generated field values to collection
     final int vectorCount = 100000;
-    List<List<Float>> vectors = generateVectors(vectorCount, dimension);
-    vectors =
-        vectors.stream().map(MilvusClientExample::normalizeVector).collect(Collectors.toList());
-    List<Map<String, Object>> defaultFieldValues = generateDefaultFieldValues(vectorCount, vectors);
-    InsertParam insertParam =
-        new InsertParam.Builder(collectionName)
-            .withFields(defaultFieldValues)
-            .build();
-    InsertResponse insertResponse = client.insert(insertParam);
+
+    List<Long> longValues = LongStream.range(0, vectorCount).boxed().collect(Collectors.toList());
+    List<Float> floatValues = LongStream.range(0, vectorCount).boxed().map(Long::floatValue).collect(Collectors.toList());
+    List<List<Float>> vectors = generateVectors(vectorCount, dimension).stream()
+        .map(MilvusClientExample::normalizeVector)
+        .collect(Collectors.toList());
+
+    InsertParam insertParam = InsertParam
+        .create(collectionName)
+        .addField("int64", DataType.INT64, longValues)
+        .addField("float", DataType.FLOAT, floatValues)
+        .addVectorField("float_vec", DataType.VECTOR_FLOAT, vectors);
+
     // Insert returns a list of entity ids that you will be using (if you did not supply them
     // yourself) to reference the entities you just inserted
-    List<Long> vectorIds = insertResponse.getEntityIds();
+    List<Long> vectorIds = client.insert(insertParam);
 
     // Flush data in collection
-    Response flushResponse = client.flush(collectionName);
+    client.flush(collectionName);
 
     // Get current entity count of collection
-    CountEntitiesResponse countEntitiesResponse = client.countEntities(collectionName);
+    long entityCount = client.countEntities(collectionName);
 
     // Create index for the collection
     // We choose IVF_SQ8 as our index type here. Refer to Milvus documentation for a
     // complete explanation of different index types and their relative parameters.
-    Index index =
-        new Index.Builder(collectionName, "float_vec")
-            .withParamsInJson("{\"index_type\": \"IVF_SQ8\", \"metric_type\": \"L2\", "
-                + "\"params\": {\"nlist\": 2048}}")
-            .build();
-    Response createIndexResponse = client.createIndex(index);
+    Index index = Index
+        .create(collectionName, "float_vec")
+        .setIndexType(IndexType.IVF_SQ8)
+        .setMetricType(MetricType.L2)
+        .setParamsInJson(new JsonBuilder().param("nlist", 2048).build());
+
+    client.createIndex(index);
 
     // Get collection info
-    Response getCollectionStatsResponse = client.getCollectionStats(collectionName);
-    if (getCollectionStatsResponse.ok()) {
-      // Collection info is sent back with JSON type string
-      String jsonString = getCollectionStatsResponse.getMessage();
-      System.out.format("Collection Stats: %s\n", jsonString);
-    }
+    String collectionStats = client.getCollectionStats(collectionName);
+    System.out.format("Collection Stats: %s\n", collectionStats);
 
     // Check whether a partition exists in collection
     // Obviously we do not have partition "tag" now
-    HasPartitionResponse testHasPartition = client.hasPartition(collectionName, "tag");
-    if (testHasPartition.ok() && testHasPartition.hasPartition()) {
-      throw new AssertionError("Wrong results!");
+    if (client.hasPartition(collectionName, "tag")) {
+      throw new AssertionError("Unexpected partition found!");
     }
 
     // Search entities using DSL statement.
@@ -220,71 +162,53 @@ public class MilvusClientExample {
             + "%s, \"params\": {\"nprobe\": 50}"
             + "    }}}]}}",
         topK, vectorsToSearch.toString());
-    SearchParam searchParam =
-        new SearchParam.Builder(collectionName)
-            .withDSL(dsl)
-            .withParamsInJson("{\"fields\": [\"int64\", \"float\"]}")
-            .build();
-    SearchResponse searchResponse = client.search(searchParam);
-    if (searchResponse.ok()) {
-      List<List<SearchResponse.QueryResult>> queryResultsList =
-          searchResponse.getQueryResultsList();
-      final double epsilon = 0.01;
-      for (int i = 0; i < searchBatchSize; i++) {
-        // Since we are searching for vector that is already present in the collection,
-        // the first result vector should be itself and the distance (inner product) should be
-        // very close to 1 (some precision is lost during the process)
-        SearchResponse.QueryResult firstQueryResult = queryResultsList.get(i).get(0);
-        if (firstQueryResult.getEntityId() != vectorIds.get(i)
-            || Math.abs(1 - firstQueryResult.getDistance()) > epsilon) {
-          throw new AssertionError("Wrong results!");
-        }
+    SearchParam searchParam = SearchParam
+        .create(collectionName)
+        .setDsl(dsl)
+        .setParamsInJson("{\"fields\": [\"int64\", \"float\"]}");
+    SearchResult searchResult = client.search(searchParam);
+    List<List<SearchResult.QueryResult>> queryResultsList = searchResult.getQueryResultsList();
+    final double epsilon = 0.01;
+    for (int i = 0; i < searchBatchSize; i++) {
+      // Since we are searching for vector that is already present in the collection,
+      // the first result vector should be itself and the distance (inner product) should be
+      // very close to 1 (some precision is lost during the process)
+      SearchResult.QueryResult firstQueryResult = queryResultsList.get(i).get(0);
+      if (firstQueryResult.getEntityId() != vectorIds.get(i)
+          || Math.abs(1 - firstQueryResult.getDistance()) > epsilon) {
+        throw new AssertionError("Wrong results!");
       }
     }
+
     // You can also get result ids and distances separately
-    List<List<Long>> resultIds = searchResponse.getResultIdsList();
-    List<List<Float>> resultDistances = searchResponse.getResultDistancesList();
+    List<List<Long>> resultIds = searchResult.getResultIdsList();
+    List<List<Float>> resultDistances = searchResult.getResultDistancesList();
 
     // You can send search request asynchronously, which returns a ListenableFuture object
-    ListenableFuture<SearchResponse> searchResponseFuture = client.searchAsync(searchParam);
-    try {
-      // Get search response immediately. Obviously you will want to do more complicated stuff with
-      // ListenableFuture
-      searchResponseFuture.get();
-    } catch (ExecutionException e) {
-      e.printStackTrace();
-    }
+    ListenableFuture<SearchResult> searchResponseFuture = client.searchAsync(searchParam);
+    // Get search response immediately. Obviously you will want to do more complicated stuff with
+    // ListenableFuture
+    Futures.getUnchecked(searchResponseFuture);
 
     // Delete the first 5 entities you just searched
-    Response deleteByIdsResponse =
-        client.deleteEntityByID(collectionName, vectorIds.subList(0, searchBatchSize));
-    flushResponse = client.flush(collectionName);
+    client.deleteEntityByID(collectionName, vectorIds.subList(0, searchBatchSize));
+    client.flush(collectionName);
 
     // After deleting them, we call getEntityByID and obviously all 5 entities should not be returned.
-    GetEntityByIDResponse getEntityByIDResponse =
-        client.getEntityByID(collectionName, vectorIds.subList(0, searchBatchSize));
-    if (getEntityByIDResponse.getValidIds().size() > 0) {
-      throw new AssertionError("This can never happen!");
+    Map<Long, Map<String, Object>> entities = client.getEntityByID(collectionName, vectorIds.subList(0, searchBatchSize));
+    if (!entities.isEmpty()) {
+      throw new AssertionError("Unexpected entity count!");
     }
 
     // Compact the collection, erase deleted data from disk and rebuild index in background (if
     // the data size after compaction is still larger than indexFileSize). Data was only
     // soft-deleted until you call compact.
-    Response compactResponse = client.compact(
-        new CompactParam.Builder(collectionName).withThreshold(0.2).build());
+    client.compact(CompactParam.create(collectionName).setThreshold(0.2));
 
     // Drop index for the collection
-    Response dropIndexResponse = client.dropIndex(collectionName, "float_vec");
+    client.dropIndex(collectionName, "float_vec");
 
     // Drop collection
-    Response dropCollectionResponse = client.dropCollection(collectionName);
-
-    // Disconnect from Milvus server
-    try {
-      Response disconnectResponse = client.disconnect();
-    } catch (InterruptedException e) {
-      System.out.println("Failed to disconnect: " + e.toString());
-      throw e;
-    }
+    client.dropCollection(collectionName);
   }
 }

+ 22 - 45
pom.xml

@@ -71,6 +71,7 @@
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <grpc.version>1.30.2</grpc.version>
+        <testcontainers.version>1.14.3</testcontainers.version>
         <protobuf.version>3.11.0</protobuf.version>
         <protoc.version>3.11.0</protoc.version>
         <maven.compiler.source>1.8</maven.compiler.source>
@@ -90,52 +91,21 @@
     </dependencyManagement>
 
     <dependencies>
-        <dependency>
-            <groupId>org.apache.maven.plugins</groupId>
-            <artifactId>maven-gpg-plugin</artifactId>
-            <version>1.6</version>
-        </dependency>
-        <dependency>
-            <groupId>io.grpc</groupId>
-            <artifactId>grpc-netty-shaded</artifactId>
-            <version>1.30.2</version>
-            <scope>runtime</scope>
-        </dependency>
         <dependency>
             <groupId>io.grpc</groupId>
             <artifactId>grpc-protobuf</artifactId>
-            <version>1.30.2</version>
+            <version>${grpc.version}</version>
         </dependency>
         <dependency>
             <groupId>io.grpc</groupId>
             <artifactId>grpc-stub</artifactId>
-            <version>1.30.2</version>
-        </dependency>
-        <dependency>
-            <groupId>javax.annotation</groupId>
-            <artifactId>javax.annotation-api</artifactId>
-            <version>1.2</version>
-            <scope>provided</scope> <!-- not needed at runtime -->
-        </dependency>
-        <dependency>
-            <groupId>com.google.protobuf</groupId>
-            <artifactId>protobuf-java-util</artifactId>
-            <version>${protobuf.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>com.google.errorprone</groupId>
-            <artifactId>error_prone_annotations</artifactId>
-            <version>2.3.4</version> <!-- prefer to use 2.3.3 or later -->
-        </dependency>
-        <dependency>
-            <groupId>org.apache.commons</groupId>
-            <artifactId>commons-text</artifactId>
-            <version>1.6</version>
+            <version>${grpc.version}</version>
         </dependency>
         <dependency>
-            <groupId>org.apache.commons</groupId>
-            <artifactId>commons-collections4</artifactId>
-            <version>4.4</version>
+            <groupId>io.grpc</groupId>
+            <artifactId>grpc-netty-shaded</artifactId>
+            <version>${grpc.version}</version>
+            <scope>runtime</scope>
         </dependency>
         <dependency>
             <groupId>org.json</groupId>
@@ -148,14 +118,15 @@
             <version>1.7.30</version>
         </dependency>
         <dependency>
-            <groupId>org.apache.logging.log4j</groupId>
-            <artifactId>log4j-slf4j-impl</artifactId>
-            <version>2.12.1</version>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.10</version>
         </dependency>
         <dependency>
-            <groupId>io.grpc</groupId>
-            <artifactId>grpc-testing</artifactId>
-            <scope>test</scope>
+            <groupId>javax.annotation</groupId>
+            <artifactId>javax.annotation-api</artifactId>
+            <version>1.2</version>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.junit.jupiter</groupId>
@@ -166,13 +137,19 @@
         <dependency>
             <groupId>org.testcontainers</groupId>
             <artifactId>testcontainers</artifactId>
-            <version>1.14.3</version>
+            <version>${testcontainers.version}</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.testcontainers</groupId>
             <artifactId>junit-jupiter</artifactId>
-            <version>1.14.3</version>
+            <version>${testcontainers.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-slf4j-impl</artifactId>
+            <version>2.12.1</version>
             <scope>test</scope>
         </dependency>
     </dependencies>

+ 99 - 92
src/main/java/io/milvus/client/CollectionMapping.java

@@ -19,119 +19,126 @@
 
 package io.milvus.client;
 
-import java.util.ArrayList;
+import com.google.common.collect.ImmutableMap;
+import io.milvus.grpc.FieldParam;
+import io.milvus.grpc.KeyValuePair;
+import io.milvus.grpc.Mapping;
+import org.json.JSONObject;
+
 import java.util.List;
 import java.util.Map;
-import javax.annotation.Nonnull;
+import java.util.stream.Collectors;
 
 /** Represents a collection mapping */
 public class CollectionMapping {
-  private final String collectionName;
-  private final List<? extends Map<String, Object>> fields;
-  private final String paramsInJson;
-
-  private CollectionMapping(@Nonnull Builder builder) {
-    collectionName = builder.collectionName;
-    fields = builder.fields;
-    paramsInJson = builder.paramsInJson;
+  private final Mapping.Builder builder;
+
+  public static CollectionMapping create(String collectionName) {
+    return new CollectionMapping(collectionName);
   }
 
-  public String getCollectionName() {
-    return collectionName;
+  CollectionMapping(Mapping mapping) {
+    this.builder = mapping.toBuilder();
   }
 
-  public List<? extends Map<String, Object>> getFields() {
-    return fields;
+  private CollectionMapping(String collectionName) {
+    this.builder = Mapping.newBuilder();
+    builder.setCollectionName(collectionName);
   }
 
-  public String getParamsInJson() {
-    return paramsInJson;
+  /**
+   * add a scalar field
+   *
+   * @param name the field name
+   * @param type the field data type
+   * @return this CollectionMapping
+   */
+  public CollectionMapping addField(String name, DataType type) {
+    builder.addFields(FieldParam.newBuilder().setName(name).setTypeValue(type.getVal()).build());
+    return this;
   }
 
-  @Override
-  public String toString() {
-    return String.format(
-        "CollectionMapping = {collectionName = %s, fields = %s, params = %s}",
-        collectionName, fields.toString(), paramsInJson);
+  /**
+   * add a vector field
+   *
+   * @param name the field name
+   * @param type the field data type
+   * @param dimension the vector dimension
+   * @return this CollectionMapping
+   */
+  public CollectionMapping addVectorField(String name, DataType type, int dimension) {
+    FieldParam field = FieldParam.newBuilder()
+        .setName(name)
+        .setTypeValue(type.getVal())
+        .addExtraParams(KeyValuePair.newBuilder()
+            .setKey(MilvusClient.extraParamKey)
+            .setValue(new JSONObject().put("dim", dimension).toString())
+            .build())
+        .build();
+    builder.addFields(field);
+    return this;
   }
 
-  /** Builder for <code>CollectionMapping</code> */
-  public static class Builder {
-    // Required parameters
-    private final String collectionName;
+  public List<Map<String, Object>> getFields() {
+    return builder.getFieldsList().stream()
+        .map(f -> {
+          ImmutableMap.Builder<String, Object> builder = ImmutableMap
+              .<String, Object>builder()
+              .put("name", f.getName())
+              .put("type", DataType.valueOf(f.getType().getNumber()));
+          String paramsInJson = getParamsInJson(f.getExtraParamsList());
+          if (paramsInJson != null) {
+            builder.put(MilvusClient.extraParamKey, paramsInJson);
+          }
+          return builder.build();
+        })
+        .collect(Collectors.toList());
+  }
 
-    // Optional parameters. Default to empty.
-    private List<Map<String, Object>> fields = new ArrayList<>();
-    private String paramsInJson = "{}";
+  /**
+   * Set extra params in json string
+   *
+   * @param paramsInJson Two optional parameters can be included. "segment_row_limit" is default
+   *                     to 100,000. Merge will be triggered if more than this number of entities
+   *                     are inserted into collection. "auto_id" is default to <code>true</code>.
+   *                     Entity ids will be auto-generated by Milvus if set to true.
+   * @return this CollectionMapping
+   */
+  public CollectionMapping setParamsInJson(String paramsInJson) {
+    builder.addExtraParams(KeyValuePair.newBuilder()
+        .setKey(MilvusClient.extraParamKey)
+        .setValue(paramsInJson)
+        .build());
+    return this;
+  }
 
-    /**
-     * @param collectionName collection name
-     */
-    public Builder(@Nonnull String collectionName) {
-      this.collectionName = collectionName;
-    }
+  public String getParamsInJson() {
+    return getParamsInJson(builder.getExtraParamsList());
+  }
 
-    /**
-     * Build with fields. Example fields:
-     * <pre>
-     *   <code>
-     *  [
-     *      {"field": "A", "type": DataType.INT64},
-     *      {"field": "B", "type": DataType.INT32},
-     *      {"field": "C", "type": DataType.FLOAT},
-     *      {"field": "Vec", "type": DataType.VECTOR_FLOAT, "params": {"dim": 128}}
-     *  ]
-     *   </code>
-     * </pre>
-     *
-     * @param fields a list of hashmap listing each field. A field must have keys "field" and
-     *               "type". A vector field must have "dim" in "params". "params" should be in json
-     *               format.
-     * @return <code>Builder</code>
-     */
-    public Builder withFields(@Nonnull List<Map<String, Object>> fields) {
-      this.fields = fields;
-      return this;
-    }
+  public String getCollectionName() {
+    return builder.getCollectionName();
+  }
 
-    /**
-     * Add a single field to collection. Example field:
-     * <pre>
-     *   <code>
-     *      {"field": "A", "type": DataType.INT64}, or
-     *      {"field": "B", "type": DataType.INT32}, or
-     *      {"field": "C", "type": DataType.FLOAT}, or
-     *      {"field": "Vec", "type": DataType.VECTOR_FLOAT, "params": {"dim": 128}}
-     *   </code>
-     * </pre>
-     *
-     * @param field A field must have keys "field" and "type". A vector field must have
-     *              "dim" in "params". <code>FieldBuilder</code> can be used to create a field.
-     * @see FieldBuilder
-     * @return <code>Builder</code>
-     */
-    public Builder field(@Nonnull Map<String, Object> field) {
-      this.fields.add(field);
-      return this;
+  Mapping grpc() {
+    if (builder.getFieldsCount() == 0) {
+      throw new IllegalArgumentException("Fields must not be empty.");
     }
+    return builder.build();
+  }
 
-    /**
-     * Build with extra params in json string format.
-     *
-     * @param paramsInJson Two optional parameters can be included. "segment_row_limit" is default
-     *                     to 100,000. Merge will be triggered if more than this number of entities
-     *                     are inserted into collection. "auto_id" is default to <code>true</code>.
-     *                     Entity ids will be auto-generated by Milvus if set to true.
-     * @see JsonBuilder
-     * @return <code>Builder</code>
-     */
-    public Builder withParamsInJson(String paramsInJson) {
-      this.paramsInJson = paramsInJson;
-      return this;
-    }
+  @Override
+  public String toString() {
+    return String.format(
+        "CollectionMapping = {collectionName = %s, fields = %s, params = %s}",
+        getCollectionName(), getFields(), getParamsInJson());
+  }
 
-    public CollectionMapping build() {
-      return new CollectionMapping(this);
-    }
+  private String getParamsInJson(List<KeyValuePair> extraParams) {
+    return extraParams.stream()
+        .filter(kv -> MilvusClient.extraParamKey.equals(kv.getKey()))
+        .map(KeyValuePair::getValue)
+        .findFirst()
+        .orElse(null);
   }
 }

+ 11 - 39
src/main/java/io/milvus/client/CompactParam.java

@@ -19,53 +19,25 @@
 
 package io.milvus.client;
 
-import javax.annotation.Nonnull;
-
 /** Contains parameters for <code>compact</code> */
 public class CompactParam {
-  private final String collectionName;
-  private final double threshold;
+  private io.milvus.grpc.CompactParam.Builder builder;
 
-  private CompactParam(@Nonnull Builder builder) {
-    this.collectionName = builder.collectionName;
-    this.threshold = builder.threshold;
+  public static CompactParam create(String collectionName) {
+    return new CompactParam(collectionName);
   }
 
-  public String getCollectionName() {
-    return collectionName;
+  private CompactParam(String collectionName) {
+    builder = io.milvus.grpc.CompactParam.newBuilder();
+    builder.setCollectionName(collectionName).setThreshold(0.2);
   }
 
-  public double getThreshold() {
-    return threshold;
+  public CompactParam setThreshold(double threshold) {
+    builder.setThreshold(threshold);
+    return this;
   }
 
-  /** Builder for <code>CompactParam</code> */
-  public static class Builder {
-    // Required parameter
-    private final String collectionName;
-
-    // Optional parameter - initialized to default value
-    private double threshold = 0.2;
-
-    /** @param collectionName collection to compact */
-    public Builder(@Nonnull String collectionName) {
-      this.collectionName = collectionName;
-    }
-
-    /**
-     * Optional. Default to 0.2. Segment will compact if and only if the percentage of entities
-     * deleted exceeds the threshold.
-     *
-     * @param threshold The threshold
-     * @return <code>Builder</code>
-     */
-    public Builder withThreshold(double threshold) {
-      this.threshold = threshold;
-      return this;
-    }
-
-    public CompactParam build() {
-      return new CompactParam(this);
-    }
+  io.milvus.grpc.CompactParam grpc() {
+    return builder.build();
   }
 }

+ 0 - 28
src/main/java/io/milvus/client/ConnectFailedException.java

@@ -1,28 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package io.milvus.client;
-
-/** Thrown when client failed to connect to server */
-public class ConnectFailedException extends Exception {
-
-  public ConnectFailedException(String message) {
-    super(message);
-  }
-}

+ 1 - 13
src/main/java/io/milvus/client/ConnectParam.java

@@ -27,8 +27,6 @@ import java.util.concurrent.TimeUnit;
 /** Contains parameters for connecting to Milvus server */
 public class ConnectParam {
   private final String target;
-  private final String host;
-  private final int port;
   private final String defaultLoadBalancingPolicy;
   private final long connectTimeoutNanos;
   private final long keepAliveTimeNanos;
@@ -37,9 +35,7 @@ public class ConnectParam {
   private final long idleTimeoutNanos;
 
   private ConnectParam(@Nonnull Builder builder) {
-    this.target = builder.target;
-    this.host = builder.host;
-    this.port = builder.port;
+    this.target = builder.target != null ? builder.target : String.format("dns:///%s:%d", builder.host, builder.port);
     this.defaultLoadBalancingPolicy = builder.defaultLoadBalancingPolicy;
     this.connectTimeoutNanos = builder.connectTimeoutNanos;
     this.keepAliveTimeNanos = builder.keepAliveTimeNanos;
@@ -52,14 +48,6 @@ public class ConnectParam {
     return target;
   }
 
-  public String getHost() {
-    return host;
-  }
-
-  public int getPort() {
-    return port;
-  }
-
   public String getDefaultLoadBalancingPolicy() {
     return defaultLoadBalancingPolicy;
   }

+ 0 - 55
src/main/java/io/milvus/client/CountEntitiesResponse.java

@@ -1,55 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package io.milvus.client;
-
-/**
- * Contains the returned <code>response</code> and <code>collectionEntityCount</code> for <code>
- * countEntities</code>
- */
-public class CountEntitiesResponse {
-  private final Response response;
-  private final long collectionEntityCount;
-
-  CountEntitiesResponse(Response response, long collectionEntityCount) {
-    this.response = response;
-    this.collectionEntityCount = collectionEntityCount;
-  }
-
-  /** @return collection entity count */
-  public long getCollectionEntityCount() {
-    return collectionEntityCount;
-  }
-
-  public Response getResponse() {
-    return response;
-  }
-
-  /** @return <code>true</code> if the response status equals SUCCESS */
-  public boolean ok() {
-    return response.ok();
-  }
-
-  @Override
-  public String toString() {
-    return String.format(
-        "CountCollectionResponse {%s, collection entity count = %d}",
-        response.toString(), collectionEntityCount);
-  }
-}

+ 0 - 68
src/main/java/io/milvus/client/FieldBuilder.java

@@ -1,68 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package io.milvus.client;
-
-import java.util.HashMap;
-import java.util.Map;
-import org.json.JSONObject;
-
-/** Contains Field Parameter Builder */
-public class FieldBuilder {
-  private Map<String, Object> fields;
-
-  /** Initialize required field information: field name and data type */
-  public FieldBuilder(String fieldName, DataType fieldType) {
-    this.fields = new HashMap<>();
-    this.fields.put("field", fieldName);
-    this.fields.put("type", fieldType);
-  }
-
-  /**
-   * Add key-value pair to <code>fields</code>.
-   *
-   * @param key The param key
-   * @param value The param value
-   * @return <code>FieldBuilder</code>
-   */
-  public FieldBuilder param(String key, Object value) {
-    if (!fields.containsKey("params")) {
-      fields.put("params", new JSONObject().put(key, value));
-    } else {
-      ((JSONObject) fields.get("params")).put(key, value);
-    }
-    return this;
-  }
-
-  /**
-   * Add values to fields. Used for insert operation. This should be a list of object whose type
-   * corresponds to relative field DataType.
-   *
-   * @param value The value
-   * @return <code>FieldBuilder</code>
-   */
-  public FieldBuilder values(Object value) {
-    this.fields.put("values", value);
-    return this;
-  }
-
-  public Map<String, Object> build() {
-    return this.fields;
-  }
-}

+ 0 - 63
src/main/java/io/milvus/client/GetCollectionInfoResponse.java

@@ -1,63 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package io.milvus.client;
-
-import javax.annotation.Nullable;
-import java.util.Optional;
-
-/**
- * Contains the returned <code>response</code> and <code>collectionMapping</code> for <code>
- * getCollectionInfo</code>
- */
-public class GetCollectionInfoResponse {
-  private final Response response;
-  private final CollectionMapping collectionMapping;
-
-  GetCollectionInfoResponse(Response response, @Nullable CollectionMapping collectionMapping) {
-    this.response = response;
-    this.collectionMapping = collectionMapping;
-  }
-
-  /**
-   * @return an <code>Optional</code> object which may or may not contain a <code>CollectionMapping
-   *     </code> object
-   * @see Optional
-   */
-  public Optional<CollectionMapping> getCollectionMapping() {
-    return Optional.ofNullable(collectionMapping);
-  }
-
-  public Response getResponse() {
-    return response;
-  }
-
-  /** @return <code>true</code> if the response status equals SUCCESS */
-  public boolean ok() {
-    return response.ok();
-  }
-
-  @Override
-  public String toString() {
-    return String.format(
-        "GetCollectionInfoResponse {%s, %s}",
-        response.toString(),
-        collectionMapping == null ? "Collection mapping = None" : collectionMapping.toString());
-  }
-}

+ 0 - 36
src/main/java/io/milvus/client/GetEntityByIDResponse.java

@@ -1,36 +0,0 @@
-package io.milvus.client;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * Contains the returned <code>response</code>, valid ids within query and a <code>List</code> of
- * fields map for <code>getEntityByID</code>.
- */
-public class GetEntityByIDResponse {
-  private final Response response;
-  private List<Map<String, Object>> fieldsMap;
-
-  GetEntityByIDResponse(
-      Response response, List<Map<String, Object>> fieldsMap) {
-    this.response = response;
-    this.fieldsMap = fieldsMap;
-  }
-
-  /**
-   * @return A <code>List</code> of map with fields information. The list order corresponds
-   * to query IDs. Each <code>Map</code> maps field names to records in a row.
-   * The record object can be one of int, long, float, double, List<Float> or List<Byte>
-   * depending on the field's <code>DataType</code> you specified.
-   */
-  public List<Map<String, Object>> getFieldsMap() { return fieldsMap; }
-
-  public Response getResponse() {
-    return response;
-  }
-
-  /** @return <code>true</code> if the response status equals SUCCESS */
-  public boolean ok() {
-    return response.ok();
-  }
-}

+ 0 - 54
src/main/java/io/milvus/client/HasCollectionResponse.java

@@ -1,54 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package io.milvus.client;
-
-/**
- * Contains the returned <code>response</code> and <code>hasCollection</code> for <code>
- * hasCollection</code>
- */
-public class HasCollectionResponse {
-  private final Response response;
-  private final boolean hasCollection;
-
-  HasCollectionResponse(Response response, boolean hasCollection) {
-    this.response = response;
-    this.hasCollection = hasCollection;
-  }
-
-  /** @return <code>true</code> if the collection is present */
-  public boolean hasCollection() {
-    return hasCollection;
-  }
-
-  public Response getResponse() {
-    return response;
-  }
-
-  /** @return <code>true</code> if the response status equals SUCCESS */
-  public boolean ok() {
-    return response.ok();
-  }
-
-  @Override
-  public String toString() {
-    return String.format(
-        "HasCollectionResponse {%s, has collection = %s}", response.toString(), hasCollection);
-  }
-}

+ 0 - 54
src/main/java/io/milvus/client/HasPartitionResponse.java

@@ -1,54 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package io.milvus.client;
-
-/**
- * Contains the returned <code>response</code> and <code>hasPartition</code> for <code>
- * hasPartition</code>
- */
-public class HasPartitionResponse {
-    private final Response response;
-    private final boolean hasPartition;
-
-    HasPartitionResponse(Response response, boolean hasPartition) {
-        this.response = response;
-        this.hasPartition = hasPartition;
-    }
-
-    /** @return <code>true</code> if the partition is present */
-    public boolean hasPartition() {
-        return hasPartition;
-    }
-
-    public Response getResponse() {
-        return response;
-    }
-
-    /** @return <code>true</code> if the response status equals SUCCESS */
-    public boolean ok() {
-        return response.ok();
-    }
-
-    @Override
-    public String toString() {
-        return String.format(
-                "HasPartitionResponse {%s, has partition = %s}", response.toString(), hasPartition);
-    }
-}

+ 61 - 65
src/main/java/io/milvus/client/Index.java

@@ -19,98 +19,94 @@
 
 package io.milvus.client;
 
+import io.milvus.grpc.IndexParam;
+import io.milvus.grpc.KeyValuePair;
+
 import javax.annotation.Nonnull;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 /** Represents an index containing <code>fieldName</code>, <code>indexName</code> and
  * <code>paramsInJson</code>, which contains index_type, params etc.
  */
 public class Index {
-  private final String collectionName;
-  private final String fieldName;
-  private final String indexName;
-  private final String paramsInJson;
-
-  private Index(@Nonnull Builder builder) {
-    this.collectionName = builder.collectionName;
-    this.fieldName = builder.fieldName;
-    this.indexName = builder.indexName;
-    this.paramsInJson = builder.paramsInJson;
+  private final IndexParam.Builder builder;
+
+  public static Index create(@Nonnull String collectionName, @Nonnull String fieldName) {
+    return new Index(collectionName, fieldName);
+  }
+
+  private Index(String collectionName, String fieldName) {
+    this.builder = IndexParam.newBuilder()
+        .setCollectionName(collectionName)
+        .setFieldName(fieldName);
   }
 
   public String getCollectionName() {
-    return collectionName;
+    return builder.getCollectionName();
+  }
+
+  public Index setCollectionName(@Nonnull String collectionName) {
+    builder.setCollectionName(collectionName);
+    return this;
   }
 
   public String getFieldName() {
-    return fieldName;
+    return builder.getFieldName();
+  }
+
+  public Index setFieldName(@Nonnull String collectionName) {
+    builder.setFieldName(collectionName);
+    return this;
   }
 
   public String getIndexName() {
-    return indexName;
+    return builder.getIndexName();
+  }
+
+  public Map<String, String> getExtraParams() {
+    return toMap(builder.getExtraParamsList());
+  }
+
+  public Index setIndexType(IndexType indexType) {
+    return addParam("index_type", indexType.name());
+  }
+
+  public Index setMetricType(MetricType metricType) {
+    return addParam("metric_type", metricType.name());
   }
 
-  public String getParamsInJson() {
-    return paramsInJson;
+  public Index setParamsInJson(String paramsInJson) {
+    return addParam(MilvusClient.extraParamKey, paramsInJson);
+  }
+
+  private Index addParam(String key, Object value) {
+    builder.addExtraParams(
+        KeyValuePair.newBuilder()
+            .setKey(key)
+            .setValue(String.valueOf(value))
+            .build());
+    return this;
   }
 
   @Override
   public String toString() {
     return "Index {"
         + "collectionName="
-        + collectionName
+        + getCollectionName()
         + ", fieldName="
-        + fieldName
+        + getFieldName()
         + ", params="
-        + paramsInJson
+        + getExtraParams()
         + '}';
   }
 
-  /** Builder for <code>Index</code> */
-  public static class Builder {
-    // Required parameters
-    private final String collectionName;
-    private final String fieldName;
-
-    // Optional parameters - initialized to default values
-    private String paramsInJson = "{}";
-    private String indexName = "";
-
-    /**
-     * @param collectionName collection to create index for
-     * @param fieldName name of the field on which index is built.
-     */
-    public Builder(@Nonnull String collectionName, @Nonnull String fieldName) {
-      this.collectionName = collectionName;
-      this.fieldName = fieldName;
-    }
-
-    /**
-     * Optional. The parameters for building an index. Index parameters are different for different
-     * index types. Refer to Milvus documentation for more information.
-     * <pre>
-     * "index_type": one of the values: FLAT, IVF_FLAT, IVF_SQ8, NSG, IVF_SQ8_HYBRID, IVF_PQ,
-     *                                  HNSW, RHNSW_FLAT, RHNSW_PQ, RHNSW_SQ, ANNOY
-     * "metric_type": one of the values: L2, IP, HAMMING, JACCARD, TANIMOTO,
-     *                                   SUBSTRUCTURE, SUPERSTRUCTURE
-     * "params": optional parameters for index, including <code>nlist</code>
-     *
-     * Example param:
-     * <code>
-     *   {"index_type": "IVF_FLAT", "metric_type": "IP", "params": {nlist": 2048}}
-     * </code>
-     * </pre>
-     *
-     * @param paramsInJson extra parameters in JSON format
-     * @see JsonBuilder
-     * @return <code>Builder</code>
-     */
-    public Builder withParamsInJson(@Nonnull String paramsInJson) {
-      this.paramsInJson = paramsInJson;
-      return this;
-    }
-
-    public Index build() {
-      return new Index(this);
-    }
+  IndexParam grpc() {
+    return builder.build();
+  }
+
+  private Map<String, String> toMap(List<KeyValuePair> extraParams) {
+    return extraParams.stream().collect(Collectors.toMap(KeyValuePair::getKey, KeyValuePair::getValue));
   }
 }

+ 19 - 0
src/main/java/io/milvus/client/IndexType.java

@@ -0,0 +1,19 @@
+package io.milvus.client;
+
+public enum IndexType {
+  ANNOY,
+  BIN_FLAT,
+  BIN_IVF_FLAT,
+  FLAT,
+  HNSW,
+  IVF_FLAT,
+  IVF_PQ,
+  IVF_SQ8,
+  IVF_SQ8_HYBRID,
+  NSG,
+  RHNSW_FLAT,
+  RHNSW_PQ,
+  RHNSW_SQ,
+  SPTAG_BKT_RNT,
+  SPTAG_KDT_RNT
+}

+ 72 - 104
src/main/java/io/milvus/client/InsertParam.java

@@ -19,125 +19,93 @@
 
 package io.milvus.client;
 
-import java.util.Map;
-import javax.annotation.Nonnull;
-import java.util.ArrayList;
+import com.google.protobuf.ByteString;
+import io.milvus.client.exception.UnsupportedDataType;
+import io.milvus.grpc.AttrRecord;
+import io.milvus.grpc.FieldValue;
+import io.milvus.grpc.VectorRecord;
+import io.milvus.grpc.VectorRowRecord;
+
+import java.nio.ByteBuffer;
 import java.util.List;
+import java.util.stream.Collectors;
 
 /** Contains parameters for <code>insert</code> */
 public class InsertParam {
-  private final String collectionName;
-  private final List<? extends Map<String, Object>> fields;
-  private final List<Long> entityIds;
-  private final String partitionTag;
+  private io.milvus.grpc.InsertParam.Builder builder;
 
-  private InsertParam(@Nonnull Builder builder) {
-    this.collectionName = builder.collectionName;
-    this.fields = builder.fields;
-    this.entityIds = builder.entityIds;
-    this.partitionTag = builder.partitionTag;
+  public static InsertParam create(String collectionName) {
+    return new InsertParam(collectionName);
   }
 
-  public String getCollectionName() {
-    return collectionName;
+  private InsertParam(String collectionName) {
+    this.builder = io.milvus.grpc.InsertParam.newBuilder();
+    builder.setCollectionName(collectionName);
   }
 
-  public List<? extends Map<String, Object>> getFields() { return fields; }
-
-  public List<Long> getEntityIds() {
-    return entityIds;
-  }
-
-  public String getPartitionTag() {
-    return partitionTag;
+  public InsertParam setEntityIds(List<Long> entityIds) {
+    builder.addAllEntityIdArray(entityIds);
+    return this;
   }
 
-  /** Builder for <code>InsertParam</code> */
-  public static class Builder {
-    // Required parameter
-    private final String collectionName;
-
-    // Optional parameters - initialized to default values
-    private List<Map<String, Object>> fields = new ArrayList<>();
-    private List<Long> entityIds = new ArrayList<>();
-    private String partitionTag = "";
-
-    /** @param collectionName collection to insert entities to */
-    public Builder(@Nonnull String collectionName) {
-      this.collectionName = collectionName;
-    }
-
-    /**
-     * The data you wish to insert into collections. Default to an empty <code>ArrayList</code>
-     *
-     * @param fields a <code>List</code> of <code>Map</code> that contains data to insert for each
-     *     field name. "field", "values" and "type" must be present in each map. The size of
-     *     map["values"] must match for all maps in the list, which is equivalent to entity count.
-     *     Example fields:
-     * <pre>
-     *     <code>
-     *   [
-     *         {"field": "A", "values": A_list, "type": DataType.INT32},
-     *         {"field": "B", "values": B_list, "type": DataType.INT32},
-     *         {"field": "C", "values": C_list, "type": DataType.INT64},
-     *         {"field": "Vec", "values": vecs, "type": DataType.VECTOR_FLOAT}
-     *   ]
-     *     </code>
-     * </pre>
-     *
-     * @return <code>Builder</code>
-     */
-    public Builder withFields(@Nonnull List<Map<String, Object>> fields) {
-      this.fields = fields;
-      return this;
-    }
-
-    /**
-     * Add a single field to collection. Example field:
-     * <pre>
-     *   <code>
-     *      {"field": "A", "values": A_list, "type": DataType.INT64}, or
-     *      {"field": "B", "values": B_list, "type": DataType.INT32}, or
-     *      {"field": "C", "values": C_list, "type": DataType.FLOAT}, or
-     *      {"field": "Vec", "values": vecs, "type": DataType.VECTOR_FLOAT}
-     *   </code>
-     * </pre>
-     *
-     * @param field A field must have keys "field", "values" and "type".
-     *              <code>FieldBuilder</code> can be used to create a field.
-     * @see FieldBuilder
-     * @return <code>Builder</code>
-     */
-    public Builder field(@Nonnull Map<String, Object> field) {
-      this.fields.add(field);
-      return this;
+  public <T> InsertParam addField(String name, DataType type, List<T> values) {
+    AttrRecord.Builder record = AttrRecord.newBuilder();
+    switch (type) {
+      case INT32:
+        record.addAllInt32Value((List<Integer>) values);
+        break;
+      case INT64:
+        record.addAllInt64Value((List<Long>) values);
+        break;
+      case FLOAT:
+        record.addAllFloatValue((List<Float>) values);
+        break;
+      case DOUBLE:
+        record.addAllDoubleValue((List<Double>) values);
+        break;
+      default:
+        throw new UnsupportedDataType("Unsupported data type: " + type.name());
     }
+    builder.addFields(FieldValue.newBuilder()
+        .setFieldName(name)
+        .setTypeValue(type.getVal())
+        .setAttrRecord(record.build())
+        .build());
+    return this;
+  }
 
-    /**
-     * Optional. Default to an empty <code>ArrayList</code>. Only needed when entity ids are not
-     * auto-generated by milvus. This is specified when creating collection.
-     *
-     * @param entityIds a <code>List</code> of ids associated with the entities to insert.
-     * @return <code>Builder</code>
-     */
-    public Builder withEntityIds(@Nonnull List<Long> entityIds) {
-      this.entityIds = entityIds;
-      return this;
+  public <T> InsertParam addVectorField(String name, DataType type, List<T> values) {
+    VectorRecord.Builder record = VectorRecord.newBuilder();
+    switch (type) {
+      case VECTOR_FLOAT:
+        record.addAllRecords(
+            ((List<List<Float>>) values).stream()
+                .map(row -> VectorRowRecord.newBuilder().addAllFloatData(row).build())
+                .collect(Collectors.toList()));
+        break;
+      case VECTOR_BINARY:
+        record.addAllRecords(
+            ((List<ByteBuffer>) values).stream()
+                .map(row -> VectorRowRecord.newBuilder().setBinaryData(ByteString.copyFrom(row.slice())).build())
+                .collect(Collectors.toList()));
+        break;
+      default:
+        throw new UnsupportedDataType("Unsupported data type: " + type.name());
     }
+    builder.addFields(FieldValue.newBuilder()
+        .setFieldName(name)
+        .setTypeValue(type.getVal())
+        .setVectorRecord(record.build())
+        .build());
+    return this;
+  }
 
-    /**
-     * Optional. Default to an empty <code>String</code>
-     *
-     * @param partitionTag partition tag
-     * @return <code>Builder</code>
-     */
-    public Builder withPartitionTag(@Nonnull String partitionTag) {
-      this.partitionTag = partitionTag;
-      return this;
-    }
+  public InsertParam setPartitionTag(String partitionTag) {
+    builder.setPartitionTag(partitionTag);
+    return this;
+  }
 
-    public InsertParam build() {
-      return new InsertParam(this);
-    }
+  io.milvus.grpc.InsertParam grpc() {
+    return builder.build();
   }
 }

+ 0 - 54
src/main/java/io/milvus/client/InsertResponse.java

@@ -1,54 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package io.milvus.client;
-
-import java.util.List;
-
-/**
- * Contains the returned <code>response</code> and <code>entityIds</code> for <code>insert</code>
- */
-public class InsertResponse {
-  private final Response response;
-  private final List<Long> entityIds;
-
-  InsertResponse(Response response, List<Long> entityIds) {
-    this.response = response;
-    this.entityIds = entityIds;
-  }
-
-  public List<Long> getEntityIds() {
-    return entityIds;
-  }
-
-  public Response getResponse() {
-    return response;
-  }
-
-  /** @return <code>true</code> if the response status equals SUCCESS */
-  public boolean ok() {
-    return response.ok();
-  }
-
-  @Override
-  public String toString() {
-    return String.format(
-        "InsertResponse {%s, returned %d entity ids}", response.toString(), this.entityIds.size());
-  }
-}

+ 0 - 19
src/main/java/io/milvus/client/JsonBuilder.java

@@ -19,7 +19,6 @@
 
 package io.milvus.client;
 
-import javax.annotation.Nonnull;
 import org.json.JSONObject;
 
 /** Contains Json Parameter Builder */
@@ -44,24 +43,6 @@ public class JsonBuilder {
     return this;
   }
 
-  /**
-   * Add key-value pair to "params" in paramsInJson. Used by index.
-   *
-   * @param key The param key
-   * @param value The param value
-   * @return <code>JsonBuilder</code>
-   */
-  public JsonBuilder indexParam(String key, Object value) {
-    JSONObject jsonObject = new JSONObject(this.paramsInJson);
-    if (!jsonObject.has("params")) {
-      jsonObject.put("params", new JSONObject().put(key, value));
-    } else {
-      ((JSONObject) jsonObject.get("params")).put(key, value);
-    }
-    this.paramsInJson = jsonObject.toString();
-    return this;
-  }
-
   public String build() {
     return this.paramsInJson;
   }

+ 0 - 56
src/main/java/io/milvus/client/ListCollectionsResponse.java

@@ -1,56 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package io.milvus.client;
-
-import java.util.List;
-
-/**
- * Contains the returned <code>response</code> and <code>collectionNames</code> for <code>
- * listCollections</code>
- */
-public class ListCollectionsResponse {
-  private final Response response;
-  private final List<String> collectionNames;
-
-  ListCollectionsResponse(Response response, List<String> collectionNames) {
-    this.response = response;
-    this.collectionNames = collectionNames;
-  }
-
-  public List<String> getCollectionNames() {
-    return collectionNames;
-  }
-
-  public Response getResponse() {
-    return response;
-  }
-
-  /** @return <code>true</code> if the response status equals SUCCESS */
-  public boolean ok() {
-    return response.ok();
-  }
-
-  @Override
-  public String toString() {
-    return String.format(
-        "ListCollectionsResponse {%s, collection names = %s}",
-        response, collectionNames.toString());
-  }
-}

+ 0 - 30
src/main/java/io/milvus/client/ListIDInSegmentResponse.java

@@ -1,30 +0,0 @@
-package io.milvus.client;
-
-import java.util.List;
-
-/**
- * Contains the returned <code>response</code> and a <code>List</code> of ids present in a segment
- * for <code>listIDInSegment</code>.
- */
-public class ListIDInSegmentResponse {
-  private final Response response;
-  private final List<Long> ids;
-
-  ListIDInSegmentResponse(Response response, List<Long> ids) {
-    this.response = response;
-    this.ids = ids;
-  }
-
-  public List<Long> getIds() {
-    return ids;
-  }
-
-  public Response getResponse() {
-    return response;
-  }
-
-  /** @return <code>true</code> if the response status equals SUCCESS */
-  public boolean ok() {
-    return response.ok();
-  }
-}

+ 0 - 57
src/main/java/io/milvus/client/ListPartitionsResponse.java

@@ -1,57 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package io.milvus.client;
-
-import java.util.List;
-
-/**
- * Contains the returned <code>response</code> and <code>partitionList</code> for <code>
- * listPartitions</code>
- */
-public class ListPartitionsResponse {
-  private final Response response;
-  private final List<String> partitionList;
-
-  ListPartitionsResponse(Response response, List<String> partitionList) {
-    this.response = response;
-    this.partitionList = partitionList;
-  }
-
-  /** @return a <code>List</code> of partition tags. */
-  public List<String> getPartitionList() {
-    return partitionList;
-  }
-
-  public Response getResponse() {
-    return response;
-  }
-
-  /** @return <code>true</code> if the response status equals SUCCESS */
-  public boolean ok() {
-    return response.ok();
-  }
-
-  @Override
-  public String toString() {
-    return String.format(
-        "ListPartitionsResponse {%s, partition names = %s}",
-        response, partitionList.toString());
-  }
-}

+ 80 - 0
src/main/java/io/milvus/client/LoggingAdapter.java

@@ -0,0 +1,80 @@
+package io.milvus.client;
+
+import com.google.protobuf.Descriptors;
+import com.google.protobuf.MessageOrBuilder;
+import com.google.protobuf.TextFormat;
+import io.grpc.MethodDescriptor;
+import org.slf4j.Logger;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
+
+public class LoggingAdapter {
+  public static final LoggingAdapter DEFAULT_LOGGING_ADAPTER = new LoggingAdapter();
+  private static final AtomicLong traceId = new AtomicLong(0);
+
+  protected LoggingAdapter() {
+  }
+
+  protected String getTraceId() {
+    return Long.toHexString(traceId.getAndIncrement());
+  }
+
+  protected void logRequest(Logger logger, String traceId, MethodDescriptor method, Object message) {
+    if (logger.isTraceEnabled()) {
+      logger.trace("TraceId: {}, Method: {}, Request: {}", traceId, method.getFullMethodName(), trace(message));
+    } else if (logger.isInfoEnabled()) {
+      logger.info("TraceId: {}, Method: {}, Request: {}", traceId, method.getFullMethodName(), info(message));
+    }
+  }
+
+  protected void logResponse(Logger logger, String traceId, MethodDescriptor method, Object message) {
+    if (logger.isTraceEnabled()) {
+      logger.trace("TraceId: {}, Method: {}, Response: {}", traceId, method.getFullMethodName(), trace(message));
+    } else if (logger.isInfoEnabled()) {
+      logger.info("TraceId: {}, Method: {}, Response: {}", traceId, method.getFullMethodName(), info(message));
+    }
+  }
+
+  protected String info(Object message) {
+    if (message instanceof MessageOrBuilder) {
+      MessageOrBuilder msg = (MessageOrBuilder) message;
+      StringBuilder output = new StringBuilder(msg.getDescriptorForType().getName());
+      write((MessageOrBuilder) message, output);
+      return output.toString();
+    }
+    return message.toString();
+  }
+
+  protected String trace(Object message) {
+    if (message instanceof MessageOrBuilder) {
+      return TextFormat.printer().printToString((MessageOrBuilder) message);
+    }
+    return message.toString();
+  }
+
+  protected void write(MessageOrBuilder message, StringBuilder output) {
+    output.append(" { ");
+    message.getAllFields().entrySet().stream().forEach(e -> {
+      if (e.getKey().isRepeated()) {
+        output.append(e.getKey().getName())
+            .append(" [ ")
+            .append(((List<?>) e.getValue()).size())
+            .append(" items ], ");
+      } else if (e.getKey().isMapField()) {
+        output.append(e.getKey().getName())
+            .append(" { ")
+            .append(((List<?>) e.getValue()).size())
+            .append(" entries }, ");
+      } else if (e.getKey().getJavaType() == Descriptors.FieldDescriptor.JavaType.MESSAGE) {
+        output.append(e.getKey().getName());
+        write((MessageOrBuilder) e.getValue(), output);
+      } else {
+        output.append(TextFormat.printer().shortDebugString(e.getKey(), e.getValue()))
+            .append(", ");
+      }
+    });
+    output.setLength(output.length() - 2);
+    output.append(" } ");
+  }
+}

+ 11 - 0
src/main/java/io/milvus/client/MetricType.java

@@ -0,0 +1,11 @@
+package io.milvus.client;
+
+public enum MetricType {
+  HAMMING,
+  IP,
+  JACCARD,
+  L2,
+  SUBSTRUCTURE,
+  SUPERSTRUCTURE,
+  TANIMOTO
+}

+ 57 - 107
src/main/java/io/milvus/client/MilvusClient.java

@@ -25,6 +25,7 @@ import org.apache.commons.lang3.exception.ExceptionUtils;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.List;
+import java.util.Map;
 import java.util.Properties;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Supplier;
@@ -32,6 +33,8 @@ import java.util.function.Supplier;
 /** The Milvus Client Interface */
 public interface MilvusClient {
 
+  String extraParamKey = "params";
+
   String clientVersion = new Supplier<String>() {
 
     @Override
@@ -49,6 +52,8 @@ public interface MilvusClient {
     }
   }.get();
 
+  String target();
+
   /** @return current Milvus client version: 0.9.0 */
   default String getClientVersion() {
     return clientVersion;
@@ -83,30 +88,24 @@ public interface MilvusClient {
    * Refer to <code>withFields</code> method for example <code>fields</code> usage.
    * </pre>
    *
-   * @return <code>Response</code>
    * @see CollectionMapping
-   * @see Response
    */
-  Response createCollection(CollectionMapping collectionMapping);
+  void createCollection(CollectionMapping collectionMapping);
 
   /**
    * Checks whether the collection exists
    *
    * @param collectionName collection to check
-   * @return <code>HasCollectionResponse</code>
-   * @see HasCollectionResponse
-   * @see Response
+   * @return true if the collection exists, false otherwise.
    */
-  HasCollectionResponse hasCollection(String collectionName);
+  boolean hasCollection(String collectionName);
 
   /**
    * Drops collection
    *
    * @param collectionName collection to drop
-   * @return <code>Response</code>
-   * @see Response
    */
-  Response dropCollection(String collectionName);
+  void dropCollection(String collectionName);
 
   /**
    * Creates index specified by <code>index</code>
@@ -123,11 +122,9 @@ public interface MilvusClient {
    * </code>
    * </pre>
    *
-   * @return <code>Response</code>
    * @see Index
-   * @see Response
    */
-  Response createIndex(Index index);
+  void createIndex(Index index);
 
   /**
    * Creates index specified by <code>index</code> asynchronously
@@ -146,49 +143,42 @@ public interface MilvusClient {
    *
    * @return a <code>ListenableFuture</code> object which holds the <code>Response</code>
    * @see Index
-   * @see Response
    * @see ListenableFuture
    */
-  ListenableFuture<Response> createIndexAsync(Index index);
+  ListenableFuture<Void> createIndexAsync(Index index);
 
   /**
    * Creates a partition specified by <code>collectionName</code> and <code>tag</code>
    *
    * @param collectionName collection name
    * @param tag partition tag
-   * @return <code>Response</code>
-   * @see Response
    */
-  Response createPartition(String collectionName, String tag);
+  void createPartition(String collectionName, String tag);
 
   /**
    * Checks whether the partition exists
    *
    * @param collectionName collection name
    * @param tag partition tag
-   * @return <code>HasPartitionResponse</code>
-   * @see Response
+   * @return true if the partition exists, false otherwise.
    */
-  HasPartitionResponse hasPartition(String collectionName, String tag);
+  boolean hasPartition(String collectionName, String tag);
 
   /**
    * Lists current partitions of a collection
    *
    * @param collectionName collection name
-   * @return <code>ListPartitionsResponse</code>
-   * @see ListPartitionsResponse
-   * @see Response
+   * @return a list of partition names
    */
-  ListPartitionsResponse listPartitions(String collectionName);
+  List<String> listPartitions(String collectionName);
 
   /**
    * Drops partition specified by <code>collectionName</code> and <code>tag</code>
    *
    * @param collectionName collection name
    * @param tag partition tag
-   * @see Response
    */
-  Response dropPartition(String collectionName, String tag);
+  void dropPartition(String collectionName, String tag);
 
   /**
    * Inserts data specified by <code>insertParam</code>
@@ -205,12 +195,10 @@ public interface MilvusClient {
    * </code>
    * </pre>
    *
-   * @return <code>InsertResponse</code>
+   * @return a list of ids for the inserted entities
    * @see InsertParam
-   * @see InsertResponse
-   * @see Response
    */
-  InsertResponse insert(InsertParam insertParam);
+  List<Long> insert(InsertParam insertParam);
 
   /**
    * Inserts data specified by <code>insertParam</code> asynchronously
@@ -227,13 +215,11 @@ public interface MilvusClient {
    * </code>
    * </pre>
    *
-   * @return a <code>ListenableFuture</code> object which holds the <code>InsertResponse</code>
+   * @return a <code>ListenableFuture</code> object which holds the list of ids for the inserted entities.
    * @see InsertParam
-   * @see InsertResponse
-   * @see Response
    * @see ListenableFuture
    */
-  ListenableFuture<InsertResponse> insertAsync(InsertParam insertParam);
+  ListenableFuture<List<Long>> insertAsync(InsertParam insertParam);
 
   /**
    * Searches entities specified by <code>searchParam</code>
@@ -250,13 +236,11 @@ public interface MilvusClient {
    * </code>
    * </pre>
    *
-   * @return <code>SearchResponse</code>
+   * @return <code>SearchResult</code>
    * @see SearchParam
-   * @see SearchResponse
-   * @see SearchResponse.QueryResult
-   * @see Response
+   * @see SearchResult
    */
-  SearchResponse search(SearchParam searchParam);
+  SearchResult search(SearchParam searchParam);
 
   /**
    * Searches entities specified by <code>searchParam</code> asynchronously
@@ -273,77 +257,64 @@ public interface MilvusClient {
    * </code>
    * </pre>
    *
-   * @return a <code>ListenableFuture</code> object which holds the <code>SearchResponse</code>
+   * @return a <code>ListenableFuture</code> object which holds the <code>SearchResult</code>
    * @see SearchParam
-   * @see SearchResponse
-   * @see SearchResponse.QueryResult
-   * @see Response
+   * @see SearchResult
    * @see ListenableFuture
    */
-  ListenableFuture<SearchResponse> searchAsync(SearchParam searchParam);
+  ListenableFuture<SearchResult> searchAsync(SearchParam searchParam);
 
   /**
    * Gets collection info
    *
    * @param collectionName collection to describe
-   * @return <code>GetCollectionInfoResponse</code>
-   * @see GetCollectionInfoResponse
+   * @return <code>CollectionMapping</code>
    * @see CollectionMapping
-   * @see Response
    */
-  GetCollectionInfoResponse getCollectionInfo(String collectionName);
+  CollectionMapping getCollectionInfo(String collectionName);
 
   /**
    * Lists current collections
    *
-   * @return <code>ListCollectionsResponse</code>
-   * @see ListCollectionsResponse
-   * @see Response
+   * @return a list of collection names
    */
-  ListCollectionsResponse listCollections();
+  List<String> listCollections();
 
   /**
    * Gets current entity count of a collection
    *
    * @param collectionName collection name
-   * @return <code>CountEntitiesResponse</code>
-   * @see CountEntitiesResponse
-   * @see Response
+   * @return a count of entities in the collection
    */
-  CountEntitiesResponse countEntities(String collectionName);
+  long countEntities(String collectionName);
 
   /**
    * Gets server status
    *
-   * @return <code>Response</code>
-   * @see Response
+   * @return a server status string
    */
-  Response getServerStatus();
+  String getServerStatus();
 
   /**
    * Gets server version
    *
-   * @return <code>Response</code>
-   * @see Response
+   * @return a server version string.
    */
-  Response getServerVersion();
+  String getServerVersion();
 
   /**
    * Sends a command to server
    *
-   * @return <code>Response</code> command's response will be return in <code>message</code>
-   * @see Response
+   * @return a message string
    */
-  Response command(String command);
+  String command(String command);
 
   /**
    * Pre-loads collection to memory
    *
    * @param collectionName collection to load
-   * @return <code>Response</code>
-   * @see Response
    */
-  Response loadCollection(String collectionName);
+  void loadCollection(String collectionName);
 
   /**
    * Drops collection index
@@ -351,10 +322,8 @@ public interface MilvusClient {
    * @param collectionName The collection to drop index.
    * @param fieldName Name of the field to drop index for. If this is set to empty string,
    *                  index of all fields in the collection will be dropped.
-   * @return <code>Response</code>
-   * @see Response
    */
-  Response dropIndex(String collectionName, String fieldName);
+  void dropIndex(String collectionName, String fieldName);
 
   /**
    * Shows collection information. A collection consists of one or multiple partitions (including
@@ -363,10 +332,8 @@ public interface MilvusClient {
    * result will be returned as JSON string.
    *
    * @param collectionName collection to show info from
-   * @return <code>Response</code>
-   * @see Response
    */
-  Response getCollectionStats(String collectionName);
+  String getCollectionStats(String collectionName);
 
   /**
    * Gets entities data by id array
@@ -375,85 +342,71 @@ public interface MilvusClient {
    * @param ids a <code>List</code> of entity ids
    * @param fieldNames  a <code>List</code> of field names. Server will only return entity
    *                    information for these fields.
-   * @return <code>GetEntityByIDResponse</code>
-   * @see GetEntityByIDResponse
-   * @see Response
+   * @return a map of entity id to entity properties
    */
-  GetEntityByIDResponse getEntityByID(String collectionName, List<Long> ids, List<String> fieldNames);
+  Map<Long, Map<String, Object>> getEntityByID(String collectionName, List<Long> ids, List<String> fieldNames);
 
   /**
    * Gets entities data by id array
    *
    * @param collectionName collection to get entities from
    * @param ids a <code>List</code> of entity ids
-   * @return <code>GetEntityByIDResponse</code>
-   * @see GetEntityByIDResponse
-   * @see Response
+   * @return a map of entity id to entity properties
    */
-  GetEntityByIDResponse getEntityByID(String collectionName, List<Long> ids);
+  Map<Long, Map<String, Object>> getEntityByID(String collectionName, List<Long> ids);
 
   /**
    * Gets all entity ids in a segment
    *
    * @param collectionName collection to get entity ids from
    * @param segmentId segment id in the collection
-   * @return <code>ListIDInSegmentResponse</code>
-   * @see ListIDInSegmentResponse
-   * @see Response
+   * @return a list of entity ids in the segment
    */
-  ListIDInSegmentResponse listIDInSegment(String collectionName, Long segmentId);
+  List<Long> listIDInSegment(String collectionName, Long segmentId);
 
   /**
    * Deletes data in a collection by a list of ids
    *
    * @param collectionName collection to delete ids from
    * @param ids a <code>List</code> of entity ids to delete
-   * @return <code>Response</code>
-   * @see Response
    */
-  Response deleteEntityByID(String collectionName, List<Long> ids);
+  void deleteEntityByID(String collectionName, List<Long> ids);
 
   /**
    * Flushes data in a list collections. Newly inserted or modifications on data will be visible
    * after <code>flush</code> returned
    *
    * @param collectionNames a <code>List</code> of collections to flush
-   * @return <code>Response</code>
-   * @see Response
    */
-  Response flush(List<String> collectionNames);
+  void flush(List<String> collectionNames);
 
   /**
    * Flushes data in a list collections asynchronously. Newly inserted or modifications on data will
    * be visible after <code>flush</code> returned
    *
    * @param collectionNames a <code>List</code> of collections to flush
-   * @return a <code>ListenableFuture</code> object which holds the <code>Response</code>
-   * @see Response
+   * @return <code>ListenableFuture</code>
    * @see ListenableFuture
    */
-  ListenableFuture<Response> flushAsync(List<String> collectionNames);
+  ListenableFuture<Void> flushAsync(List<String> collectionNames);
 
   /**
    * Flushes data in a collection. Newly inserted or modifications on data will be visible after
    * <code>flush</code> returned
    *
    * @param collectionName name of collection to flush
-   * @return <code>Response</code>
-   * @see Response
    */
-  Response flush(String collectionName);
+  void flush(String collectionName);
 
   /**
    * Flushes data in a collection asynchronously. Newly inserted or modifications on data will be
    * visible after <code>flush</code> returned
    *
    * @param collectionName name of collection to flush
-   * @return a <code>ListenableFuture</code> object which holds the <code>Response</code>
-   * @see Response
+   * @return <code>ListenableFuture</code>
    * @see ListenableFuture
    */
-  ListenableFuture<Response> flushAsync(String collectionName);
+  ListenableFuture<Void> flushAsync(String collectionName);
 
   /**
    * Compacts the collection, erasing deleted data from disk and rebuild index in background (if the
@@ -470,11 +423,9 @@ public interface MilvusClient {
    * </code>
    * </pre>
    *
-   * @return <code>Response</code>
    * @see CompactParam
-   * @see Response
    */
-  Response compact(CompactParam compactParam);
+  void compact(CompactParam compactParam);
 
   /**
    * Compacts the collection, erasing deleted data from disk and rebuild index in background (if the
@@ -493,8 +444,7 @@ public interface MilvusClient {
    *
    * @return a <code>ListenableFuture</code> object which holds the <code>Response</code>
    * @see CompactParam
-   * @see Response
    * @see ListenableFuture
    */
-  ListenableFuture<Response> compactAsync(CompactParam compactParam);
+  ListenableFuture<Void> compactAsync(CompactParam compactParam);
 }

File diff suppressed because it is too large
+ 325 - 1465
src/main/java/io/milvus/client/MilvusGrpcClient.java


+ 0 - 115
src/main/java/io/milvus/client/Response.java

@@ -1,115 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package io.milvus.client;
-
-import java.util.Arrays;
-import java.util.Optional;
-
-/**
- * Represents response of a client call. Contains a <code>status</code> and a <code>message</code>
- */
-public class Response {
-
-  private final Status status;
-  private final String message;
-
-  public Response(Status status, String message) {
-    this.status = status;
-    this.message = message;
-  }
-
-  public Response(Status status) {
-    this.status = status;
-    if (status == Status.CLIENT_NOT_CONNECTED) {
-      this.message = "You are not connected to Milvus server";
-    } else {
-      this.message = "Success!";
-    }
-  }
-
-  public Status getStatus() {
-    return status;
-  }
-
-  public String getMessage() {
-    return message;
-  }
-
-  /** @return <code>true</code> if status equals SUCCESS */
-  public boolean ok() {
-    return status == Status.SUCCESS;
-  }
-
-  @Override
-  public String toString() {
-    return String.format("Response {code = %s, message = \"%s\"}", status.name(), this.message);
-  }
-
-  /** Represents server and client side status code */
-  public enum Status {
-    // Server side error
-    SUCCESS(0),
-    UNEXPECTED_ERROR(1),
-    CONNECT_FAILED(2),
-    PERMISSION_DENIED(3),
-    COLLECTION_NOT_EXISTS(4),
-    ILLEGAL_ARGUMENT(5),
-    ILLEGAL_DIMENSION(7),
-    ILLEGAL_INDEX_TYPE(8),
-    ILLEGAL_COLLECTION_NAME(9),
-    ILLEGAL_TOPK(10),
-    ILLEGAL_ROWRECORD(11),
-    ILLEGAL_VECTOR_ID(12),
-    ILLEGAL_SEARCH_RESULT(13),
-    FILE_NOT_FOUND(14),
-    META_FAILED(15),
-    CACHE_FAILED(16),
-    CANNOT_CREATE_FOLDER(17),
-    CANNOT_CREATE_FILE(18),
-    CANNOT_DELETE_FOLDER(19),
-    CANNOT_DELETE_FILE(20),
-    BUILD_INDEX_ERROR(21),
-    ILLEGAL_NLIST(22),
-    ILLEGAL_METRIC_TYPE(23),
-    OUT_OF_MEMORY(24),
-
-    // Client side error
-    RPC_ERROR(-1),
-    CLIENT_NOT_CONNECTED(-2),
-    UNKNOWN(-3),
-    VERSION_MISMATCH(-4);
-
-    private final int code;
-
-    Status(int code) {
-      this.code = code;
-    }
-
-    public static Status valueOf(int val) {
-      Optional<Status> search =
-          Arrays.stream(values()).filter(status -> status.code == val).findFirst();
-      return search.orElse(UNKNOWN);
-    }
-
-    public int getCode() {
-      return code;
-    }
-  }
-}

+ 128 - 106
src/main/java/io/milvus/client/SearchParam.java

@@ -19,133 +19,155 @@
 
 package io.milvus.client;
 
+import com.google.common.collect.ImmutableList;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.UnsafeByteOperations;
+import io.milvus.client.exception.InvalidDsl;
+import io.milvus.grpc.KeyValuePair;
+import io.milvus.grpc.VectorParam;
+import io.milvus.grpc.VectorRecord;
+import io.milvus.grpc.VectorRowRecord;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.nio.ByteBuffer;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
-import javax.annotation.Nonnull;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
 
 /** Contains parameters for <code>search</code> */
 public class SearchParam {
+  private static final String VECTOR_QUERY_KEY = "vector";
+  private static final String VECTOR_QUERY_PLACEHOLDER = "placeholder";
 
-  private final String collectionName;
-  private final String dsl;
-  private final List<String> partitionTags;
-  private final String paramsInJson;
+  private io.milvus.grpc.SearchParam.Builder builder;
 
-  private SearchParam(@Nonnull Builder builder) {
-    this.collectionName = builder.collectionName;
-    this.dsl = builder.dsl;
-    this.partitionTags = builder.partitionTags;
-    this.paramsInJson = builder.paramsInJson;
+  public static SearchParam create(String collectionName) {
+    return new SearchParam(collectionName);
   }
 
-  public String getCollectionName() {
-    return collectionName;
+  private SearchParam(String collectionName) {
+    builder = io.milvus.grpc.SearchParam.newBuilder();
+    builder.setCollectionName(collectionName);
   }
 
-  public String getDSL() { return dsl; }
-
-  public List<String> getPartitionTags() {
-    return partitionTags;
+  public SearchParam setDsl(String dsl) {
+    try {
+      JSONObject dslJson = new JSONObject(dsl);
+      JSONObject vectorQueryParent = locateVectorQuery(dslJson)
+          .orElseThrow(() -> new InvalidDsl("A vector query must be specified", dsl));
+      JSONObject vectorQueries = vectorQueryParent.getJSONObject(VECTOR_QUERY_KEY);
+      vectorQueryParent.put(VECTOR_QUERY_KEY, VECTOR_QUERY_PLACEHOLDER);
+      String vectorQueryField = vectorQueries.keys().next();
+      JSONObject vectorQuery = vectorQueries.getJSONObject(vectorQueryField);
+      String vectorQueryType = vectorQuery.getString("type");
+      JSONArray vectorQueryData = vectorQuery.getJSONArray("query");
+
+      VectorRecord vectorRecord;
+      switch (vectorQueryType) {
+        case "float":
+          vectorRecord = toFloatVectorRecord(vectorQueryData);
+          break;
+        case "binary":
+          vectorRecord = toBinaryVectorRecord(vectorQueryData);
+          break;
+        default:
+          throw new InvalidDsl("Unsupported vector type: " + vectorQueryType, dsl);
+      }
+
+      JSONObject json = new JSONObject();
+      vectorQuery.remove("type");
+      vectorQuery.remove("query");
+      json.put("placeholder", vectorQueries);
+      VectorParam vectorParam = VectorParam.newBuilder()
+          .setJson(json.toString())
+          .setRowRecord(vectorRecord)
+          .build();
+
+      builder.setDsl(dslJson.toString())
+          .addAllVectorParam(ImmutableList.of(vectorParam));
+      return this;
+    } catch (JSONException e) {
+      throw new InvalidDsl(e.getMessage(), dsl);
+    }
   }
 
-  public String getParamsInJson() {
-    return paramsInJson;
+  public SearchParam setPartitionTags(List<String> partitionTags) {
+    builder.addAllPartitionTagArray(partitionTags);
+    return this;
   }
 
-  /** Builder for <code>SearchParam</code> */
-  public static class Builder {
-    // Required parameter
-    private final String collectionName;
+  public SearchParam setParamsInJson(String paramsInJson) {
+    builder.addExtraParams(KeyValuePair.newBuilder()
+        .setKey(MilvusClient.extraParamKey)
+        .setValue(paramsInJson)
+        .build());
+    return this;
+  }
 
-    // Optional parameters - initialized to default values
-    private List<String> partitionTags = new ArrayList<>();
-    private String dsl = "{}";
-    private String paramsInJson = "{}";
+  io.milvus.grpc.SearchParam grpc() {
+    return builder.build();
+  }
 
-    /** @param collectionName collection to search from */
-    public Builder(@Nonnull String collectionName) {
-      this.collectionName = collectionName;
-    }
+  private Optional<JSONObject> locateVectorQuery(Object obj) {
+    return obj instanceof JSONObject ? locateVectorQuery((JSONObject) obj)
+        : obj instanceof JSONArray ? locateVectorQuery((JSONArray) obj)
+        : Optional.empty();
+  }
 
-    /**
-     * The DSL statement for search. DSL provides a more convenient and idiomatic way to write and
-     * manipulate queries. It is in JSON format (passed into builder as String), and an example of
-     * DSL statement is as follows.
-     *
-     * <pre>
-     *   <code>
-     * {
-     *     "bool": {
-     *         "must": [
-     *             {
-     *                 "term": {
-     *                     "A": [1, 2, 5]
-     *                 }
-     *             },
-     *             {
-     *                 "range": {
-     *                     "B": {"GT": 1, "LT": 100}
-     *                 }
-     *             },
-     *             {
-     *                 "vector": {
-     *                     "Vec": {
-     *                         "topk": 10, "type": "float", "query": list_of_vecs, "params": {"nprobe": 10}
-     *                     }
-     *                 }
-     *             }
-     *         ],
-     *     },
-     * }
-     *   </code>
-     * </pre>
-     *
-     * <p>Note that "vector" must be included in DSL. The "params" in "Vec" is different for different
-     * index types. Refer to Milvus documentation for more information about DSL.</p>
-     *
-     * <p>A "type" key must be present in "Vec" field to indicate whether your query vectors are
-     * "float" or "binary".</p>
-     *
-     * @param dsl The DSL String in JSON format
-     * @return <code>Builder</code>
-     */
-    public SearchParam.Builder withDSL(@Nonnull String dsl) {
-      this.dsl = dsl;
-      return this;
-    }
+  private Optional<JSONObject> locateVectorQuery(JSONArray array) {
+    return StreamSupport.stream(array.spliterator(), false)
+        .map(this::locateVectorQuery)
+        .filter(Optional::isPresent)
+        .map(Optional::get)
+        .findFirst();
+  }
 
-    /**
-     * Optional. Search vectors with corresponding <code>partitionTags</code>. Default to an empty
-     * <code>List</code>
-     *
-     * @param partitionTags a <code>List</code> of partition tags
-     * @return <code>Builder</code>
-     */
-    public SearchParam.Builder withPartitionTags(@Nonnull List<String> partitionTags) {
-      this.partitionTags = partitionTags;
-      return this;
+  private Optional<JSONObject> locateVectorQuery(JSONObject obj) {
+    if (obj.opt(VECTOR_QUERY_KEY) instanceof JSONObject) {
+      return Optional.of(obj);
     }
+    return obj.keySet().stream()
+        .map(key -> locateVectorQuery(obj.get(key)))
+        .filter(Optional::isPresent)
+        .map(Optional::get)
+        .findFirst();
+  }
 
-    /**
-     * Optional. Default to empty <code>String</code>. This is to specify the fields you would like
-     * Milvus server to return from query results. No field information will be returned if this
-     * is not specified. Example:
-     * <pre>
-     *   {"fields": ["B", "D"]}
-     * </pre>
-     *
-     * @param paramsInJson extra parameters in JSON format
-     * @return <code>Builder</code>
-     */
-    public SearchParam.Builder withParamsInJson(@Nonnull String paramsInJson) {
-      this.paramsInJson = paramsInJson;
-      return this;
-    }
+  private VectorRecord toFloatVectorRecord(JSONArray data) {
+    return VectorRecord.newBuilder().addAllRecords(
+        StreamSupport.stream(data.spliterator(), false)
+            .map(element -> (JSONArray) element)
+            .map(array -> {
+              int dimension = array.length();
+              List<Float> vector = new ArrayList<>(dimension);
+              for (int i = 0; i < dimension; i++) {
+                vector.add(array.getFloat(i));
+              }
+              return VectorRowRecord.newBuilder().addAllFloatData(vector).build();
+            })
+            .collect(Collectors.toList()))
+        .build();
+  }
 
-    public SearchParam build() {
-      return new SearchParam(this);
-    }
+  private VectorRecord toBinaryVectorRecord(JSONArray data) {
+    return VectorRecord.newBuilder().addAllRecords(
+        StreamSupport.stream(data.spliterator(), false)
+            .map(element -> (JSONArray) element)
+            .map(array -> {
+              int dimension = array.length();
+              ByteBuffer bytes = ByteBuffer.allocate(dimension);
+              for (int i = 0; i < dimension; i++) {
+                bytes.put(array.getNumber(i).byteValue());
+              }
+              bytes.flip();
+              ByteString vector = UnsafeByteOperations.unsafeWrap(bytes);
+              return VectorRowRecord.newBuilder().setBinaryData(vector).build();
+            })
+            .collect(Collectors.toList()))
+        .build();
   }
 }

+ 0 - 150
src/main/java/io/milvus/client/SearchResponse.java

@@ -1,150 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package io.milvus.client;
-
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
-import java.util.stream.LongStream;
-
-/**
- * Contains the returned <code>response</code> and query results for <code>search</code>
- */
-public class SearchResponse {
-
-  private Response response;
-  private int numQueries;
-  private long topK;
-  private List<List<Long>> resultIdsList;
-  private List<List<Float>> resultDistancesList;
-  private List<List<Map<String, Object>>> fieldsMap;
-
-  public int getNumQueries() {
-    return numQueries;
-  }
-
-  void setNumQueries(int numQueries) {
-    this.numQueries = numQueries;
-  }
-
-  public long getTopK() {
-    return topK;
-  }
-
-  void setTopK(long topK) {
-    this.topK = topK;
-  }
-
-  /**
-   * @return a <code>List</code> of <code>QueryResult</code>s. Each inner <code>List</code> contains
-   *     the query result of an entity.
-   */
-  public List<List<QueryResult>> getQueryResultsList() {
-    return IntStream.range(0, numQueries)
-        .mapToObj(
-            i ->
-                IntStream.range(0, resultIdsList.get(i).size())
-                    .mapToObj(
-                        j ->
-                            new QueryResult(
-                                resultIdsList.get(i).get(j),
-                                resultDistancesList.get(i).get(j)))
-                    .collect(Collectors.toList()))
-        .collect(Collectors.toList());
-  }
-
-  /**
-   * @return a <code>List</code> of result ids. Each inner <code>List</code> contains the result ids
-   *     of an entity.
-   */
-  public List<List<Long>> getResultIdsList() {
-    return resultIdsList;
-  }
-
-  void setResultIdsList(List<List<Long>> resultIdsList) {
-    this.resultIdsList = resultIdsList;
-  }
-
-  /**
-   * @return a <code>List</code> of result distances. Each inner <code>List</code> contains
-   *     the result distances of an entity.
-   */
-  public List<List<Float>> getResultDistancesList() {
-    return resultDistancesList;
-  }
-
-  void setResultDistancesList(List<List<Float>> resultDistancesList) {
-    this.resultDistancesList = resultDistancesList;
-  }
-
-  public Response getResponse() {
-    return response;
-  }
-
-  void setResponse(Response response) {
-    this.response = response;
-  }
-
-  /**
-   * @return A <code>List</code> of map with fields information. Each inner <code>List</code> contains
-   * a <code>Map</code> of field names to records in a row.
-   * The record object can be one of int, long, float, double, List<Float> or List<Byte>
-   * depending on the field's <code>DataType</code> you specified.
-   */
-  public List<List<Map<String, Object>>> getFieldsMap() { return fieldsMap; }
-
-  void setFieldsMap(List<List<Map<String, Object>>> fieldsMap) {
-    this.fieldsMap = fieldsMap;
-  }
-
-  /** @return <code>true</code> if the response status equals SUCCESS */
-  public boolean ok() {
-    return response.ok();
-  }
-
-  @Override
-  public String toString() {
-    return String.format(
-        "SearchResponse {%s, returned results for %d queries}", response.toString(), numQueries);
-  }
-
-  /**
-   * Represents a single result of an entity query. Contains the result <code>entityId</code> and its
-   * <code>distance</code> to the entity being queried
-   */
-  public static class QueryResult {
-    private final long entityId;
-    private final float distance;
-
-    QueryResult(long entityId, float distance) {
-      this.entityId = entityId;
-      this.distance = distance;
-    }
-
-    public long getEntityId() {
-      return entityId;
-    }
-
-    public float getDistance() {
-      return distance;
-    }
-  }
-}

+ 72 - 0
src/main/java/io/milvus/client/SearchResult.java

@@ -0,0 +1,72 @@
+package io.milvus.client;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+public class SearchResult {
+  private int numQueries;
+  private long topK;
+  private List<List<Long>> resultIdsList;
+  private List<List<Float>> resultDistancesList;
+  private List<List<Map<String, Object>>> fieldsMap;
+
+  public SearchResult(int numQueries,
+                      long topK,
+                      List<List<Long>> resultIdsList,
+                      List<List<Float>> resultDistancesList,
+                      List<List<Map<String, Object>>> fieldsMap) {
+    this.numQueries = numQueries;
+    this.topK = topK;
+    this.resultIdsList = resultIdsList;
+    this.resultDistancesList = resultDistancesList;
+    this.fieldsMap = fieldsMap;
+  }
+
+  public int getNumQueries() {
+    return numQueries;
+  }
+
+  public long getTopK() {
+    return topK;
+  }
+
+  public List<List<Long>> getResultIdsList() {
+    return resultIdsList;
+  }
+
+  public List<List<Float>> getResultDistancesList() {
+    return resultDistancesList;
+  }
+
+  public List<List<Map<String, Object>>> getFieldsMap() {
+    return fieldsMap;
+  }
+
+  public List<List<QueryResult>> getQueryResultsList() {
+    return IntStream.range(0, numQueries)
+        .mapToObj(i -> IntStream.range(0, resultIdsList.get(i).size())
+            .mapToObj(j -> new QueryResult(resultIdsList.get(i).get(j), resultDistancesList.get(i).get(j)))
+            .collect(Collectors.toList()))
+        .collect(Collectors.toList());
+  }
+
+  public static class QueryResult {
+    private final long entityId;
+    private final float distance;
+
+    QueryResult(long entityId, float distance) {
+      this.entityId = entityId;
+      this.distance = distance;
+    }
+
+    public long getEntityId() {
+      return entityId;
+    }
+
+    public float getDistance() {
+      return distance;
+    }
+  }
+}

+ 16 - 0
src/main/java/io/milvus/client/exception/ClientSideMilvusException.java

@@ -0,0 +1,16 @@
+package io.milvus.client.exception;
+
+public class ClientSideMilvusException extends MilvusException {
+
+  public ClientSideMilvusException(String target) {
+    super(target, false, null, null);
+  }
+
+  public ClientSideMilvusException(String target, Throwable cause) {
+    super(target, false, null, cause);
+  }
+
+  public ClientSideMilvusException(String target, String message) {
+    super(target, false, message, null);
+  }
+}

+ 0 - 7
src/main/java/io/milvus/client/exception/InitializationException.java

@@ -1,7 +0,0 @@
-package io.milvus.client.exception;
-
-public class InitializationException extends MilvusException {
-  public InitializationException(String host, String message) {
-    super(false, host + ": " + message);
-  }
-}

+ 15 - 0
src/main/java/io/milvus/client/exception/InvalidDsl.java

@@ -0,0 +1,15 @@
+package io.milvus.client.exception;
+
+public class InvalidDsl extends ClientSideMilvusException {
+  private String dsl;
+
+  public InvalidDsl(String dsl, String message) {
+    super(null, message);
+    this.dsl = dsl;
+  }
+
+  @Override
+  protected String getErrorMessage() {
+    return super.getErrorMessage() + ": " + dsl;
+  }
+}

+ 14 - 8
src/main/java/io/milvus/client/exception/MilvusException.java

@@ -1,20 +1,26 @@
 package io.milvus.client.exception;
 
-public class MilvusException extends RuntimeException {
+public abstract class MilvusException extends RuntimeException {
+  private String target;
   private boolean fillInStackTrace;
 
-  MilvusException(boolean fillInStackTrace) {
-    this.fillInStackTrace = fillInStackTrace;
+  MilvusException(String target, boolean fillInStackTrace) {
+    this(target, fillInStackTrace, null, null);
   }
 
-  MilvusException(boolean fillInStackTrace, Throwable cause) {
-    super(cause);
+  MilvusException(String target, boolean fillInStackTrace, String message, Throwable cause) {
+    super(message, cause);
+    this.target = target;
     this.fillInStackTrace = fillInStackTrace;
   }
 
-  MilvusException(boolean fillInStackTrace, String message) {
-    super(message);
-    this.fillInStackTrace = fillInStackTrace;
+  @Override
+  public final String getMessage() {
+    return String.format("%s: %s", target, getErrorMessage());
+  }
+
+  protected String getErrorMessage() {
+    return super.getMessage();
   }
 
   @Override

+ 33 - 0
src/main/java/io/milvus/client/exception/ServerSideMilvusException.java

@@ -0,0 +1,33 @@
+package io.milvus.client.exception;
+
+import io.milvus.grpc.ErrorCode;
+import io.milvus.grpc.Status;
+
+public class ServerSideMilvusException extends MilvusException {
+  private ErrorCode errorCode;
+  private String reason;
+
+  public ServerSideMilvusException(String target, Status status) {
+    super(target, false);
+    this.errorCode = status.getErrorCode();
+    this.reason = status.getReason();
+  }
+
+  public ErrorCode getErrorCode() {
+    return errorCode;
+  }
+
+  public String getReason() {
+    return reason;
+  }
+
+  @Override
+  public synchronized Throwable fillInStackTrace() {
+    return this;
+  }
+
+  @Override
+  public String getErrorMessage() {
+    return String.format("ServerSideMilvusException{errorCode=%s, reason=%s}", errorCode, reason);
+  }
+}

+ 7 - 0
src/main/java/io/milvus/client/exception/UnsupportedDataType.java

@@ -0,0 +1,7 @@
+package io.milvus.client.exception;
+
+public class UnsupportedDataType extends ClientSideMilvusException {
+  public UnsupportedDataType(String message) {
+    super(null, message);
+  }
+}

+ 6 - 8
src/main/java/io/milvus/client/exception/UnsupportedServerVersion.java

@@ -2,21 +2,19 @@ package io.milvus.client.exception;
 
 import io.milvus.client.MilvusClient;
 
-public class UnsupportedServerVersion extends MilvusException {
-  private String host;
+public class UnsupportedServerVersion extends ClientSideMilvusException {
   private String expect;
   private String actual;
 
-  public UnsupportedServerVersion(String host, String expect, String actual) {
-    super(false);
-    this.host = host;
+  public UnsupportedServerVersion(String target, String expect, String actual) {
+    super(target);
     this.expect = expect;
     this.actual = actual;
   }
 
   @Override
-  public String getMessage() {
-    return String.format("%s: Milvus client %s is expected to work with Milvus server %s, but the version of the connected server is %s",
-        host, MilvusClient.clientVersion, expect, actual);
+  public String getErrorMessage() {
+    return String.format("Milvus client %s is expected to work with Milvus server %s, but the version of the connected server is %s",
+        MilvusClient.clientVersion, expect, actual);
   }
 }

File diff suppressed because it is too large
+ 260 - 526
src/test/java/io/milvus/client/MilvusGrpcClientTest.java


+ 0 - 0
src/main/resources/log4j2.xml → src/test/resources/log4j2-test.xml


Some files were not shown because too many files changed in this diff