Browse Source

Merge pull request #30 from milvus-io/branch-0.1.0

Release first version
Jin Hai 5 years ago
parent
commit
42ee5672c3
35 changed files with 4083 additions and 1 deletions
  1. 4 0
      .gitignore
  2. 24 0
      CHANGELOG.md
  3. 42 1
      README.md
  4. 2 0
      examples/examples.iml
  5. 53 0
      examples/pom.xml
  6. 152 0
      examples/src/main/java/MilvusClientExample.java
  7. 75 0
      milvus-sdk-java.iml
  8. 265 0
      pom.xml
  9. 74 0
      src/main/java/io/milvus/client/CommandParam.java
  10. 77 0
      src/main/java/io/milvus/client/ConnectParam.java
  11. 96 0
      src/main/java/io/milvus/client/CreateIndexParam.java
  12. 54 0
      src/main/java/io/milvus/client/DateRange.java
  13. 94 0
      src/main/java/io/milvus/client/DeleteByRangeParam.java
  14. 54 0
      src/main/java/io/milvus/client/DescribeIndexResponse.java
  15. 55 0
      src/main/java/io/milvus/client/DescribeTableResponse.java
  16. 46 0
      src/main/java/io/milvus/client/GetTableRowCountResponse.java
  17. 44 0
      src/main/java/io/milvus/client/HasTableResponse.java
  18. 77 0
      src/main/java/io/milvus/client/Index.java
  19. 49 0
      src/main/java/io/milvus/client/IndexType.java
  20. 101 0
      src/main/java/io/milvus/client/InsertParam.java
  21. 47 0
      src/main/java/io/milvus/client/InsertResponse.java
  22. 45 0
      src/main/java/io/milvus/client/MetricType.java
  23. 368 0
      src/main/java/io/milvus/client/MilvusClient.java
  24. 804 0
      src/main/java/io/milvus/client/MilvusGrpcClient.java
  25. 113 0
      src/main/java/io/milvus/client/Response.java
  26. 81 0
      src/main/java/io/milvus/client/SearchInFilesParam.java
  27. 140 0
      src/main/java/io/milvus/client/SearchParam.java
  28. 109 0
      src/main/java/io/milvus/client/SearchResponse.java
  29. 48 0
      src/main/java/io/milvus/client/ShowTablesResponse.java
  30. 78 0
      src/main/java/io/milvus/client/TableParam.java
  31. 106 0
      src/main/java/io/milvus/client/TableSchema.java
  32. 77 0
      src/main/java/io/milvus/client/TableSchemaParam.java
  33. 327 0
      src/main/proto/milvus.proto
  34. 40 0
      src/main/proto/status.proto
  35. 262 0
      src/test/java/io/milvus/client/MilvusGrpcClientTest.java

+ 4 - 0
.gitignore

@@ -21,3 +21,7 @@
 
 
 # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
 # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
 hs_err_pid*
 hs_err_pid*
+
+.idea/
+target/
+

+ 24 - 0
CHANGELOG.md

@@ -0,0 +1,24 @@
+### Bug
+---
+    
+### Improvement
+---
+- \#3: Force channel to request connection in connect()  and some code cleanup
+- \#6: Update pom & fix deleteByRange error message & update unittest
+- \#8: change default timeout to 24 hour
+- \#9: Add more getters in SearchResponse & add normalize method in unittest
+- \#10: fix connected() & add port range check & add @nonnull annotation & set maxInboundMessageSize
+- \#17: change IndexParam in DescribeIndexResponse to Index
+- \#27: change proto package to io.milvus.grpc
+    
+### New Feature
+---
+- \#16: add IVF_SQ8_H index type
+
+### Task
+---
+- \#1: First implementation
+- \#21: Add javadoc
+- \#23: Format code with Google-java-style and add Apache 2.0 license header
+- \#28: add examples
+- \#29: add README

+ 42 - 1
README.md

@@ -1 +1,42 @@
-# milvus-sdk-java
+# milvus-sdk-java
+
+[![Maven Central](https://img.shields.io/maven-central/v/io.milvus/milvus-sdk-java.svg)](https://search.maven.org/artifact/io.milvus/milvus-sdk-java/)
+
+Java SDK for Milvus distributed high-performance vector search engine. 
+If you want to contribute to this repo, please read our [contribution guidelines]().
+
+## Getting started
+
+### Dependency 
+
+Apache Maven
+```xml
+<dependency>
+    <groupId>io.milvus</groupId>
+    <artifactId>milvus-sdk-java</artifactId>
+    <version>0.1.1</version>
+</dependency>
+```
+
+Gradle/Grails 
+
+`compile 'io.milvus:milvus-sdk-java:0.1.0'`
+
+###Examples
+
+Please refer to [examples](https://github.com/milvus-io/milvus-sdk-java/tree/master/examples) folder
+
+###Documentation
+
+- [Javadoc](https://milvus-io.github.io/milvus-sdk-java/javadoc/index.html)
+- [Milvus doc](https://milvus.io/docs/en/userguide/install_milvus/)
+
+###Additional information
+
+- The Java source code is formatted using [google-java-format](https://github.com/google/google-java-format).
+
+
+
+
+
+

+ 2 - 0
examples/examples.iml

@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4" />

+ 53 - 0
examples/pom.xml

@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>io.milvus</groupId>
+    <artifactId>milvus-sdk-java-examples</artifactId>
+    <version>0.1.1</version>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>8</source>
+                    <target>8</target>
+                </configuration>
+                <version>3.8.1</version>
+            </plugin>
+        </plugins>
+    </build>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>io.milvus</groupId>
+            <artifactId>milvus-sdk-java</artifactId>
+            <version>0.1.1</version>
+        </dependency>
+    </dependencies>
+
+</project>

+ 152 - 0
examples/src/main/java/MilvusClientExample.java

@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+import io.milvus.client.*;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+public class MilvusClientExample {
+
+  // Helper function that normalizes a vector if you are using IP (Inner product) as your metric
+  // type
+  static List<Float> normalize(List<Float> vector) {
+    float squareSum = vector.stream().map(x -> x * x).reduce((float) 0, Float::sum);
+    final float norm = (float) Math.sqrt(squareSum);
+    vector = vector.stream().map(x -> x / norm).collect(Collectors.toList());
+    return vector;
+  }
+
+  public static void main(String[] args) throws InterruptedException {
+
+    final String host = "localhost";
+    final String port = "19530";
+
+    // Create Milvus client
+    MilvusClient client = new MilvusGrpcClient();
+
+    // Connect to Milvus server
+    ConnectParam connectParam = new ConnectParam.Builder().withHost(host).withPort(port).build();
+    Response connectResponse = client.connect(connectParam);
+    System.out.println(connectResponse);
+
+    // Check whether we are connected
+    boolean connected = client.connected();
+    System.out.println("Connected = " + connected);
+
+    // Create a table with the following table schema
+    final String tableName = "example";
+    final long dimension = 128;
+    final long indexFileSize = 1024;
+    final MetricType metricType = MetricType.IP;
+    TableSchema tableSchema =
+        new TableSchema.Builder(tableName, dimension)
+            .withIndexFileSize(indexFileSize)
+            .withMetricType(metricType)
+            .build();
+    TableSchemaParam tableSchemaParam =
+        new TableSchemaParam.Builder(tableSchema).withTimeout(10).build();
+    Response createTableResponse = client.createTable(tableSchemaParam);
+    System.out.println(createTableResponse);
+
+    // Check whether the table exists
+    TableParam hasTableParam = new TableParam.Builder(tableName).withTimeout(1).build();
+    HasTableResponse hasTableResponse = client.hasTable(hasTableParam);
+    System.out.println(hasTableResponse);
+
+    // Describe the table
+    TableParam describeTableParam = new TableParam.Builder(tableName).withTimeout(1).build();
+    DescribeTableResponse describeTableResponse = client.describeTable(describeTableParam);
+    System.out.println(describeTableResponse);
+
+    // Insert randomly generated vectors to table
+    final int vectorCount = 1024;
+    Random random = new Random();
+    List<List<Float>> vectors = new ArrayList<>();
+    for (int i = 0; i < vectorCount; ++i) {
+      List<Float> vector = new ArrayList<>();
+      for (int j = 0; j < dimension; ++j) {
+        vector.add(random.nextFloat());
+      }
+      vector = normalize(vector);
+      vectors.add(vector);
+    }
+    InsertParam insertParam = new InsertParam.Builder(tableName, vectors).withTimeout(10).build();
+    InsertResponse insertResponse = client.insert(insertParam);
+    System.out.println(insertResponse);
+    // Insert returns a list of vector ids that you will be using (if you did not supply them
+    // yourself) to reference the vectors you just inserted
+    List<Long> vectorIds = insertResponse.getVectorIds();
+
+    // Sleep for 1 second
+    TimeUnit.SECONDS.sleep(1);
+
+    // Get current row count of table
+    TableParam getTableRowCountParam = new TableParam.Builder(tableName).withTimeout(1).build();
+    GetTableRowCountResponse getTableRowCountResponse =
+        client.getTableRowCount(getTableRowCountParam);
+    System.out.println(getTableRowCountResponse);
+
+    // Create index for the table
+    final IndexType indexType = IndexType.IVF_SQ8;
+    Index index = new Index.Builder().withIndexType(IndexType.IVF_SQ8).build();
+    CreateIndexParam createIndexParam =
+        new CreateIndexParam.Builder(tableName).withIndex(index).withTimeout(10).build();
+    Response createIndexResponse = client.createIndex(createIndexParam);
+    System.out.println(createIndexResponse);
+
+    // Describe the index for your table
+    TableParam describeIndexParam = new TableParam.Builder(tableName).withTimeout(1).build();
+    DescribeIndexResponse describeIndexResponse = client.describeIndex(describeIndexParam);
+    System.out.println(describeIndexResponse);
+
+    // Search vectors
+    final int searchSize = 5;
+    // Searching the first 5 vectors of the vectors we just inserted
+    List<List<Float>> vectorsToSearch = vectors.subList(0, searchSize);
+    final long topK = 10;
+    SearchParam searchParam =
+        new SearchParam.Builder(tableName, vectorsToSearch).withTopK(topK).withTimeout(10).build();
+    SearchResponse searchResponse = client.search(searchParam);
+    System.out.println(searchResponse);
+    List<List<SearchResponse.QueryResult>> queryResultsList = searchResponse.getQueryResultsList();
+    final double epsilon = 0.001;
+    for (int i = 0; i < searchSize; i++) {
+      // Since we are searching for vector that is already present in the table,
+      // the first result vector should be itself and the distance should be less than epsilon
+      assert queryResultsList.get(i).get(0).getVectorId() == vectorIds.get(0);
+      assert queryResultsList.get(i).get(0).getDistance() < epsilon;
+    }
+
+    // Drop index for the table
+    TableParam dropIndexParam = new TableParam.Builder(tableName).withTimeout(1).build();
+    Response dropIndexResponse = client.dropIndex(dropIndexParam);
+    System.out.println(dropIndexResponse);
+
+    // Drop table
+    TableParam dropTableParam = new TableParam.Builder(tableName).withTimeout(1).build();
+    Response dropTableResponse = client.dropTable(dropTableParam);
+    System.out.println(dropTableResponse);
+
+    // Disconnect from Milvus server
+    Response disconnectResponse = client.disconnect();
+    System.out.println(disconnectResponse);
+  }
+}

+ 75 - 0
milvus-sdk-java.iml

@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
+    <output url="file://$MODULE_DIR$/target/classes" />
+    <output-test url="file://$MODULE_DIR$/target/test-classes" />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/target/generated-sources/protobuf/grpc-java" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/target/generated-sources/protobuf/java" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/proto" type="java-resource" />
+      <excludeFolder url="file://$MODULE_DIR$/target" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="library" name="Bundled Protobuf Distribution" level="application" />
+    <orderEntry type="library" name="Maven: org.apache.maven.plugins:maven-gpg-plugin:1.6" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.maven:maven-plugin-api:2.2.1" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.maven:maven-project:2.2.1" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.maven:maven-settings:2.2.1" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.maven:maven-profile:2.2.1" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.maven:maven-artifact-manager:2.2.1" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.maven.wagon:wagon-provider-api:1.0-beta-6" level="project" />
+    <orderEntry type="library" name="Maven: backport-util-concurrent:backport-util-concurrent:3.1" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.maven:maven-plugin-registry:2.2.1" level="project" />
+    <orderEntry type="library" name="Maven: org.codehaus.plexus:plexus-interpolation:1.11" level="project" />
+    <orderEntry type="library" name="Maven: org.codehaus.plexus:plexus-container-default:1.0-alpha-9-stable-1" level="project" />
+    <orderEntry type="library" name="Maven: classworlds:classworlds:1.1-alpha-2" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.maven:maven-artifact:2.2.1" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.maven:maven-repository-metadata:2.2.1" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.maven:maven-model:2.2.1" level="project" />
+    <orderEntry type="library" name="Maven: org.codehaus.plexus:plexus-utils:3.0.20" level="project" />
+    <orderEntry type="library" name="Maven: org.sonatype.plexus:plexus-sec-dispatcher:1.4" level="project" />
+    <orderEntry type="library" name="Maven: org.sonatype.plexus:plexus-cipher:1.4" level="project" />
+    <orderEntry type="library" name="Maven: com.google.googlejavaformat:google-java-format:1.7" level="project" />
+    <orderEntry type="library" name="Maven: com.google.guava:guava:27.0.1-jre" level="project" />
+    <orderEntry type="library" name="Maven: com.google.guava:failureaccess:1.0.1" level="project" />
+    <orderEntry type="library" name="Maven: com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava" level="project" />
+    <orderEntry type="library" name="Maven: com.google.code.findbugs:jsr305:3.0.2" level="project" />
+    <orderEntry type="library" name="Maven: org.checkerframework:checker-qual:2.5.2" level="project" />
+    <orderEntry type="library" name="Maven: com.google.j2objc:j2objc-annotations:1.1" level="project" />
+    <orderEntry type="library" name="Maven: org.codehaus.mojo:animal-sniffer-annotations:1.17" level="project" />
+    <orderEntry type="library" name="Maven: com.google.errorprone:javac-shaded:9+181-r4173-1" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Maven: io.grpc:grpc-netty-shaded:1.24.0" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Maven: io.grpc:grpc-core:1.24.0" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Maven: com.google.android:annotations:4.1.1.4" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Maven: io.perfmark:perfmark-api:0.17.0" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Maven: io.opencensus:opencensus-api:0.21.0" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Maven: io.opencensus:opencensus-contrib-grpc-metrics:0.21.0" level="project" />
+    <orderEntry type="library" name="Maven: io.grpc:grpc-protobuf:1.24.0" level="project" />
+    <orderEntry type="library" name="Maven: io.grpc:grpc-api:1.24.0" level="project" />
+    <orderEntry type="library" name="Maven: io.grpc:grpc-context:1.24.0" level="project" />
+    <orderEntry type="library" name="Maven: com.google.protobuf:protobuf-java:3.9.0" level="project" />
+    <orderEntry type="library" name="Maven: com.google.api.grpc:proto-google-common-protos:1.12.0" level="project" />
+    <orderEntry type="library" name="Maven: io.grpc:grpc-protobuf-lite:1.24.0" level="project" />
+    <orderEntry type="library" name="Maven: io.grpc:grpc-stub:1.24.0" level="project" />
+    <orderEntry type="library" scope="PROVIDED" name="Maven: javax.annotation:javax.annotation-api:1.2" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: io.grpc:grpc-testing:1.24.0" level="project" />
+    <orderEntry type="library" name="Maven: junit:junit:4.12" level="project" />
+    <orderEntry type="library" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" />
+    <orderEntry type="library" name="Maven: com.google.protobuf:protobuf-java-util:3.10.0" level="project" />
+    <orderEntry type="library" name="Maven: com.google.errorprone:error_prone_annotations:2.3.2" level="project" />
+    <orderEntry type="library" name="Maven: com.google.code.gson:gson:2.8.5" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter:5.5.2" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-api:5.5.2" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.apiguardian:apiguardian-api:1.1.0" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.opentest4j:opentest4j:1.2.0" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.junit.platform:junit-platform-commons:1.5.2" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-params:5.5.2" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.junit.jupiter:junit-jupiter-engine:5.5.2" level="project" />
+    <orderEntry type="library" scope="TEST" name="Maven: org.junit.platform:junit-platform-engine:1.5.2" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.commons:commons-text:1.6" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.8.1" level="project" />
+  </component>
+</module>

+ 265 - 0
pom.xml

@@ -0,0 +1,265 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>io.milvus</groupId>
+    <artifactId>milvus-sdk-java</artifactId>
+    <version>0.1.1</version>
+    <packaging>jar</packaging>
+
+    <name>io.milvus:milvus-sdk-java</name>
+    <description>Java SDK for Milvus distributed high-performance vector search engine.</description>
+    <url>https://github.com/milvus-io/milvus-sdk-java</url>
+
+    <licenses>
+        <license>
+            <name>Apache License, Version 2.0</name>
+            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+            <distribution>repo</distribution>
+        </license>
+    </licenses>
+
+    <developers>
+        <developer>
+            <name>Zhiru Zhu</name>
+            <email>zhiru.zhu@zilliz.com</email>
+            <organization>Milvus</organization>
+            <organizationUrl>http://www.milvus.io</organizationUrl>
+        </developer>
+    </developers>
+
+    <scm>
+        <connection>scm:git:https://github.com/milvus-io/milvus-sdk-java.git</connection>
+        <developerConnection>scm:git:https://github.com/milvus-io/milvus-sdk-java.git</developerConnection>
+        <url>https://github.com/milvus-io/milvus-sdk-java</url>
+    </scm>
+
+    <distributionManagement>
+        <snapshotRepository>
+            <id>ossrh</id>
+            <url>https://oss.sonatype.org/content/repositories/snapshots</url>
+        </snapshotRepository>
+    </distributionManagement>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <grpc.version>1.24.0</grpc.version>
+        <protobuf.version>3.10.0</protobuf.version>
+        <protoc.version>3.10.0</protoc.version>
+        <maven.compiler.source>1.8</maven.compiler.source>
+        <maven.compiler.target>1.8</maven.compiler.target>
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>io.grpc</groupId>
+                <artifactId>grpc-bom</artifactId>
+                <version>${grpc.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-gpg-plugin</artifactId>
+            <version>1.6</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.googlejavaformat</groupId>
+            <artifactId>google-java-format</artifactId>
+            <version>1.7</version>
+        </dependency>
+        <dependency>
+            <groupId>io.grpc</groupId>
+            <artifactId>grpc-netty-shaded</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.grpc</groupId>
+            <artifactId>grpc-protobuf</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.grpc</groupId>
+            <artifactId>grpc-stub</artifactId>
+        </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>io.grpc</groupId>
+            <artifactId>grpc-testing</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.google.protobuf</groupId>
+            <artifactId>protobuf-java-util</artifactId>
+            <version>${protobuf.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter</artifactId>
+            <version>5.5.2</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-text</artifactId>
+            <version>1.6</version>
+        </dependency>
+    </dependencies>
+
+    <profiles>
+        <profile>
+            <id>release</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-source-plugin</artifactId>
+                        <version>3.1.0</version>
+                        <executions>
+                            <execution>
+                                <id>attach-sources</id>
+                                <goals>
+                                    <goal>jar-no-fork</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-javadoc-plugin</artifactId>
+                        <version>3.1.1</version>
+                        <executions>
+                            <execution>
+                                <id>attach-javadocs</id>
+                                <goals>
+                                    <goal>jar</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-gpg-plugin</artifactId>
+                        <version>1.6</version>
+                        <executions>
+                            <execution>
+                                <id>sign-artifacts</id>
+                                <phase>verify</phase>
+                                <goals>
+                                    <goal>sign</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+
+    <build>
+        <extensions>
+            <extension>
+                <groupId>kr.motd.maven</groupId>
+                <artifactId>os-maven-plugin</artifactId>
+                <version>1.6.2</version>
+            </extension>
+        </extensions>
+        <plugins>
+            <plugin>
+                <groupId>org.sonatype.plugins</groupId>
+                <artifactId>nexus-staging-maven-plugin</artifactId>
+                <version>1.6.8</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <serverId>ossrh</serverId>
+                    <nexusUrl>https://oss.sonatype.org/</nexusUrl>
+                    <autoReleaseAfterClose>true</autoReleaseAfterClose>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-release-plugin</artifactId>
+                <version>2.5.3</version>
+                <configuration>
+                    <autoVersionSubmodules>true</autoVersionSubmodules>
+                    <useReleaseProfile>false</useReleaseProfile>
+                    <releaseProfiles>release</releaseProfiles>
+                    <goals>deploy</goals>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.xolstice.maven.plugins</groupId>
+                <artifactId>protobuf-maven-plugin</artifactId>
+                <version>0.6.1</version>
+                <configuration>
+                    <protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}
+                    </protocArtifact>
+                    <pluginId>grpc-java</pluginId>
+                    <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}
+                    </pluginArtifact>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>compile</goal>
+                            <goal>compile-custom</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-enforcer-plugin</artifactId>
+                <version>3.0.0-M2</version>
+                <executions>
+                    <execution>
+                        <id>enforce</id>
+                        <configuration>
+                            <rules>
+                                <requireUpperBoundDeps>
+                                    <excludes>
+                                        <exclude>com.google.guava:guava</exclude>
+                                        <exclude>com.google.errorprone:error_prone_annotations</exclude>
+                                        <exclude>com.google.protobuf:protobuf-java</exclude>
+                                    </excludes>
+                                </requireUpperBoundDeps>
+                            </rules>
+                        </configuration>
+                        <goals>
+                            <goal>enforce</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 74 - 0
src/main/java/io/milvus/client/CommandParam.java

@@ -0,0 +1,74 @@
+/*
+ * 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.Nonnull;
+
+/** Contains parameters for <code>command</code> */
+class CommandParam {
+  private final String command;
+  private final long timeout;
+
+  private CommandParam(@Nonnull Builder builder) {
+    this.command = builder.command;
+    this.timeout = builder.timeout;
+  }
+
+  String getCommand() {
+    return command;
+  }
+
+  long getTimeout() {
+    return timeout;
+  }
+
+  @Override
+  public String toString() {
+    return "CommandParam {" + "command='" + command + '\'' + ", timeout=" + timeout + '}';
+  }
+
+  /** Builder for <code>CommandParam</code> */
+  public static class Builder {
+    // Required parameters
+    private final String command;
+
+    // Optional parameters - initialized to default values
+    private long timeout = 86400;
+
+    /** @param command a string command */
+    public Builder(@Nonnull String command) {
+      this.command = command;
+    }
+
+    /**
+     * Optional. Sets the deadline from when the client RPC is set to when the response is picked up
+     * by the client. Default to 86400s (1 day).
+     *
+     * @param timeout in seconds
+     * @return <code>Builder</code>
+     */
+    public Builder withTimeout(long timeout) {
+      this.timeout = timeout;
+      return this;
+    }
+
+    public CommandParam build() {
+      return new CommandParam(this);
+    }
+  }
+}

+ 77 - 0
src/main/java/io/milvus/client/ConnectParam.java

@@ -0,0 +1,77 @@
+/*
+ * 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.Nonnull;
+
+/** Contains parameters for connecting to Milvus server */
+public class ConnectParam {
+  private final String host;
+  private final String port;
+
+  private ConnectParam(@Nonnull Builder builder) {
+    this.host = builder.host;
+    this.port = builder.port;
+  }
+
+  public String getHost() {
+    return host;
+  }
+
+  public String getPort() {
+    return port;
+  }
+
+  @Override
+  public String toString() {
+    return "ConnectParam {" + "host='" + host + '\'' + ", port='" + port + '\'' + '}';
+  }
+
+  /** Builder for <code>ConnectParam</code> */
+  public static class Builder {
+    // Optional parameters - initialized to default values
+    private String host = "127.0.0.1";
+    private String port = "19530";
+
+    /**
+     * Optional. Default to "127.0.0.1".
+     *
+     * @param host server host
+     * @return <code>Builder</code>
+     */
+    public Builder withHost(@Nonnull String host) {
+      this.host = host;
+      return this;
+    }
+
+    /**
+     * Optional. Default to "19530".
+     *
+     * @param port server port
+     * @return <code>Builder</code>
+     */
+    public Builder withPort(@Nonnull String port) {
+      this.port = port;
+      return this;
+    }
+
+    public ConnectParam build() {
+      return new ConnectParam(this);
+    }
+  }
+}

+ 96 - 0
src/main/java/io/milvus/client/CreateIndexParam.java

@@ -0,0 +1,96 @@
+/*
+ * 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.Nonnull;
+
+/** Contains parameters for <code>createIndex</code> */
+public class CreateIndexParam {
+
+  private final String tableName;
+  private final Index index;
+  private final long timeout;
+
+  private CreateIndexParam(@Nonnull Builder builder) {
+    this.tableName = builder.tableName;
+    this.index = builder.index;
+    this.timeout = builder.timeout;
+  }
+
+  public String getTableName() {
+    return tableName;
+  }
+
+  public Index getIndex() {
+    return index;
+  }
+
+  public long getTimeout() {
+    return timeout;
+  }
+
+  @Override
+  public String toString() {
+    return String.format(
+        "IndexParam = {tableName = %s, index = {indexType = %s, nList = %d}, timeout = %d}",
+        tableName, index.getIndexType().name(), index.getNList(), timeout);
+  }
+
+  /** Builder for <code>CreateIndexParam</code> */
+  public static class Builder {
+    // Required parameters
+    private final String tableName;
+
+    // Optional parameters - initialized to default values
+    private Index index;
+    private long timeout = 86400;
+
+    /** @param tableName table to create index on */
+    public Builder(@Nonnull String tableName) {
+      this.tableName = tableName;
+    }
+
+    /**
+     * Optional. Default to Index{indexType = IndexType.FLAT, nList = 16384}
+     *
+     * @param index a <code>Index</code> object
+     * @return <code>Builder</code>
+     * @see Index
+     */
+    public Builder withIndex(Index index) {
+      this.index = index;
+      return this;
+    }
+
+    /**
+     * Optional. Sets the deadline from when the client RPC is set to when the response is picked up
+     * by the client. Default to 86400s (1 day).
+     *
+     * @param timeout in seconds
+     * @return <code>Builder</code>
+     */
+    public Builder withTimeout(long timeout) {
+      this.timeout = timeout;
+      return this;
+    }
+
+    public CreateIndexParam build() {
+      return new CreateIndexParam(this);
+    }
+  }
+}

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

@@ -0,0 +1,54 @@
+/*
+ * 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.Nonnull;
+import java.util.Date;
+
+/** Represents a date range [<code>startDate</code>, <code>endDate</code>) */
+public class DateRange {
+  private Date startDate;
+  private Date endDate;
+
+  /** @see Date */
+  public DateRange(@Nonnull Date startDate, @Nonnull Date endDate) {
+    this.startDate = startDate;
+    this.endDate = endDate;
+  }
+
+  public Date getStartDate() {
+    return startDate;
+  }
+
+  public void setStartDate(@Nonnull Date startDate) {
+    this.startDate = startDate;
+  }
+
+  public Date getEndDate() {
+    return endDate;
+  }
+
+  public void setEndDate(@Nonnull Date endDate) {
+    this.endDate = endDate;
+  }
+
+  @Override
+  public String toString() {
+    return "{startDate=" + startDate + ", endDate=" + endDate + '}';
+  }
+}

+ 94 - 0
src/main/java/io/milvus/client/DeleteByRangeParam.java

@@ -0,0 +1,94 @@
+/*
+ * 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.Nonnull;
+
+/** Contains parameters for <code>deleteByRange</code> */
+public class DeleteByRangeParam {
+  private final DateRange dateRange;
+  private final String tableName;
+  private final long timeout;
+
+  private DeleteByRangeParam(@Nonnull Builder builder) {
+    this.dateRange = builder.dateRange;
+    this.tableName = builder.tableName;
+    this.timeout = builder.timeout;
+  }
+
+  public DateRange getDateRange() {
+    return dateRange;
+  }
+
+  public String getTableName() {
+    return tableName;
+  }
+
+  public long getTimeout() {
+    return timeout;
+  }
+
+  @Override
+  public String toString() {
+    return "DeleteByRangeParam {"
+        + "dateRange = "
+        + dateRange.toString()
+        + ", tableName = '"
+        + tableName
+        + '\''
+        + ", timeout = "
+        + timeout
+        + '}';
+  }
+
+  /** Builder for <code>DeleteByRangeParam</code> */
+  public static final class Builder {
+    // Required parameters
+    private final DateRange dateRange;
+    private final String tableName;
+
+    // Optional parameters - initialized to default values
+    private long timeout = 86400;
+
+    /**
+     * @param dateRange a <code>DateRange</code> object
+     * @param tableName table to delete from
+     * @see DateRange
+     */
+    public Builder(@Nonnull DateRange dateRange, @Nonnull String tableName) {
+      this.dateRange = dateRange;
+      this.tableName = tableName;
+    }
+
+    /**
+     * Optional. Sets the deadline from when the client RPC is set to when the response is picked up
+     * by the client. Default to 86400s (1 day).
+     *
+     * @param timeout in seconds
+     * @return <code>Builder</code>
+     */
+    public Builder withTimeout(long timeout) {
+      this.timeout = timeout;
+      return this;
+    }
+
+    public DeleteByRangeParam build() {
+      return new DeleteByRangeParam(this);
+    }
+  }
+}

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

@@ -0,0 +1,54 @@
+/*
+ * 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>index</code> for <code>describeIndex</code>
+ */
+public class DescribeIndexResponse {
+  private final Response response;
+  private final Index index;
+
+  public DescribeIndexResponse(Response response, @Nullable Index index) {
+    this.response = response;
+    this.index = index;
+  }
+
+  /**
+   * @return an <code>Optional</code> object which may or may not contain an <code>Index</code>
+   *     object
+   * @see Optional
+   */
+  public Optional<Index> getIndex() {
+    return Optional.ofNullable(index);
+  }
+
+  public Response getResponse() {
+    return response;
+  }
+
+  @Override
+  public String toString() {
+    return String.format(
+        "DescribeIndexResponse {%s, %s}",
+        response.toString(), index == null ? "Index = Null" : index.toString());
+  }
+}

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

@@ -0,0 +1,55 @@
+/*
+ * 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>tableSchema</code> for <code>describeTable
+ * </code>
+ */
+public class DescribeTableResponse {
+  private final Response response;
+  private final TableSchema tableSchema;
+
+  public DescribeTableResponse(Response response, @Nullable TableSchema tableSchema) {
+    this.response = response;
+    this.tableSchema = tableSchema;
+  }
+
+  /**
+   * @return an <code>Optional</code> object which may or may not contain a <code>TableSchema</code>
+   *     object
+   * @see Optional
+   */
+  public Optional<TableSchema> getTableSchema() {
+    return Optional.ofNullable(tableSchema);
+  }
+
+  public Response getResponse() {
+    return response;
+  }
+
+  @Override
+  public String toString() {
+    return String.format(
+        "DescribeTableResponse {%s, %s}",
+        response.toString(), tableSchema == null ? "Table schema = None" : tableSchema.toString());
+  }
+}

+ 46 - 0
src/main/java/io/milvus/client/GetTableRowCountResponse.java

@@ -0,0 +1,46 @@
+/*
+ * 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>tableRowCount</code> for <code>
+ * getTableRowCount</code>
+ */
+public class GetTableRowCountResponse {
+  private final Response response;
+  private final long tableRowCount;
+
+  public GetTableRowCountResponse(Response response, long tableRowCount) {
+    this.response = response;
+    this.tableRowCount = tableRowCount;
+  }
+
+  public long getTableRowCount() {
+    return tableRowCount;
+  }
+
+  public Response getResponse() {
+    return response;
+  }
+
+  @Override
+  public String toString() {
+    return String.format(
+        "CountTableResponse {%s, table row count = %d}", response.toString(), tableRowCount);
+  }
+}

+ 44 - 0
src/main/java/io/milvus/client/HasTableResponse.java

@@ -0,0 +1,44 @@
+/*
+ * 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>hasTable</code> for <code>hasTable</code>
+ */
+public class HasTableResponse {
+  private final Response response;
+  private final boolean hasTable;
+
+  public HasTableResponse(Response response, boolean hasTable) {
+    this.response = response;
+    this.hasTable = hasTable;
+  }
+
+  public boolean hasTable() {
+    return hasTable;
+  }
+
+  public Response getResponse() {
+    return response;
+  }
+
+  @Override
+  public String toString() {
+    return String.format("HasTableResponse {%s, has table = %s}", response.toString(), hasTable);
+  }
+}

+ 77 - 0
src/main/java/io/milvus/client/Index.java

@@ -0,0 +1,77 @@
+/*
+ * 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.Nonnull;
+
+/** Represents an index containing <code>indexType</code> and <code>nList</code> */
+public class Index {
+  private final IndexType indexType;
+  private final int nList;
+
+  private Index(@Nonnull Builder builder) {
+    this.indexType = builder.indexType;
+    this.nList = builder.nList;
+  }
+
+  public IndexType getIndexType() {
+    return indexType;
+  }
+
+  public int getNList() {
+    return nList;
+  }
+
+  @Override
+  public String toString() {
+    return "Index {" + "indexType=" + indexType + ", nList=" + nList + '}';
+  }
+
+  /** Builder for <code>Index</code> */
+  public static class Builder {
+    // Optional parameters - initialized to default values
+    private IndexType indexType = IndexType.FLAT;
+    private int nList = 16384;
+
+    /**
+     * Optional. Default to <code>IndexType.FLAT</code>
+     *
+     * @param indexType a <code>IndexType</code> object
+     * @return <code>Builder</code>
+     */
+    public Builder withIndexType(@Nonnull IndexType indexType) {
+      this.indexType = indexType;
+      return this;
+    }
+
+    /**
+     * Optional. Default to 16384.
+     *
+     * @param nList nList of the index
+     * @return <code>Builder</code>
+     */
+    public Builder withNList(int nList) {
+      this.nList = nList;
+      return this;
+    }
+
+    public Index build() {
+      return new Index(this);
+    }
+  }
+}

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

@@ -0,0 +1,49 @@
+/*
+ * 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 available index types */
+public enum IndexType {
+  INVALID(0),
+  FLAT(1),
+  IVFLAT(2),
+  IVF_SQ8(3),
+  MIX_NSG(4),
+  IVF_SQ8_H(5),
+
+  UNKNOWN(-1);
+
+  private final int val;
+
+  IndexType(int val) {
+    this.val = val;
+  }
+
+  public static IndexType valueOf(int val) {
+    Optional<IndexType> search =
+        Arrays.stream(values()).filter(indexType -> indexType.val == val).findFirst();
+    return search.orElse(UNKNOWN);
+  }
+
+  public int getVal() {
+    return val;
+  }
+}

+ 101 - 0
src/main/java/io/milvus/client/InsertParam.java

@@ -0,0 +1,101 @@
+/*
+ * 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.Nonnull;
+import java.util.ArrayList;
+import java.util.List;
+
+/** Contains parameters for <code>insert</code> */
+public class InsertParam {
+  private final String tableName;
+  private final List<List<Float>> vectors;
+  private final List<Long> vectorIds;
+  private final long timeout;
+
+  private InsertParam(@Nonnull Builder builder) {
+    this.tableName = builder.tableName;
+    this.vectors = builder.vectors;
+    this.vectorIds = builder.vectorIds;
+    this.timeout = builder.timeout;
+  }
+
+  public String getTableName() {
+    return tableName;
+  }
+
+  public List<List<Float>> getVectors() {
+    return vectors;
+  }
+
+  public List<Long> getVectorIds() {
+    return vectorIds;
+  }
+
+  public long getTimeout() {
+    return timeout;
+  }
+
+  /** Builder for <code>InsertParam</code> */
+  public static class Builder {
+    // Required parameters
+    private final String tableName;
+    private final List<List<Float>> vectors;
+
+    // Optional parameters - initialized to default values
+    private List<Long> vectorIds = new ArrayList<>();
+    private long timeout = 86400;
+
+    /**
+     * @param tableName table to insert vectors to
+     * @param vectors a <code>List</code> of vectors to insert. Each inner <code>List</code>
+     *     represents a vector.
+     */
+    public Builder(@Nonnull String tableName, @Nonnull List<List<Float>> vectors) {
+      this.tableName = tableName;
+      this.vectors = vectors;
+    }
+
+    /**
+     * Optional. Default to an empty <code>ArrayList</code>
+     *
+     * @param vectorIds a <code>List</code> of ids associated with the vectors to insert
+     * @return <code>Builder</code>
+     */
+    public Builder withVectorIds(@Nonnull List<Long> vectorIds) {
+      this.vectorIds = vectorIds;
+      return this;
+    }
+
+    /**
+     * Optional. Sets the deadline from when the client RPC is set to when the response is picked up
+     * by the client. Default to 86400s (1 day).
+     *
+     * @param timeout in seconds
+     * @return <code>Builder</code>
+     */
+    public Builder withTimeout(long timeout) {
+      this.timeout = timeout;
+      return this;
+    }
+
+    public InsertParam build() {
+      return new InsertParam(this);
+    }
+  }
+}

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

@@ -0,0 +1,47 @@
+/*
+ * 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>vectorIds</code> for <code>insert</code>
+ */
+public class InsertResponse {
+  private final Response response;
+  private final List<Long> vectorIds;
+
+  public InsertResponse(Response response, List<Long> vectorIds) {
+    this.response = response;
+    this.vectorIds = vectorIds;
+  }
+
+  public List<Long> getVectorIds() {
+    return vectorIds;
+  }
+
+  public Response getResponse() {
+    return response;
+  }
+
+  @Override
+  public String toString() {
+    return String.format(
+        "InsertResponse {%s, returned %d vector ids}", response.toString(), this.vectorIds.size());
+  }
+}

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

@@ -0,0 +1,45 @@
+/*
+ * 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 available metric types */
+public enum MetricType {
+  L2(1),
+  IP(2),
+
+  UNKNOWN(-1);
+
+  private final int val;
+
+  MetricType(int val) {
+    this.val = val;
+  }
+
+  public static MetricType valueOf(int val) {
+    Optional<MetricType> search =
+        Arrays.stream(values()).filter(metricType -> metricType.val == val).findFirst();
+    return search.orElse(UNKNOWN);
+  }
+
+  public int getVal() {
+    return val;
+  }
+}

+ 368 - 0
src/main/java/io/milvus/client/MilvusClient.java

@@ -0,0 +1,368 @@
+/*
+ * 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;
+
+/** The Milvus Client Interface */
+public interface MilvusClient {
+
+  String clientVersion = "0.1.0";
+
+  /** @return the current Milvus client version */
+  default String clientVersion() {
+    return clientVersion;
+  }
+
+  /**
+   * Connects to Milvus server
+   *
+   * @param connectParam the <code>ConnectParam</code> object
+   *     <pre>
+   * example usage:
+   * <code>
+   * ConnectParam connectParam = new ConnectParam.Builder()
+   *                                             .withHost("localhost")
+   *                                             .withPort("19530")
+   *                                             .build();
+   * </code>
+   * </pre>
+   *
+   * @return <code>Response</code>
+   * @see ConnectParam
+   * @see Response
+   */
+  Response connect(ConnectParam connectParam);
+
+  /** @return <code>true</code> if the client is connected to Milvus server */
+  boolean connected();
+
+  /**
+   * Disconnects from Milvus server
+   *
+   * @return <code>Response</code>
+   * @throws InterruptedException
+   * @see Response
+   */
+  Response disconnect() throws InterruptedException;
+
+  /**
+   * Creates table specified by <code>tableSchemaParam</code>
+   *
+   * @param tableSchemaParam the <code>TableSchemaParam</code> object
+   *     <pre>
+   * example usage:
+   * <code>
+   * TableSchema tableSchema = new TableSchema.Builder(tableName, dimension)
+   *                                          .withIndexFileSize(1024)
+   *                                          .withMetricType(MetricType.IP)
+   *                                          .build();
+   * TableSchemaParam tableSchemaParam = new TableSchemaParam.Builder(tableSchema)
+   *                                                         .withTimeout(timeout)
+   *                                                         .build();
+   * </code>
+   * </pre>
+   *
+   * @return <code>Response</code>
+   * @see TableSchema
+   * @see TableSchemaParam
+   * @see MetricType
+   * @see Response
+   */
+  Response createTable(TableSchemaParam tableSchemaParam);
+
+  /**
+   * Check whether the table specified by <code>tableParam</code> exists
+   *
+   * @param tableParam the <code>TableParam</code> object
+   *     <pre>
+   * example usage:
+   * <code>
+   * TableParam tableParam = new TableParam.Builder(tableName)
+   *                                       .withTimeout(timeout)
+   *                                       .build();
+   * </code>
+   * </pre>
+   *
+   * @return <code>HasTableResponse</code>
+   * @see TableParam
+   * @see HasTableResponse
+   * @see Response
+   */
+  HasTableResponse hasTable(TableParam tableParam);
+
+  /**
+   * Drops the table specified by <code>tableParam</code>
+   *
+   * @param tableParam the <code>TableParam</code> object
+   *     <pre>
+   * example usage:
+   * <code>
+   * TableParam tableParam = new TableParam.Builder(tableName)
+   *                                       .withTimeout(timeout)
+   *                                       .build();
+   * </code>
+   * </pre>
+   *
+   * @return <code>Response</code>
+   * @see TableParam
+   * @see Response
+   */
+  Response dropTable(TableParam tableParam);
+
+  /**
+   * Creates index specified by <code>indexParam</code>
+   *
+   * @param createIndexParam the <code>CreateIndexParam</code> object
+   *     <pre>
+   * example usage:
+   * <code>
+   * Index index = new Index.Builder()
+   *                        .withIndexType(IndexType.IVF_SQ8)
+   *                        .withNList(16384)
+   *                        .build();
+   * CreateIndexParam createIndexParam = new CreateIndexParam.Builder(tableName)
+   *                                                         .withIndex(index)
+   *                                                         .withTimeout(timeout)
+   *                                                         .build();
+   * </code>
+   * </pre>
+   *
+   * @return <code>Response</code>
+   * @see Index
+   * @see CreateIndexParam
+   * @see IndexType
+   * @see Response
+   */
+  Response createIndex(CreateIndexParam createIndexParam);
+
+  /**
+   * Inserts data specified by <code>insertParam</code>
+   *
+   * @param insertParam the <code>InsertParam</code> object
+   *     <pre>
+   * example usage:
+   * <code>
+   * InsertParam insertParam = new InsertParam.Builder(tableName, vectors)
+   *                                          .withVectorIds(vectorIds)
+   *                                          .withTimeout(timeout)
+   *                                          .build();
+   * </code>
+   * </pre>
+   *
+   * @return <code>InsertResponse</code>
+   * @see InsertParam
+   * @see InsertResponse
+   * @see Response
+   */
+  InsertResponse insert(InsertParam insertParam);
+
+  /**
+   * Searches vectors specified by <code>searchParam</code>
+   *
+   * @param searchParam the <code>SearchParam</code> object
+   *     <pre>
+   * example usage:
+   * <code>
+   * SearchParam searchParam = new SearchParam.Builder(tableName, vectorsToSearch)
+   *                                          .withTopK(topK)
+   *                                          .withNProbe(nProbe)
+   *                                          .withDateRanges(dateRanges)
+   *                                          .withTimeout(timeout)
+   *                                          .build();
+   * </code>
+   * </pre>
+   *
+   * @return <code>SearchResponse</code>
+   * @see SearchParam
+   * @see DateRange
+   * @see SearchResponse
+   * @see SearchResponse.QueryResult
+   * @see Response
+   */
+  SearchResponse search(SearchParam searchParam);
+
+  /**
+   * Searches vectors in specific files specified by <code>searchInFilesParam</code>
+   *
+   * @param searchInFilesParam the <code>SearchInFilesParam</code> object
+   *     <pre>
+   * example usage:
+   * <code>
+   * SearchParam searchParam = new SearchParam.Builder(tableName, vectorsToSearch)
+   *                                          .withTopK(topK)
+   *                                          .withNProbe(nProbe)
+   *                                          .withDateRanges(dateRanges)
+   *                                          .build();
+   * SearchInFilesParam searchInFilesParam = new SearchInFilesParam.Builder(fileIds, searchParam)
+   *                                                               .withTimeout(timeout)
+   *                                                               .build();
+   * </code>
+   * </pre>
+   *
+   * @return <code>SearchResponse</code>
+   * @see SearchInFilesParam
+   * @see SearchParam
+   * @see DateRange
+   * @see SearchResponse
+   * @see SearchResponse.QueryResult
+   * @see Response
+   */
+  SearchResponse searchInFiles(SearchInFilesParam searchInFilesParam);
+
+  /**
+   * Describes table specified by <code>tableParam</code>
+   *
+   * @param tableParam the <code>TableParam</code> object
+   *     <pre>
+   * example usage:
+   * <code>
+   * TableParam tableParam = new TableParam.Builder(tableName)
+   *                                       .withTimeout(timeout)
+   *                                       .build();
+   * </code>
+   * </pre>
+   *
+   * @return <code>DescribeTableResponse</code>
+   * @see TableParam
+   * @see DescribeTableResponse
+   * @see Response
+   */
+  DescribeTableResponse describeTable(TableParam tableParam);
+
+  /**
+   * Shows current tables
+   *
+   * @return <code>ShowTablesResponse</code>
+   * @see ShowTablesResponse
+   * @see Response
+   */
+  ShowTablesResponse showTables();
+
+  /**
+   * Gets current row count of table specified by <code>tableParam</code>
+   *
+   * @param tableParam the <code>TableParam</code> object
+   *     <pre>
+   * example usage:
+   * <code>
+   * TableParam tableParam = new TableParam.Builder(tableName)
+   *                                       .withTimeout(timeout)
+   *                                       .build();
+   * </code>
+   * </pre>
+   *
+   * @return <code>GetTableRowCountResponse</code>
+   * @see GetTableRowCountResponse
+   * @see Response
+   */
+  GetTableRowCountResponse getTableRowCount(TableParam tableParam);
+
+  /**
+   * Prints server status
+   *
+   * @return <code>Response</code>
+   * @see Response
+   */
+  Response serverStatus();
+
+  /**
+   * Prints server version
+   *
+   * @return <code>Response</code>
+   * @see Response
+   */
+  Response serverVersion();
+
+  /**
+   * Deletes vectors by date range, specified by <code>deleteByRangeParam</code>
+   *
+   * @param deleteByRangeParam the <code>DeleteByRangeParam</code> object
+   *     <pre>
+   * example usage:
+   * <code>
+   * DeleteByRangeParam deleteByRangeParam = new DeleteByRangeParam.Builder(dateRange, tableName)
+   *                                                               .withTimeout(timeout)
+   *                                                               .build();
+   * </code>
+   * </pre>
+   *
+   * @return <code>Response</code>
+   * @see DeleteByRangeParam
+   * @see DateRange
+   * @see Response
+   */
+  Response deleteByRange(DeleteByRangeParam deleteByRangeParam);
+
+  /**
+   * Pre-loads table to memory
+   *
+   * @param tableParam the <code>TableParam</code> object
+   *     <pre>
+   * example usage:
+   * <code>
+   * TableParam tableParam = new TableParam.Builder(tableName)
+   *                                       .withTimeout(timeout)
+   *                                       .build();
+   * </code>
+   * </pre>
+   *
+   * @return <code>Response</code>
+   * @see TableParam
+   * @see Response
+   */
+  Response preloadTable(TableParam tableParam);
+
+  /**
+   * Describes table index specified by <code>tableParam</code>
+   *
+   * @param tableParam the <code>TableParam</code> object
+   *     <pre>
+   * example usage:
+   * <code>
+   * TableParam tableParam = new TableParam.Builder(tableName)
+   *                                       .withTimeout(timeout)
+   *                                       .build();
+   * </code>
+   * </pre>
+   *
+   * @return <code>DescribeIndexResponse</code>
+   * @see TableParam
+   * @see DescribeIndexResponse
+   * @see Index
+   * @see Response
+   */
+  DescribeIndexResponse describeIndex(TableParam tableParam);
+
+  /**
+   * Drops table index specified by <code>tableParam</code>
+   *
+   * @param tableParam the <code>TableParam</code> object
+   *     <pre>
+   * example usage:
+   * <code>
+   * TableParam tableParam = new TableParam.Builder(tableName)
+   *                                       .withTimeout(timeout)
+   *                                       .build();
+   * </code>
+   * </pre>
+   *
+   * @return <code>dropIndex</code>
+   * @see TableParam
+   * @see Response
+   */
+  Response dropIndex(TableParam tableParam);
+}

+ 804 - 0
src/main/java/io/milvus/client/MilvusGrpcClient.java

@@ -0,0 +1,804 @@
+/*
+ * 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 io.grpc.ConnectivityState;
+import io.grpc.ManagedChannel;
+import io.grpc.ManagedChannelBuilder;
+import io.grpc.StatusRuntimeException;
+
+import javax.annotation.Nonnull;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/** Actual implementation of interface <code>MilvusClient</code> */
+public class MilvusGrpcClient implements MilvusClient {
+
+  private static final Logger logger = Logger.getLogger(MilvusGrpcClient.class.getName());
+  private static final String ANSI_RESET = "\u001B[0m";
+  private static final String ANSI_YELLOW = "\u001B[33m";
+  private static final String ANSI_PURPLE = "\u001B[35m";
+  private static final String ANSI_BRIGHT_PURPLE = "\u001B[95m";
+
+  private ManagedChannel channel = null;
+  private io.milvus.grpc.MilvusServiceGrpc.MilvusServiceBlockingStub blockingStub;
+
+  /////////////////////// Client Calls///////////////////////
+
+  @Override
+  public Response connect(ConnectParam connectParam) {
+    if (channel != null) {
+      logWarning("You have already connected!");
+      return new Response(Response.Status.CONNECT_FAILED, "You have already connected!");
+    }
+
+    try {
+      int port = Integer.parseInt(connectParam.getPort());
+      if (port < 0 || port > 0xFFFF) {
+        logSevere("Connect failed! Port {0} out of range", connectParam.getPort());
+        return new Response(Response.Status.CONNECT_FAILED, "Port " + port + " out of range");
+      }
+
+      channel =
+          ManagedChannelBuilder.forAddress(connectParam.getHost(), port)
+              .usePlaintext()
+              .maxInboundMessageSize(Integer.MAX_VALUE)
+              .build();
+
+      ConnectivityState connectivityState;
+      connectivityState = channel.getState(true);
+
+      logInfo("Waiting to connect...");
+      TimeUnit.MILLISECONDS.sleep(500);
+
+      connectivityState = channel.getState(false);
+      if (connectivityState != ConnectivityState.READY) {
+        logSevere("Connect failed! {0}", connectParam.toString());
+        return new Response(
+            Response.Status.CONNECT_FAILED, "connectivity state = " + connectivityState);
+      }
+
+      blockingStub = io.milvus.grpc.MilvusServiceGrpc.newBlockingStub(channel);
+
+    } catch (Exception e) {
+      logSevere("Connect failed! {0}\n{1}", connectParam.toString(), e.toString());
+      return new Response(Response.Status.CONNECT_FAILED, e.toString());
+    }
+
+    logInfo("Connected successfully!\n{0}", connectParam.toString());
+    return new Response(Response.Status.SUCCESS);
+  }
+
+  @Override
+  public boolean connected() {
+    if (channel == null) {
+      return false;
+    }
+    ConnectivityState connectivityState = channel.getState(false);
+    return connectivityState == ConnectivityState.READY;
+  }
+
+  @Override
+  public Response disconnect() throws InterruptedException {
+    if (!connected()) {
+      logWarning("You are not connected to Milvus server");
+      return new Response(Response.Status.CLIENT_NOT_CONNECTED);
+    } else {
+      if (channel.shutdown().awaitTermination(60, TimeUnit.SECONDS)) {
+        logInfo("Channel terminated");
+      } else {
+        logSevere("Encountered error when terminating channel");
+        return new Response(Response.Status.RPC_ERROR);
+      }
+    }
+    return new Response(Response.Status.SUCCESS);
+  }
+
+  @Override
+  public Response createTable(@Nonnull TableSchemaParam tableSchemaParam) {
+
+    if (!connected()) {
+      logWarning("You are not connected to Milvus server");
+      return new Response(Response.Status.CLIENT_NOT_CONNECTED);
+    }
+
+    TableSchema tableSchema = tableSchemaParam.getTableSchema();
+    io.milvus.grpc.TableSchema request =
+        io.milvus.grpc.TableSchema.newBuilder()
+            .setTableName(tableSchema.getTableName())
+            .setDimension(tableSchema.getDimension())
+            .setIndexFileSize(tableSchema.getIndexFileSize())
+            .setMetricType(tableSchema.getMetricType().getVal())
+            .build();
+
+    io.milvus.grpc.Status response;
+
+    try {
+      response =
+          blockingStub
+              .withDeadlineAfter(tableSchemaParam.getTimeout(), TimeUnit.SECONDS)
+              .createTable(request);
+
+      if (response.getErrorCode() == io.milvus.grpc.ErrorCode.SUCCESS) {
+        logInfo("Created table successfully!\n{0}", tableSchema.toString());
+        return new Response(Response.Status.SUCCESS);
+      } else if (response.getReason().contentEquals("Table already exists")) {
+        logWarning("Table `{0}` already exists", tableSchema.getTableName());
+        return new Response(
+            Response.Status.valueOf(response.getErrorCodeValue()), response.getReason());
+      } else {
+        logSevere("Create table failed\n{0}\n{1}", tableSchema.toString(), response.toString());
+        return new Response(
+            Response.Status.valueOf(response.getErrorCodeValue()), response.getReason());
+      }
+    } catch (StatusRuntimeException e) {
+      logSevere("createTable RPC failed:\n{0}", e.getStatus().toString());
+      return new Response(Response.Status.RPC_ERROR, e.toString());
+    }
+  }
+
+  @Override
+  public HasTableResponse hasTable(@Nonnull TableParam tableParam) {
+
+    if (!connected()) {
+      logWarning("You are not connected to Milvus server");
+      return new HasTableResponse(new Response(Response.Status.CLIENT_NOT_CONNECTED), false);
+    }
+
+    String tableName = tableParam.getTableName();
+    io.milvus.grpc.TableName request =
+        io.milvus.grpc.TableName.newBuilder().setTableName(tableName).build();
+    io.milvus.grpc.BoolReply response;
+
+    try {
+      response =
+          blockingStub
+              .withDeadlineAfter(tableParam.getTimeout(), TimeUnit.SECONDS)
+              .hasTable(request);
+
+      if (response.getStatus().getErrorCode() == io.milvus.grpc.ErrorCode.SUCCESS) {
+        logInfo("hasTable `{0}` = {1}", tableName, response.getBoolReply());
+        return new HasTableResponse(new Response(Response.Status.SUCCESS), response.getBoolReply());
+      } else {
+        logSevere("hasTable `{0}` failed:\n{1}", tableName, response.toString());
+        return new HasTableResponse(
+            new Response(
+                Response.Status.valueOf(response.getStatus().getErrorCodeValue()),
+                response.getStatus().getReason()),
+            false);
+      }
+    } catch (StatusRuntimeException e) {
+      logSevere("hasTable RPC failed:\n{0}", e.getStatus().toString());
+      return new HasTableResponse(new Response(Response.Status.RPC_ERROR, e.toString()), false);
+    }
+  }
+
+  @Override
+  public Response dropTable(@Nonnull TableParam tableParam) {
+
+    if (!connected()) {
+      logWarning("You are not connected to Milvus server");
+      return new Response(Response.Status.CLIENT_NOT_CONNECTED);
+    }
+
+    String tableName = tableParam.getTableName();
+    io.milvus.grpc.TableName request =
+        io.milvus.grpc.TableName.newBuilder().setTableName(tableName).build();
+    io.milvus.grpc.Status response;
+
+    try {
+      response =
+          blockingStub
+              .withDeadlineAfter(tableParam.getTimeout(), TimeUnit.SECONDS)
+              .dropTable(request);
+
+      if (response.getErrorCode() == io.milvus.grpc.ErrorCode.SUCCESS) {
+        logInfo("Dropped table `{0}` successfully!", tableName);
+        return new Response(Response.Status.SUCCESS);
+      } else {
+        logSevere("Drop table `{0}` failed:\n{1}", tableName, response.toString());
+        return new Response(
+            Response.Status.valueOf(response.getErrorCodeValue()), response.getReason());
+      }
+    } catch (StatusRuntimeException e) {
+      logSevere("dropTable RPC failed:\n{0}", e.getStatus().toString());
+      return new Response(Response.Status.RPC_ERROR, e.toString());
+    }
+  }
+
+  @Override
+  public Response createIndex(@Nonnull CreateIndexParam createIndexParam) {
+
+    if (!connected()) {
+      logWarning("You are not connected to Milvus server");
+      return new Response(Response.Status.CLIENT_NOT_CONNECTED);
+    }
+
+    io.milvus.grpc.Index index =
+        io.milvus.grpc.Index.newBuilder()
+            .setIndexType(createIndexParam.getIndex().getIndexType().getVal())
+            .setNlist(createIndexParam.getIndex().getNList())
+            .build();
+    io.milvus.grpc.IndexParam request =
+        io.milvus.grpc.IndexParam.newBuilder()
+            .setTableName(createIndexParam.getTableName())
+            .setIndex(index)
+            .build();
+
+    io.milvus.grpc.Status response;
+
+    try {
+      response =
+          blockingStub
+              .withDeadlineAfter(createIndexParam.getTimeout(), TimeUnit.SECONDS)
+              .createIndex(request);
+
+      if (response.getErrorCode() == io.milvus.grpc.ErrorCode.SUCCESS) {
+        logInfo("Created index successfully!\n{0}", createIndexParam.toString());
+        return new Response(Response.Status.SUCCESS);
+      } else {
+        logSevere(
+            "Create index failed\n{0}\n{1}", createIndexParam.toString(), response.toString());
+        return new Response(
+            Response.Status.valueOf(response.getErrorCodeValue()), response.getReason());
+      }
+    } catch (StatusRuntimeException e) {
+      logSevere("createIndex RPC failed:\n{0}", e.getStatus().toString());
+      return new Response(Response.Status.RPC_ERROR, e.toString());
+    }
+  }
+
+  @Override
+  public InsertResponse insert(@Nonnull InsertParam insertParam) {
+
+    if (!connected()) {
+      logWarning("You are not connected to Milvus server");
+      return new InsertResponse(
+          new Response(Response.Status.CLIENT_NOT_CONNECTED), new ArrayList<>());
+    }
+
+    List<io.milvus.grpc.RowRecord> rowRecordList = new ArrayList<>();
+    for (List<Float> vectors : insertParam.getVectors()) {
+      io.milvus.grpc.RowRecord rowRecord =
+          io.milvus.grpc.RowRecord.newBuilder().addAllVectorData(vectors).build();
+      rowRecordList.add(rowRecord);
+    }
+
+    io.milvus.grpc.InsertParam request =
+        io.milvus.grpc.InsertParam.newBuilder()
+            .setTableName(insertParam.getTableName())
+            .addAllRowRecordArray(rowRecordList)
+            .addAllRowIdArray(insertParam.getVectorIds())
+            .build();
+    io.milvus.grpc.VectorIds response;
+
+    try {
+      response =
+          blockingStub
+              .withDeadlineAfter(insertParam.getTimeout(), TimeUnit.SECONDS)
+              .insert(request);
+
+      if (response.getStatus().getErrorCode() == io.milvus.grpc.ErrorCode.SUCCESS) {
+        Optional<List<Long>> resultVectorIds = Optional.ofNullable(response.getVectorIdArrayList());
+        logInfo(
+            "Inserted {0} vectors to table `{1}` successfully!",
+            resultVectorIds.map(List::size).orElse(0), insertParam.getTableName());
+        return new InsertResponse(
+            new Response(Response.Status.SUCCESS), resultVectorIds.orElse(new ArrayList<>()));
+      } else {
+        logSevere("Insert vectors failed:\n{0}", response.toString());
+        return new InsertResponse(
+            new Response(
+                Response.Status.valueOf(response.getStatus().getErrorCodeValue()),
+                response.getStatus().getReason()),
+            new ArrayList<>());
+      }
+    } catch (StatusRuntimeException e) {
+      logSevere("insert RPC failed:\n{0}", e.getStatus().toString());
+      return new InsertResponse(
+          new Response(Response.Status.RPC_ERROR, e.toString()), new ArrayList<>());
+    }
+  }
+
+  @Override
+  public SearchResponse search(@Nonnull SearchParam searchParam) {
+
+    if (!connected()) {
+      logWarning("You are not connected to Milvus server");
+      return new SearchResponse(
+          new Response(Response.Status.CLIENT_NOT_CONNECTED), new ArrayList<>());
+    }
+
+    List<io.milvus.grpc.RowRecord> queryRowRecordList = getQueryRowRecordList(searchParam);
+
+    List<io.milvus.grpc.Range> queryRangeList = getQueryRangeList(searchParam);
+
+    io.milvus.grpc.SearchParam request =
+        io.milvus.grpc.SearchParam.newBuilder()
+            .setTableName(searchParam.getTableName())
+            .addAllQueryRecordArray(queryRowRecordList)
+            .addAllQueryRangeArray(queryRangeList)
+            .setTopk(searchParam.getTopK())
+            .setNprobe(searchParam.getNProbe())
+            .build();
+
+    io.milvus.grpc.TopKQueryResultList response;
+
+    try {
+      response =
+          blockingStub
+              .withDeadlineAfter(searchParam.getTimeout(), TimeUnit.SECONDS)
+              .search(request);
+
+      if (response.getStatus().getErrorCode() == io.milvus.grpc.ErrorCode.SUCCESS) {
+        List<List<SearchResponse.QueryResult>> queryResultsList = getQueryResultsList(response);
+        logInfo(
+            "Search completed successfully! Returned results for {0} queries",
+            queryResultsList.size());
+        return new SearchResponse(new Response(Response.Status.SUCCESS), queryResultsList);
+      } else {
+        logSevere("Search failed:\n{0}", response.toString());
+        return new SearchResponse(
+            new Response(
+                Response.Status.valueOf(response.getStatus().getErrorCodeValue()),
+                response.getStatus().getReason()),
+            new ArrayList<>());
+      }
+    } catch (StatusRuntimeException e) {
+      logSevere("search RPC failed:\n{0}", e.getStatus().toString());
+      return new SearchResponse(
+          new Response(Response.Status.RPC_ERROR, e.toString()), new ArrayList<>());
+    }
+  }
+
+  @Override
+  public SearchResponse searchInFiles(@Nonnull SearchInFilesParam searchInFilesParam) {
+
+    if (!connected()) {
+      logWarning("You are not connected to Milvus server");
+      return new SearchResponse(
+          new Response(Response.Status.CLIENT_NOT_CONNECTED), new ArrayList<>());
+    }
+
+    SearchParam searchParam = searchInFilesParam.getSearchParam();
+
+    List<io.milvus.grpc.RowRecord> queryRowRecordList = getQueryRowRecordList(searchParam);
+
+    List<io.milvus.grpc.Range> queryRangeList = getQueryRangeList(searchParam);
+
+    io.milvus.grpc.SearchParam searchParamToSet =
+        io.milvus.grpc.SearchParam.newBuilder()
+            .setTableName(searchParam.getTableName())
+            .addAllQueryRecordArray(queryRowRecordList)
+            .addAllQueryRangeArray(queryRangeList)
+            .setTopk(searchParam.getTopK())
+            .setNprobe(searchParam.getNProbe())
+            .build();
+
+    io.milvus.grpc.SearchInFilesParam request =
+        io.milvus.grpc.SearchInFilesParam.newBuilder()
+            .addAllFileIdArray(searchInFilesParam.getFileIds())
+            .setSearchParam(searchParamToSet)
+            .build();
+
+    io.milvus.grpc.TopKQueryResultList response;
+
+    try {
+      response =
+          blockingStub
+              .withDeadlineAfter(searchInFilesParam.getTimeout(), TimeUnit.SECONDS)
+              .searchInFiles(request);
+
+      if (response.getStatus().getErrorCode() == io.milvus.grpc.ErrorCode.SUCCESS) {
+        logInfo("Search in files {0} completed successfully!", searchInFilesParam.getFileIds());
+
+        List<List<SearchResponse.QueryResult>> queryResultsList = getQueryResultsList(response);
+        return new SearchResponse(new Response(Response.Status.SUCCESS), queryResultsList);
+      } else {
+        logSevere(
+            "Search in files {0} failed:\n{1}",
+            searchInFilesParam.getFileIds(), response.toString());
+        return new SearchResponse(
+            new Response(
+                Response.Status.valueOf(response.getStatus().getErrorCodeValue()),
+                response.getStatus().getReason()),
+            new ArrayList<>());
+      }
+    } catch (StatusRuntimeException e) {
+      logSevere("searchInFiles RPC failed:\n{0}", e.getStatus().toString());
+      return new SearchResponse(
+          new Response(Response.Status.RPC_ERROR, e.toString()), new ArrayList<>());
+    }
+  }
+
+  @Override
+  public DescribeTableResponse describeTable(@Nonnull TableParam tableParam) {
+
+    if (!connected()) {
+      logWarning("You are not connected to Milvus server");
+      return new DescribeTableResponse(new Response(Response.Status.CLIENT_NOT_CONNECTED), null);
+    }
+
+    String tableName = tableParam.getTableName();
+    io.milvus.grpc.TableName request =
+        io.milvus.grpc.TableName.newBuilder().setTableName(tableName).build();
+    io.milvus.grpc.TableSchema response;
+
+    try {
+      response =
+          blockingStub
+              .withDeadlineAfter(tableParam.getTimeout(), TimeUnit.SECONDS)
+              .describeTable(request);
+
+      if (response.getStatus().getErrorCode() == io.milvus.grpc.ErrorCode.SUCCESS) {
+        TableSchema tableSchema =
+            new TableSchema.Builder(response.getTableName(), response.getDimension())
+                .withIndexFileSize(response.getIndexFileSize())
+                .withMetricType(MetricType.valueOf(response.getMetricType()))
+                .build();
+        logInfo("Describe Table `{0}` returned:\n{1}", tableName, tableSchema);
+        return new DescribeTableResponse(new Response(Response.Status.SUCCESS), tableSchema);
+      } else {
+        logSevere("Describe Table `{0}` failed:\n{1}", tableName, response.toString());
+        return new DescribeTableResponse(
+            new Response(
+                Response.Status.valueOf(response.getStatus().getErrorCodeValue()),
+                response.getStatus().getReason()),
+            null);
+      }
+    } catch (StatusRuntimeException e) {
+      logSevere("describeTable RPC failed:\n{0}", e.getStatus().toString());
+      return new DescribeTableResponse(new Response(Response.Status.RPC_ERROR, e.toString()), null);
+    }
+  }
+
+  @Override
+  public ShowTablesResponse showTables() {
+
+    if (!connected()) {
+      logWarning("You are not connected to Milvus server");
+      return new ShowTablesResponse(
+          new Response(Response.Status.CLIENT_NOT_CONNECTED), new ArrayList<>());
+    }
+
+    io.milvus.grpc.Command request = io.milvus.grpc.Command.newBuilder().setCmd("").build();
+    io.milvus.grpc.TableNameList response;
+
+    try {
+      response = blockingStub.showTables(request);
+
+      if (response.getStatus().getErrorCode() == io.milvus.grpc.ErrorCode.SUCCESS) {
+        List<String> tableNames = response.getTableNamesList();
+        logInfo("Current tables: {0}", tableNames.toString());
+        return new ShowTablesResponse(new Response(Response.Status.SUCCESS), tableNames);
+      } else {
+        logSevere("Show tables failed:\n{0}", response.toString());
+        return new ShowTablesResponse(
+            new Response(
+                Response.Status.valueOf(response.getStatus().getErrorCodeValue()),
+                response.getStatus().getReason()),
+            new ArrayList<>());
+      }
+    } catch (StatusRuntimeException e) {
+      logSevere("showTables RPC failed:\n{0}", e.getStatus().toString());
+      return new ShowTablesResponse(
+          new Response(Response.Status.RPC_ERROR, e.toString()), new ArrayList<>());
+    }
+  }
+
+  @Override
+  public GetTableRowCountResponse getTableRowCount(@Nonnull TableParam tableParam) {
+
+    if (!connected()) {
+      logWarning("You are not connected to Milvus server");
+      return new GetTableRowCountResponse(new Response(Response.Status.CLIENT_NOT_CONNECTED), 0);
+    }
+
+    String tableName = tableParam.getTableName();
+    io.milvus.grpc.TableName request =
+        io.milvus.grpc.TableName.newBuilder().setTableName(tableName).build();
+    io.milvus.grpc.TableRowCount response;
+
+    try {
+      response =
+          blockingStub
+              .withDeadlineAfter(tableParam.getTimeout(), TimeUnit.SECONDS)
+              .countTable(request);
+
+      if (response.getStatus().getErrorCode() == io.milvus.grpc.ErrorCode.SUCCESS) {
+        long tableRowCount = response.getTableRowCount();
+        logInfo("Table `{0}` has {1} rows", tableName, tableRowCount);
+        return new GetTableRowCountResponse(new Response(Response.Status.SUCCESS), tableRowCount);
+      } else {
+        logSevere("Get table `{0}` row count failed:\n{1}", tableName, response.toString());
+        return new GetTableRowCountResponse(
+            new Response(
+                Response.Status.valueOf(response.getStatus().getErrorCodeValue()),
+                response.getStatus().getReason()),
+            0);
+      }
+    } catch (StatusRuntimeException e) {
+      logSevere("countTable RPC failed:\n{0}", e.getStatus().toString());
+      return new GetTableRowCountResponse(new Response(Response.Status.RPC_ERROR, e.toString()), 0);
+    }
+  }
+
+  @Override
+  public Response serverStatus() {
+    CommandParam commandParam = new CommandParam.Builder("OK").build();
+    return command(commandParam);
+  }
+
+  @Override
+  public Response serverVersion() {
+    CommandParam commandParam = new CommandParam.Builder("version").build();
+    return command(commandParam);
+  }
+
+  private Response command(@Nonnull CommandParam commandParam) {
+
+    if (!connected()) {
+      logWarning("You are not connected to Milvus server");
+      return new Response(Response.Status.CLIENT_NOT_CONNECTED);
+    }
+
+    String command = commandParam.getCommand();
+    io.milvus.grpc.Command request = io.milvus.grpc.Command.newBuilder().setCmd(command).build();
+    io.milvus.grpc.StringReply response;
+
+    try {
+      response =
+          blockingStub.withDeadlineAfter(commandParam.getTimeout(), TimeUnit.SECONDS).cmd(request);
+
+      if (response.getStatus().getErrorCode() == io.milvus.grpc.ErrorCode.SUCCESS) {
+        logInfo("Command `{0}`: {1}", command, response.getStringReply());
+        return new Response(Response.Status.SUCCESS, response.getStringReply());
+      } else {
+        logSevere("Command `{0}` failed:\n{1}", command, response.toString());
+        return new Response(
+            Response.Status.valueOf(response.getStatus().getErrorCodeValue()),
+            response.getStatus().getReason());
+      }
+    } catch (StatusRuntimeException e) {
+      logSevere("Command RPC failed:\n{0}", e.getStatus().toString());
+      return new Response(Response.Status.RPC_ERROR, e.toString());
+    }
+  }
+
+  public Response deleteByRange(@Nonnull DeleteByRangeParam deleteByRangeParam) {
+
+    if (!connected()) {
+      logWarning("You are not connected to Milvus server");
+      return new Response(Response.Status.CLIENT_NOT_CONNECTED);
+    }
+
+    io.milvus.grpc.DeleteByRangeParam request =
+        io.milvus.grpc.DeleteByRangeParam.newBuilder()
+            .setRange(getRange(deleteByRangeParam.getDateRange()))
+            .setTableName(deleteByRangeParam.getTableName())
+            .build();
+    io.milvus.grpc.Status response;
+
+    try {
+      response =
+          blockingStub
+              .withDeadlineAfter(deleteByRangeParam.getTimeout(), TimeUnit.SECONDS)
+              .deleteByRange(request);
+
+      if (response.getErrorCode() == io.milvus.grpc.ErrorCode.SUCCESS) {
+        logInfo(
+            "Deleted vectors from table `{0}` in range {1} successfully!",
+            deleteByRangeParam.getTableName(), deleteByRangeParam.getDateRange().toString());
+        return new Response(Response.Status.SUCCESS);
+      } else {
+        logSevere(
+            "Deleted vectors from table `{0}` in range {1} failed:\n{2}",
+            deleteByRangeParam.getTableName(),
+            deleteByRangeParam.getDateRange().toString(),
+            response.toString());
+        return new Response(
+            Response.Status.valueOf(response.getErrorCodeValue()), response.getReason());
+      }
+    } catch (StatusRuntimeException e) {
+      logSevere("deleteByRange RPC failed:\n{0}", e.getStatus().toString());
+      return new Response(Response.Status.RPC_ERROR, e.toString());
+    }
+  }
+
+  @Override
+  public Response preloadTable(@Nonnull TableParam tableParam) {
+
+    if (!connected()) {
+      logWarning("You are not connected to Milvus server");
+      return new Response(Response.Status.CLIENT_NOT_CONNECTED);
+    }
+
+    String tableName = tableParam.getTableName();
+    io.milvus.grpc.TableName request =
+        io.milvus.grpc.TableName.newBuilder().setTableName(tableName).build();
+    io.milvus.grpc.Status response;
+
+    try {
+      response =
+          blockingStub
+              .withDeadlineAfter(tableParam.getTimeout(), TimeUnit.SECONDS)
+              .preloadTable(request);
+
+      if (response.getErrorCode() == io.milvus.grpc.ErrorCode.SUCCESS) {
+        logInfo("Preloaded table `{0}` successfully!", tableName);
+        return new Response(Response.Status.SUCCESS);
+      } else {
+        logSevere("Preload table `{0}` failed:\n{1}", tableName, response.toString());
+        return new Response(
+            Response.Status.valueOf(response.getErrorCodeValue()), response.getReason());
+      }
+    } catch (StatusRuntimeException e) {
+      logSevere("preloadTable RPC failed:\n{0}", e.getStatus().toString());
+      return new Response(Response.Status.RPC_ERROR, e.toString());
+    }
+  }
+
+  @Override
+  public DescribeIndexResponse describeIndex(@Nonnull TableParam tableParam) {
+
+    if (!connected()) {
+      logWarning("You are not connected to Milvus server");
+      return new DescribeIndexResponse(new Response(Response.Status.CLIENT_NOT_CONNECTED), null);
+    }
+
+    String tableName = tableParam.getTableName();
+    io.milvus.grpc.TableName request =
+        io.milvus.grpc.TableName.newBuilder().setTableName(tableName).build();
+    io.milvus.grpc.IndexParam response;
+
+    try {
+      response =
+          blockingStub
+              .withDeadlineAfter(tableParam.getTimeout(), TimeUnit.SECONDS)
+              .describeIndex(request);
+
+      if (response.getStatus().getErrorCode() == io.milvus.grpc.ErrorCode.SUCCESS) {
+        Index index =
+            new Index.Builder()
+                .withIndexType(IndexType.valueOf(response.getIndex().getIndexType()))
+                .withNList(response.getIndex().getNlist())
+                .build();
+        logInfo("Describe index for table `{0}` returned:\n{1}", tableName, index.toString());
+        return new DescribeIndexResponse(new Response(Response.Status.SUCCESS), index);
+      } else {
+        logSevere("Describe index for table `{0}` failed:\n{1}", tableName, response.toString());
+        return new DescribeIndexResponse(
+            new Response(
+                Response.Status.valueOf(response.getStatus().getErrorCodeValue()),
+                response.getStatus().getReason()),
+            null);
+      }
+    } catch (StatusRuntimeException e) {
+      logSevere("describeIndex RPC failed:\n{0}", e.getStatus().toString());
+      return new DescribeIndexResponse(new Response(Response.Status.RPC_ERROR, e.toString()), null);
+    }
+  }
+
+  @Override
+  public Response dropIndex(@Nonnull TableParam tableParam) {
+
+    if (!connected()) {
+      logWarning("You are not connected to Milvus server");
+      return new Response(Response.Status.CLIENT_NOT_CONNECTED);
+    }
+
+    String tableName = tableParam.getTableName();
+    io.milvus.grpc.TableName request =
+        io.milvus.grpc.TableName.newBuilder().setTableName(tableName).build();
+    io.milvus.grpc.Status response;
+
+    try {
+      response =
+          blockingStub
+              .withDeadlineAfter(tableParam.getTimeout(), TimeUnit.SECONDS)
+              .dropIndex(request);
+
+      if (response.getErrorCode() == io.milvus.grpc.ErrorCode.SUCCESS) {
+        logInfo("Dropped index for table `{0}` successfully!", tableName);
+        return new Response(Response.Status.SUCCESS);
+      } else {
+        logSevere("Drop index for table `{0}` failed:\n{1}", tableName, response.toString());
+        return new Response(
+            Response.Status.valueOf(response.getErrorCodeValue()), response.getReason());
+      }
+    } catch (StatusRuntimeException e) {
+      logSevere("dropIndex RPC failed:\n{0}", e.getStatus().toString());
+      return new Response(Response.Status.RPC_ERROR, e.toString());
+    }
+  }
+
+  ///////////////////// Util Functions/////////////////////
+  private List<io.milvus.grpc.RowRecord> getQueryRowRecordList(@Nonnull SearchParam searchParam) {
+    List<io.milvus.grpc.RowRecord> queryRowRecordList = new ArrayList<>();
+    for (List<Float> vectors : searchParam.getQueryVectors()) {
+      io.milvus.grpc.RowRecord rowRecord =
+          io.milvus.grpc.RowRecord.newBuilder().addAllVectorData(vectors).build();
+      queryRowRecordList.add(rowRecord);
+    }
+    return queryRowRecordList;
+  }
+
+  private List<io.milvus.grpc.Range> getQueryRangeList(@Nonnull SearchParam searchParam) {
+    List<io.milvus.grpc.Range> queryRangeList = new ArrayList<>();
+    String datePattern = "yyyy-MM-dd";
+    SimpleDateFormat simpleDateFormat = new SimpleDateFormat(datePattern);
+    for (DateRange queryRange : searchParam.getdateRanges()) {
+      io.milvus.grpc.Range dateRange =
+          io.milvus.grpc.Range.newBuilder()
+              .setStartValue(simpleDateFormat.format(queryRange.getStartDate()))
+              .setEndValue(simpleDateFormat.format(queryRange.getEndDate()))
+              .build();
+      queryRangeList.add(dateRange);
+    }
+    return queryRangeList;
+  }
+
+  private io.milvus.grpc.Range getRange(@Nonnull DateRange dateRange) {
+    String datePattern = "yyyy-MM-dd";
+    SimpleDateFormat simpleDateFormat = new SimpleDateFormat(datePattern);
+    return io.milvus.grpc.Range.newBuilder()
+        .setStartValue(simpleDateFormat.format(dateRange.getStartDate()))
+        .setEndValue(simpleDateFormat.format(dateRange.getEndDate()))
+        .build();
+  }
+
+  private List<List<SearchResponse.QueryResult>> getQueryResultsList(
+      io.milvus.grpc.TopKQueryResultList searchResponse) {
+    // TODO: refactor
+    List<List<SearchResponse.QueryResult>> queryResultsList = new ArrayList<>();
+    Optional<List<io.milvus.grpc.TopKQueryResult>> topKQueryResultList =
+        Optional.ofNullable(searchResponse.getTopkQueryResultList());
+    if (topKQueryResultList.isPresent()) {
+      for (io.milvus.grpc.TopKQueryResult topKQueryResult : topKQueryResultList.get()) {
+        List<SearchResponse.QueryResult> responseQueryResults = new ArrayList<>();
+        List<io.milvus.grpc.QueryResult> queryResults = topKQueryResult.getQueryResultArraysList();
+        for (io.milvus.grpc.QueryResult queryResult : queryResults) {
+          SearchResponse.QueryResult responseQueryResult =
+              new SearchResponse.QueryResult(queryResult.getId(), queryResult.getDistance());
+          responseQueryResults.add(responseQueryResult);
+        }
+        queryResultsList.add(responseQueryResults);
+      }
+    }
+    return queryResultsList;
+  }
+
+  ///////////////////// Log Functions//////////////////////
+
+  private void logInfo(String msg, Object... params) {
+    logger.log(Level.INFO, ANSI_YELLOW + msg + ANSI_RESET, params);
+  }
+
+  private void logWarning(String msg, Object... params) {
+    logger.log(Level.WARNING, ANSI_PURPLE + msg + ANSI_RESET, params);
+  }
+
+  private void logSevere(String msg, Object... params) {
+    logger.log(Level.SEVERE, ANSI_BRIGHT_PURPLE + msg + ANSI_RESET, params);
+  }
+}

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

@@ -0,0 +1,113 @@
+/*
+ * 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),
+    TABLE_NOT_EXISTS(4),
+    ILLEGAL_ARGUMENT(5),
+    ILLEGAL_RANGE(6),
+    ILLEGAL_DIMENSION(7),
+    ILLEGAL_INDEX_TYPE(8),
+    ILLEGAL_TABLE_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);
+
+    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;
+    }
+  }
+}

+ 81 - 0
src/main/java/io/milvus/client/SearchInFilesParam.java

@@ -0,0 +1,81 @@
+/*
+ * 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.Nonnull;
+import java.util.List;
+
+/** Contains parameters for <code>searchInFiles</code> */
+public class SearchInFilesParam {
+  private final List<String> fileIds;
+  private final SearchParam searchParam;
+  private final long timeout;
+
+  private SearchInFilesParam(@Nonnull Builder builder) {
+    this.fileIds = builder.fileIds;
+    this.searchParam = builder.searchParam;
+    this.timeout = builder.timeout;
+  }
+
+  public List<String> getFileIds() {
+    return fileIds;
+  }
+
+  public SearchParam getSearchParam() {
+    return searchParam;
+  }
+
+  public long getTimeout() {
+    return timeout;
+  }
+
+  /** Builder for <code>SearchInFilesParam</code> */
+  public static class Builder {
+    // Required parameters
+    private final List<String> fileIds;
+    private final SearchParam searchParam;
+
+    // Optional parameters - initialized to default values
+    private long timeout = 86400;
+
+    /**
+     * @param fileIds a <code>List</code> of file ids to search from
+     * @param searchParam a <code>searchParam</code> object
+     */
+    public Builder(List<String> fileIds, SearchParam searchParam) {
+      this.fileIds = fileIds;
+      this.searchParam = searchParam;
+    }
+
+    /**
+     * Optional. Sets the deadline from when the client RPC is set to when the response is picked up
+     * by the client. Default to 86400s (1 day).
+     *
+     * @param timeout in seconds
+     * @return <code>Builder</code>
+     */
+    public Builder withTimeout(long timeout) {
+      this.timeout = timeout;
+      return this;
+    }
+
+    public SearchInFilesParam build() {
+      return new SearchInFilesParam(this);
+    }
+  }
+}

+ 140 - 0
src/main/java/io/milvus/client/SearchParam.java

@@ -0,0 +1,140 @@
+/*
+ * 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.Nonnull;
+import java.util.ArrayList;
+import java.util.List;
+
+/** Contains parameters for <code>search</code> */
+public class SearchParam {
+
+  private final String tableName;
+  private final List<List<Float>> queryVectors;
+  private final List<DateRange> dateRanges;
+  private final long topK;
+  private final long nProbe;
+  private final long timeout;
+
+  private SearchParam(@Nonnull Builder builder) {
+    this.tableName = builder.tableName;
+    this.queryVectors = builder.queryVectors;
+    this.dateRanges = builder.dateRanges;
+    this.nProbe = builder.nProbe;
+    this.topK = builder.topK;
+    this.timeout = builder.timeout;
+  }
+
+  public String getTableName() {
+    return tableName;
+  }
+
+  public List<List<Float>> getQueryVectors() {
+    return queryVectors;
+  }
+
+  public List<DateRange> getdateRanges() {
+    return dateRanges;
+  }
+
+  public long getTopK() {
+    return topK;
+  }
+
+  public long getNProbe() {
+    return nProbe;
+  }
+
+  public long getTimeout() {
+    return timeout;
+  }
+
+  /** Builder for <code>SearchParam</code> */
+  public static class Builder {
+    // Required parameters
+    private final String tableName;
+    private final List<List<Float>> queryVectors;
+
+    // Optional parameters - initialized to default values
+    private List<DateRange> dateRanges = new ArrayList<>();
+    private long topK = 1024;
+    private long nProbe = 20;
+    private long timeout = 86400;
+
+    /**
+     * @param tableName table to search from
+     * @param queryVectors a <code>List</code> of vectors to be queried. Each inner <code>List
+     *     </code> represents a vector.
+     */
+    public Builder(@Nonnull String tableName, @Nonnull List<List<Float>> queryVectors) {
+      this.tableName = tableName;
+      this.queryVectors = queryVectors;
+    }
+
+    /**
+     * Optional. Searches vectors in their corresponding date range. Default to an empty <code>
+     * ArrayList</code>
+     *
+     * @param dateRanges a <code>List</code> of <code>DateRange</code> objects
+     * @return <code>Builder</code>
+     * @see DateRange
+     */
+    public Builder withDateRanges(@Nonnull List<DateRange> dateRanges) {
+      this.dateRanges = dateRanges;
+      return this;
+    }
+
+    /**
+     * Optional. Limits search result to <code>topK</code>. Default to 1024.
+     *
+     * @param topK a topK number
+     * @return <code>Builder</code>
+     */
+    public Builder withTopK(long topK) {
+      this.topK = topK;
+      return this;
+    }
+
+    /**
+     * Optional. Default to 20.
+     *
+     * @param nProbe a nProbe number
+     * @return <code>Builder</code>
+     */
+    public Builder withNProbe(long nProbe) {
+      this.nProbe = nProbe;
+      return this;
+    }
+
+    /**
+     * Optional. Sets the deadline from when the client RPC is set to when the response is picked up
+     * by the client. Default to 86400s (1 day).
+     *
+     * @param timeout in seconds
+     * @return <code>Builder</code>
+     */
+    public Builder withTimeout(long timeout) {
+      this.timeout = timeout;
+      return this;
+    }
+
+    public SearchParam build() {
+      return new SearchParam(this);
+    }
+  }
+}

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

@@ -0,0 +1,109 @@
+/*
+ * 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.ArrayList;
+import java.util.List;
+
+/**
+ * Contains the returned <code>response</code> and <code>queryResultsList</code> for <code>search
+ * </code>
+ */
+public class SearchResponse {
+
+  private final Response response;
+  private final List<List<QueryResult>> queryResultsList;
+
+  public SearchResponse(Response response, List<List<QueryResult>> queryResultsList) {
+    this.response = response;
+    this.queryResultsList = queryResultsList;
+  }
+
+  /**
+   * @return a <code>List</code> of <code>QueryResult</code>s. Each inner <code>List</code> contains
+   *     the query result of a vector.
+   */
+  public List<List<QueryResult>> getQueryResultsList() {
+    return queryResultsList;
+  }
+
+  /**
+   * @return a <code>List</code> of result ids. Each inner <code>List</code> contains the result ids
+   *     of a vector.
+   */
+  public List<List<Long>> getResultIdsList() {
+    List<List<Long>> resultIdsList = new ArrayList<>();
+    for (List<QueryResult> queryResults : queryResultsList) {
+      List<Long> resultIds = new ArrayList<>();
+      for (QueryResult queryResult : queryResults) {
+        resultIds.add(queryResult.vectorId);
+      }
+      resultIdsList.add(resultIds);
+    }
+    return resultIdsList;
+  }
+
+  /**
+   * @return @return a <code>List</code> of result distances. Each inner <code>List</code> contains
+   *     the result distances of a vector.
+   */
+  public List<List<Double>> getResultDistancesList() {
+    List<List<Double>> resultDistancesList = new ArrayList<>();
+    for (List<QueryResult> queryResults : queryResultsList) {
+      List<Double> resultDistances = new ArrayList<>();
+      for (QueryResult queryResult : queryResults) {
+        resultDistances.add(queryResult.distance);
+      }
+      resultDistancesList.add(resultDistances);
+    }
+    return resultDistancesList;
+  }
+
+  public Response getResponse() {
+    return response;
+  }
+
+  @Override
+  public String toString() {
+    return String.format(
+        "SearchResponse {%s, returned results for %d queries}",
+        response.toString(), this.queryResultsList.size());
+  }
+
+  /**
+   * Represents a single result of a vector query. Contains the result <code>vectorId</code> and its
+   * <code>distance</code> to the vector being queried
+   */
+  public static class QueryResult {
+    private final long vectorId;
+    private final double distance;
+
+    public QueryResult(long vectorId, double distance) {
+      this.vectorId = vectorId;
+      this.distance = distance;
+    }
+
+    public long getVectorId() {
+      return vectorId;
+    }
+
+    public double getDistance() {
+      return distance;
+    }
+  }
+}

+ 48 - 0
src/main/java/io/milvus/client/ShowTablesResponse.java

@@ -0,0 +1,48 @@
+/*
+ * 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>tableNames</code> for <code>showTables
+ * </code>
+ */
+public class ShowTablesResponse {
+  private final Response response;
+  private final List<String> tableNames;
+
+  public ShowTablesResponse(Response response, List<String> tableNames) {
+    this.response = response;
+    this.tableNames = tableNames;
+  }
+
+  public List<String> getTableNames() {
+    return tableNames;
+  }
+
+  public Response getResponse() {
+    return response;
+  }
+
+  @Override
+  public String toString() {
+    return String.format(
+        "ShowTablesResponse {%s, table names = %s}", response, tableNames.toString());
+  }
+}

+ 78 - 0
src/main/java/io/milvus/client/TableParam.java

@@ -0,0 +1,78 @@
+/*
+ * 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.Nonnull;
+
+/**
+ * Contains parameters for <code>hasTable</code>, <code>dropTable</code>, <code>describeTable</code>
+ * , <code>getTableRowCount</code>, <code>preloadTable</code>, <code>describeIndex</code> and <code>
+ * dropIndex</code>
+ */
+public class TableParam {
+  private final String tableName;
+  private final long timeout;
+
+  private TableParam(@Nonnull Builder builder) {
+    this.tableName = builder.tableName;
+    this.timeout = builder.timeout;
+  }
+
+  public String getTableName() {
+    return tableName;
+  }
+
+  public long getTimeout() {
+    return timeout;
+  }
+
+  @Override
+  public String toString() {
+    return "TableParam {" + "tableName = '" + tableName + '\'' + ", timeout = " + timeout + '}';
+  }
+
+  /** Builder for <code>TableParam</code> */
+  public static class Builder {
+    // Required parameters
+    private final String tableName;
+
+    // Optional parameters - initialized to default values
+    private long timeout = 86400;
+
+    /** @param tableName table name */
+    public Builder(@Nonnull String tableName) {
+      this.tableName = tableName;
+    }
+
+    /**
+     * Optional. Sets the deadline from when the client RPC is set to when the response is picked up
+     * by the client. Default to 86400s (1 day).
+     *
+     * @param timeout in seconds
+     * @return <code>Builder</code>
+     */
+    public Builder withTimeout(long timeout) {
+      this.timeout = timeout;
+      return this;
+    }
+
+    public TableParam build() {
+      return new TableParam(this);
+    }
+  }
+}

+ 106 - 0
src/main/java/io/milvus/client/TableSchema.java

@@ -0,0 +1,106 @@
+/*
+ * 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.Nonnull;
+
+/** Represents a table schema */
+// Builder Pattern
+public class TableSchema {
+  private final String tableName;
+  private final long dimension;
+  private final long indexFileSize;
+  private final MetricType metricType;
+
+  private TableSchema(@Nonnull Builder builder) {
+    tableName = builder.tableName;
+    dimension = builder.dimension;
+    indexFileSize = builder.indexFileSize;
+    metricType = builder.metricType;
+  }
+
+  public String getTableName() {
+    return tableName;
+  }
+
+  public long getDimension() {
+    return dimension;
+  }
+
+  public long getIndexFileSize() {
+    return indexFileSize;
+  }
+
+  public MetricType getMetricType() {
+    return metricType;
+  }
+
+  @Override
+  public String toString() {
+    return String.format(
+        "TableSchema = {tableName = %s, dimension = %d, indexFileSize = %d, metricType = %s}",
+        tableName, dimension, indexFileSize, metricType.name());
+  }
+
+  /** Builder for <code>TableSchema</code> */
+  public static class Builder {
+    // Required parameters
+    private final String tableName;
+    private final long dimension;
+
+    // Optional parameters - initialized to default values
+    private long indexFileSize = 1024;
+    private MetricType metricType = MetricType.L2;
+
+    /**
+     * @param tableName table name
+     * @param dimension vector dimension
+     */
+    public Builder(@Nonnull String tableName, long dimension) {
+      this.tableName = tableName;
+      this.dimension = dimension;
+    }
+
+    /**
+     * Optional. Default to 1024 MB.
+     *
+     * @param indexFileSize in megabytes.
+     * @return <code>Builder</code>
+     */
+    public Builder withIndexFileSize(long indexFileSize) {
+      this.indexFileSize = indexFileSize;
+      return this;
+    }
+
+    /**
+     * Optional. Default to MetricType.L2
+     *
+     * @param metricType a <code>MetricType</code> value
+     * @return <code>Builder</code>
+     * @see MetricType
+     */
+    public Builder withMetricType(@Nonnull MetricType metricType) {
+      this.metricType = metricType;
+      return this;
+    }
+
+    public TableSchema build() {
+      return new TableSchema(this);
+    }
+  }
+}

+ 77 - 0
src/main/java/io/milvus/client/TableSchemaParam.java

@@ -0,0 +1,77 @@
+/*
+ * 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.Nonnull;
+
+/** Contains parameters for <code>createTable</code> */
+public class TableSchemaParam {
+  private final TableSchema tableSchema;
+  private final long timeout;
+
+  private TableSchemaParam(@Nonnull Builder builder) {
+    this.tableSchema = builder.tableSchema;
+    this.timeout = builder.timeout;
+  }
+
+  public TableSchema getTableSchema() {
+    return tableSchema;
+  }
+
+  public long getTimeout() {
+    return timeout;
+  }
+
+  @Override
+  public String toString() {
+    return "CreateTableParam {" + tableSchema + ", timeout = " + timeout + '}';
+  }
+
+  /** Builder for <code>TableSchemaParam</code> */
+  public static class Builder {
+    // Required parameters
+    private final TableSchema tableSchema;
+
+    // Optional parameters - initialized to default values
+    private long timeout = 86400;
+
+    /**
+     * @param tableSchema a <code>TableSchema</code> object
+     * @see TableSchema
+     */
+    public Builder(@Nonnull TableSchema tableSchema) {
+      this.tableSchema = tableSchema;
+    }
+
+    /**
+     * Optional. Sets the deadline from when the client RPC is set to when the response is picked up
+     * by the client. Default to 86400s (1 day).
+     *
+     * @param timeout in seconds
+     * @return <code>Builder</code>
+     */
+    public Builder withTimeout(long timeout) {
+      this.timeout = timeout;
+      return this;
+    }
+
+    public TableSchemaParam build() {
+      return new TableSchemaParam(this);
+    }
+  }
+}

+ 327 - 0
src/main/proto/milvus.proto

@@ -0,0 +1,327 @@
+syntax = "proto3";
+
+import "status.proto";
+
+option java_multiple_files = true;
+option java_package = "io.milvus.grpc";
+option java_outer_classname = "MilvusProto";
+
+package milvus.grpc;
+
+/**
+ * @brief Table Name
+ */
+message TableName {
+    string table_name = 1;
+}
+
+/**
+ * @brief Table Name List
+ */
+message TableNameList {
+    Status status = 1;
+    repeated string table_names = 2;
+}
+
+/**
+ * @brief Table Schema
+ */
+message TableSchema {
+    Status status = 1;
+    string table_name = 2;
+    int64 dimension = 3;
+    int64 index_file_size = 4;
+    int32 metric_type = 5;
+}
+
+/**
+ * @brief Range Schema
+ */
+message Range {
+    string start_value = 1;
+    string end_value = 2;
+}
+
+/**
+ * @brief Record inserted
+ */
+message RowRecord {
+    repeated float vector_data = 1;             //binary vector data
+}
+
+/**
+ * @brief params to be inserted
+ */
+message InsertParam {
+    string table_name = 1;
+    repeated RowRecord row_record_array = 2;
+    repeated int64 row_id_array = 3;            //optional
+}
+
+/**
+ * @brief Vector ids
+ */
+message VectorIds {
+    Status status = 1;
+    repeated int64 vector_id_array = 2;
+}
+
+/**
+ * @brief params for searching vector
+ */
+message SearchParam {
+    string table_name = 1;
+    repeated RowRecord query_record_array = 2;
+    repeated Range query_range_array = 3;
+    int64 topk = 4;
+    int64 nprobe = 5;
+}
+
+/**
+ * @brief params for searching vector in files
+ */
+message SearchInFilesParam {
+    repeated string file_id_array = 1;
+    SearchParam search_param = 2;
+}
+
+/**
+ * @brief Query result params
+ */
+message QueryResult {
+    int64 id = 1;
+    double distance = 2;
+}
+
+/**
+ * @brief TopK query result
+ */
+message TopKQueryResult {
+    repeated QueryResult query_result_arrays = 1;
+}
+
+/**
+ * @brief List of topK query result
+ */
+message TopKQueryResultList {
+    Status status = 1;
+    repeated TopKQueryResult topk_query_result = 2;
+}
+
+/**
+ * @brief Server String Reply
+ */
+message StringReply {
+    Status status = 1;
+    string string_reply = 2;
+}
+
+/**
+ * @brief Server bool Reply
+ */
+message BoolReply {
+    Status status = 1;
+    bool bool_reply = 2;
+}
+
+/**
+ * @brief Return table row count
+ */
+message TableRowCount {
+    Status status = 1;
+    int64 table_row_count = 2;
+}
+
+/**
+ * @brief Give Server Command
+ */
+message Command {
+    string cmd = 1;
+}
+
+/**
+ * @brief Index
+ * @index_type: 0-invalid, 1-idmap, 2-ivflat, 3-ivfsq8, 4-nsgmix
+ * @metric_type: 1-L2, 2-IP
+ */
+message Index {
+    int32 index_type = 1;
+    int32 nlist = 2;
+}
+
+/**
+ * @brief Index params
+ */
+message IndexParam {
+    Status status = 1;
+    string table_name = 2;
+    Index index = 3;
+}
+
+/**
+ * @brief table name and range for DeleteByRange
+ */
+message DeleteByRangeParam {
+    Range range = 1;
+    string table_name = 2;
+}
+
+service MilvusService {
+    /**
+     * @brief Create table method
+     *
+     * This method is used to create table
+     *
+     * @param param, use to provide table information to be created.
+     *
+     */
+    rpc CreateTable(TableSchema) returns (Status){}
+
+    /**
+     * @brief Test table existence method
+     *
+     * This method is used to test table existence.
+     *
+     * @param table_name, table name is going to be tested.
+     *
+     */
+    rpc HasTable(TableName) returns (BoolReply) {}
+
+    /**
+     * @brief Delete table method
+     *
+     * This method is used to delete table.
+     *
+     * @param table_name, table name is going to be deleted.
+     *
+     */
+    rpc DropTable(TableName) returns (Status) {}
+
+    /**
+     * @brief Build index by table method
+     *
+     * This method is used to build index by table in sync mode.
+     *
+     * @param table_name, table is going to be built index.
+     *
+     */
+    rpc CreateIndex(IndexParam) returns (Status) {}
+
+    /**
+     * @brief Add vector array to table
+     *
+     * This method is used to add vector array to table.
+     *
+     * @param table_name, table_name is inserted.
+     * @param record_array, vector array is inserted.
+     *
+     * @return vector id array
+     */
+    rpc Insert(InsertParam) returns (VectorIds) {}
+
+    /**
+     * @brief Query vector
+     *
+     * This method is used to query vector in table.
+     *
+     * @param table_name, table_name is queried.
+     * @param query_record_array, all vector are going to be queried.
+     * @param query_range_array, optional ranges for conditional search. If not specified, search whole table
+     * @param topk, how many similarity vectors will be searched.
+     *
+     * @return query result array.
+     */
+    rpc Search(SearchParam) returns (TopKQueryResultList) {}
+
+    /**
+     * @brief Internal use query interface
+     *
+     * This method is used to query vector in specified files.
+     *
+     * @param file_id_array, specified files id array, queried.
+     * @param query_record_array, all vector are going to be queried.
+     * @param query_range_array, optional ranges for conditional search. If not specified, search whole table
+     * @param topk, how many similarity vectors will be searched.
+     *
+     * @return query result array.
+     */
+    rpc SearchInFiles(SearchInFilesParam) returns (TopKQueryResultList) {}
+
+    /**
+     * @brief Get table schema
+     *
+     * This method is used to get table schema.
+     *
+     * @param table_name, target table name.
+     *
+     * @return table schema
+     */
+    rpc DescribeTable(TableName) returns (TableSchema) {}
+
+    /**
+     * @brief Get table schema
+     *
+     * This method is used to get table schema.
+     *
+     * @param table_name, target table name.
+     *
+     * @return table schema
+     */
+    rpc CountTable(TableName) returns (TableRowCount) {}
+
+    /**
+     * @brief List all tables in database
+     *
+     * This method is used to list all tables.
+     *
+     *
+     * @return table names.
+     */
+    rpc ShowTables(Command) returns (TableNameList) {}
+
+    /**
+     * @brief Give the server status
+     *
+     * This method is used to give the server status.
+     *
+     * @return Server status.
+     */
+    rpc Cmd(Command) returns (StringReply) {}
+
+    /**
+    * @brief delete table by range
+    *
+    * This method is used to delete vector by range
+    *
+    * @return rpc status.
+    */
+    rpc DeleteByRange(DeleteByRangeParam) returns (Status) {}
+
+    /**
+     * @brief preload table
+     *
+     * This method is used to preload table
+     *
+     * @return Status.
+     */
+    rpc PreloadTable(TableName) returns (Status) {}
+
+    /**
+     * @brief describe index
+     *
+     * This method is used to describe index
+     *
+     * @return Status.
+     */
+    rpc DescribeIndex(TableName) returns (IndexParam) {}
+
+    /**
+     * @brief drop index
+     *
+     * This method is used to drop index
+     *
+     * @return Status.
+     */
+    rpc DropIndex(TableName) returns (Status) {}
+
+}

+ 40 - 0
src/main/proto/status.proto

@@ -0,0 +1,40 @@
+syntax = "proto3";
+
+option java_multiple_files = true;
+option java_package = "io.milvus.grpc";
+option java_outer_classname = "MilvusStatusProto";
+
+package milvus.grpc;
+
+enum ErrorCode {
+    SUCCESS = 0;
+    UNEXPECTED_ERROR = 1;
+    CONNECT_FAILED = 2;
+    PERMISSION_DENIED = 3;
+    TABLE_NOT_EXISTS = 4;
+    ILLEGAL_ARGUMENT = 5;
+    ILLEGAL_RANGE = 6;
+    ILLEGAL_DIMENSION = 7;
+    ILLEGAL_INDEX_TYPE = 8;
+    ILLEGAL_TABLE_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;
+}
+
+message Status {
+    ErrorCode error_code = 1;
+    string reason = 2;
+}

+ 262 - 0
src/test/java/io/milvus/client/MilvusGrpcClientTest.java

@@ -0,0 +1,262 @@
+/*
+ * 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 org.apache.commons.text.RandomStringGenerator;
+
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class MilvusGrpcClientTest {
+
+  private MilvusGrpcClient client;
+
+  private RandomStringGenerator generator;
+
+  private String randomTableName;
+  private long size;
+  private long dimension;
+  private TableParam tableParam;
+  private TableSchema tableSchema;
+
+  @org.junit.jupiter.api.BeforeEach
+  void setUp() throws Exception {
+
+    client = new MilvusGrpcClient();
+    ConnectParam connectParam =
+        new ConnectParam.Builder().withHost("localhost").withPort("19530").build();
+    client.connect(connectParam);
+
+    generator = new RandomStringGenerator.Builder().withinRange('a', 'z').build();
+    randomTableName = generator.generate(10);
+    size = 100;
+    dimension = 128;
+    tableParam = new TableParam.Builder(randomTableName).build();
+    tableSchema =
+        new TableSchema.Builder(randomTableName, dimension)
+            .withIndexFileSize(1024)
+            .withMetricType(MetricType.IP)
+            .build();
+    TableSchemaParam tableSchemaParam = new TableSchemaParam.Builder(tableSchema).build();
+
+    assertTrue(client.createTable(tableSchemaParam).ok());
+  }
+
+  @org.junit.jupiter.api.AfterEach
+  void tearDown() throws InterruptedException {
+    assertTrue(client.dropTable(tableParam).ok());
+    client.disconnect();
+  }
+
+  @org.junit.jupiter.api.Test
+  void connected() {
+    assertTrue(client.connected());
+  }
+
+  @org.junit.jupiter.api.Test
+  void createTable() {
+    String invalidTableName = "╯°□°)╯";
+    TableSchema invalidTableSchema = new TableSchema.Builder(invalidTableName, dimension).build();
+    TableSchemaParam invalidTableSchemaParam =
+        new TableSchemaParam.Builder(invalidTableSchema).withTimeout(20).build();
+    Response createTableResponse = client.createTable(invalidTableSchemaParam);
+    assertFalse(createTableResponse.ok());
+    assertEquals(Response.Status.ILLEGAL_TABLE_NAME, createTableResponse.getStatus());
+  }
+
+  @org.junit.jupiter.api.Test
+  void hasTable() {
+    HasTableResponse hasTableResponse = client.hasTable(tableParam);
+    assertTrue(hasTableResponse.getResponse().ok());
+  }
+
+  @org.junit.jupiter.api.Test
+  void dropTable() {
+    String nonExistingTableName = generator.generate(10);
+    TableParam tableParam = new TableParam.Builder(nonExistingTableName).build();
+    Response dropTableResponse = client.dropTable(tableParam);
+    assertFalse(dropTableResponse.ok());
+    assertEquals(Response.Status.TABLE_NOT_EXISTS, dropTableResponse.getStatus());
+  }
+
+  @org.junit.jupiter.api.Test
+  void createIndex() {
+    Index index = new Index.Builder().withIndexType(IndexType.IVF_SQ8).withNList(16384).build();
+    CreateIndexParam createIndexParam =
+        new CreateIndexParam.Builder(randomTableName).withIndex(index).build();
+    Response createIndexResponse = client.createIndex(createIndexParam);
+    assertTrue(createIndexResponse.ok());
+  }
+
+  @org.junit.jupiter.api.Test
+  void insert() {
+    Random random = new Random();
+    List<List<Float>> vectors = new ArrayList<>();
+    for (int i = 0; i < size; ++i) {
+      List<Float> vector = new ArrayList<>();
+      for (int j = 0; j < dimension; ++j) {
+        vector.add(random.nextFloat());
+      }
+      vectors.add(vector);
+    }
+    InsertParam insertParam = new InsertParam.Builder(randomTableName, vectors).build();
+    InsertResponse insertResponse = client.insert(insertParam);
+    assertTrue(insertResponse.getResponse().ok());
+    assertEquals(size, insertResponse.getVectorIds().size());
+  }
+
+  List<Float> normalize(List<Float> vector) {
+    float squareSum = vector.stream().map(x -> x * x).reduce((float) 0, Float::sum);
+    final float norm = (float) Math.sqrt(squareSum);
+    vector = vector.stream().map(x -> x / norm).collect(Collectors.toList());
+    return vector;
+  }
+
+  @org.junit.jupiter.api.Test
+  void search() throws InterruptedException {
+    Random random = new Random();
+    List<List<Float>> vectors = new ArrayList<>();
+    List<List<Float>> vectorsToSearch = new ArrayList<>();
+    int searchSize = 5;
+    for (int i = 0; i < size; ++i) {
+      List<Float> vector = new ArrayList<>();
+      for (int j = 0; j < dimension; ++j) {
+        vector.add(random.nextFloat());
+      }
+      if (tableSchema.getMetricType() == MetricType.IP) {
+        vector = normalize(vector);
+      }
+      vectors.add(vector);
+      if (i < searchSize) {
+        vectorsToSearch.add(vector);
+      }
+    }
+    InsertParam insertParam = new InsertParam.Builder(randomTableName, vectors).build();
+    InsertResponse insertResponse = client.insert(insertParam);
+    assertTrue(insertResponse.getResponse().ok());
+    assertEquals(size, insertResponse.getVectorIds().size());
+
+    TimeUnit.SECONDS.sleep(1);
+
+    List<DateRange> queryRanges = new ArrayList<>();
+    Date today = new Date();
+    Calendar c = Calendar.getInstance();
+    c.setTime(today);
+    c.add(Calendar.DAY_OF_MONTH, -1);
+    Date yesterday = c.getTime();
+    c.setTime(today);
+    c.add(Calendar.DAY_OF_MONTH, 1);
+    Date tomorrow = c.getTime();
+    queryRanges.add(new DateRange(yesterday, tomorrow));
+    System.out.println(queryRanges);
+    SearchParam searchParam =
+        new SearchParam.Builder(randomTableName, vectorsToSearch)
+            .withTopK(1)
+            .withNProbe(20)
+            .withDateRanges(queryRanges)
+            .build();
+    SearchResponse searchResponse = client.search(searchParam);
+    assertTrue(searchResponse.getResponse().ok());
+    System.out.println(searchResponse);
+    assertEquals(searchSize, searchResponse.getQueryResultsList().size());
+  }
+
+  //    @org.junit.jupiter.api.Test
+  //    void searchInFiles() {
+  //    }
+
+  @org.junit.jupiter.api.Test
+  void describeTable() {
+    DescribeTableResponse describeTableResponse = client.describeTable(tableParam);
+    assertTrue(describeTableResponse.getResponse().ok());
+    assertTrue(describeTableResponse.getTableSchema().isPresent());
+
+    String nonExistingTableName = generator.generate(10);
+    TableParam tableParam = new TableParam.Builder(nonExistingTableName).build();
+    describeTableResponse = client.describeTable(tableParam);
+    assertFalse(describeTableResponse.getResponse().ok());
+    assertFalse(describeTableResponse.getTableSchema().isPresent());
+  }
+
+  @org.junit.jupiter.api.Test
+  void showTables() {
+    ShowTablesResponse showTablesResponse = client.showTables();
+    assertTrue(showTablesResponse.getResponse().ok());
+  }
+
+  @org.junit.jupiter.api.Test
+  void serverStatus() {
+    Response serverStatusResponse = client.serverStatus();
+    assertTrue(serverStatusResponse.ok());
+  }
+
+  @org.junit.jupiter.api.Test
+  void serverVersion() {
+    Response serverVersionResponse = client.serverVersion();
+    assertTrue(serverVersionResponse.ok());
+  }
+
+  @org.junit.jupiter.api.Test
+  void getTableRowCount() throws InterruptedException {
+    insert();
+    TimeUnit.SECONDS.sleep(1);
+
+    GetTableRowCountResponse getTableRowCountResponse = client.getTableRowCount(tableParam);
+    assertTrue(getTableRowCountResponse.getResponse().ok());
+    assertEquals(size, getTableRowCountResponse.getTableRowCount());
+  }
+
+  @org.junit.jupiter.api.Test
+  void deleteByRange() {
+    Date today = new Date();
+    Calendar c = Calendar.getInstance();
+    c.setTime(today);
+    c.add(Calendar.DAY_OF_MONTH, -1);
+    Date yesterday = c.getTime();
+    c.setTime(today);
+    c.add(Calendar.DAY_OF_MONTH, 1);
+    Date tomorrow = c.getTime();
+
+    DeleteByRangeParam deleteByRangeParam =
+        new DeleteByRangeParam.Builder(new DateRange(yesterday, tomorrow), randomTableName).build();
+    Response deleteByRangeResponse = client.deleteByRange(deleteByRangeParam);
+    assertTrue(deleteByRangeResponse.ok());
+  }
+
+  @org.junit.jupiter.api.Test
+  void preloadTable() {
+    Response preloadTableResponse = client.preloadTable(tableParam);
+    assertTrue(preloadTableResponse.ok());
+  }
+
+  @org.junit.jupiter.api.Test
+  void describeIndex() {
+    DescribeIndexResponse describeIndexResponse = client.describeIndex(tableParam);
+    assertTrue(describeIndexResponse.getResponse().ok());
+    assertTrue(describeIndexResponse.getIndex().isPresent());
+  }
+
+  @org.junit.jupiter.api.Test
+  void dropIndex() {
+    Response dropIndexResponse = client.dropIndex(tableParam);
+    assertTrue(dropIndexResponse.ok());
+  }
+}