Skip to content

Commit

Permalink
push updates for PineconeIndexOperationClient + collection functions …
Browse files Browse the repository at this point in the history
…+ example
  • Loading branch information
austin-denoble committed Feb 1, 2024
1 parent 12a2ee5 commit 63eaf79
Show file tree
Hide file tree
Showing 13 changed files with 511 additions and 453 deletions.
10 changes: 5 additions & 5 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,9 @@ nexusPublishing {
}

signing {
def signingKeyId = findProperty("signingKeyId")
def signingKey = findProperty("signingKey")
def signingPassword = findProperty("signingPassword")
useInMemoryPgpKeys(signingKeyId, signingKey, signingPassword)
sign publishing.publications.pineconeClientMaven
// def signingKeyId = findProperty("signingKeyId")
// def signingKey = findProperty("signingKey")
// def signingPassword = findProperty("signingPassword")
// useInMemoryPgpKeys(signingKeyId, signingKey, signingPassword)
// sign publishing.publications.pineconeClientMaven
}
2 changes: 1 addition & 1 deletion examples/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ repositories {
}

dependencies {
implementation project(':pinecone-client')
implementation project(":")

implementation "org.slf4j:slf4j-simple:1.7.30"
implementation 'org.codehaus.groovy:groovy-all:2.4.15'
Expand Down
16 changes: 16 additions & 0 deletions examples/java-basic-mvn/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Use the official Maven image with Java
FROM maven:3.8.4-openjdk-17

# Set the working directory in the container
WORKDIR /app

# Copy the Java project into the container at /app
# Adjust this to copy only the necessary files
COPY . /app

# Compile the entire project. You can customize this if needed
RUN mvn clean package -Dmaven.repo.local=repository

# The command to run the examples. Replace 'com.example.MainClass' with your main class
# You can repeat this pattern for different examples, or use script/commands to handle multiple examples
CMD ["mvn", "package", "exec:java", "-Dexec.mainClass=pineconeexamples.CreateIndexAndCollectionExample", "-Dpinecone.apiKey=b56c33c1-ba11-4f93-9333-4235ffdaac43", "-Dpinecone.indexName=poddy2", "-Dpinecone.environment=us-west1-gcp", "-Dpinecone.projectName=1390950"]
3 changes: 2 additions & 1 deletion examples/java-basic-mvn/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
<dependency>
<groupId>io.pinecone</groupId>
<artifactId>pinecone-client</artifactId>
<version>0.2.1</version> <!-- [pc:VERSION_NEXT] -->
<version>0.7.4</version> <!-- [pc:VERSION_NEXT] -->
<scope>compile</scope>
</dependency>
<dependency> <!-- Add an slf4j binding like this if you want to see logs emitted by pinecone-client -->
<groupId>org.slf4j</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package pineconeexamples;

import java.util.List;

import io.pinecone.PineconeIndexOperationClient;
import io.pinecone.PineconeClientConfig;
import io.pinecone.exceptions.PineconeException;
import org.openapitools.client.ApiClient;
import org.openapitools.client.model.IndexList;
import org.openapitools.client.model.CollectionList;
import org.openapitools.client.ApiException;

public class CreateIndexAndCollectionExample {

private static PineconeIndexOperationClient pc;
public static class Args {
String apiKey = System.getProperty("pinecone.apiKey", "example-api-key");
String namespace = "";
}

public static void main(String[] cliArgs) throws ApiException {
System.out.println("Starting CreateIndexAndCollectionExample application...");
Args args = new Args();

pc = new PineconeIndexOperationClient(args.apiKey);

try {
IndexList indexList = pc.listIndexes();
System.out.println("Index list: " + indexList);

CollectionList collections = pc.listCollections();
System.out.println("Collection list: " + collections);
}
catch (PineconeException e) {
e.printStackTrace();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import io.pinecone.PineconeClientConfig;
import io.pinecone.PineconeConnection;
import io.pinecone.PineconeConnectionConfig;
import io.pinecone.PineconeException;
import io.pinecone.exceptions.PineconeException;
import io.pinecone.proto.QueryRequest;
import io.pinecone.proto.QueryResponse;
import io.pinecone.proto.QueryVector;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import io.pinecone.PineconeClientConfig;
import io.pinecone.PineconeConnection;
import io.pinecone.PineconeConnectionConfig;
import io.pinecone.PineconeException;
import io.pinecone.exceptions.PineconeException;
import io.pinecone.proto.QueryRequest;
import io.pinecone.proto.QueryResponse;
import io.pinecone.proto.QueryVector;
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
2 changes: 2 additions & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
rootProject.name = "pinecone-java-client"
include 'examples'
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public static void defineConfig() {
config = new PineconeClientConfig()
.withApiKey(System.getenv("PINECONE_API_KEY"))
.withEnvironment(System.getenv("PINECONE_ENVIRONMENT"));
logger.info(String.format("CONFIG: %s", config));
}

@BeforeEach
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import io.pinecone.proto.*;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.Arrays;
Expand All @@ -24,6 +26,8 @@ public class UpdateAndQueryTest {
private static VectorServiceGrpc.VectorServiceFutureStub futureStub;
private static final int dimension = 3;

Logger logger = LoggerFactory.getLogger(UpdateAndQueryTest.class);

@BeforeAll
public static void setUp() throws IOException, InterruptedException {
PineconeConnection connection = createIndexIfNotExistsDataPlane(dimension);
Expand Down Expand Up @@ -387,6 +391,7 @@ public void QueryWithFilersSync() {
.build())
.build();
QueryResponse queryResponse = blockingStub.query(queryRequest);
logger.info(String.format("queryResponse: %s", queryResponse));
// Verify the metadata field is correctly filtered in the query response
assert (queryResponse.getMatches(0).getMetadata().getFieldsMap().get(fieldToQuery).toString().contains(valueToQuery));
} catch (InterruptedException e) {
Expand Down Expand Up @@ -422,6 +427,7 @@ public void QueryWithFilersFuture() {
.build())
.build();
QueryResponse queryResponse = futureStub.query(queryRequest).get();

// Verify the metadata field is correctly filtered in the query response
assert (queryResponse.getMatches(0).getMetadata().getFieldsMap().get(fieldToQuery).toString().contains(valueToQuery));
} catch (ExecutionException | InterruptedException e) {
Expand Down
186 changes: 90 additions & 96 deletions src/main/java/io/pinecone/PineconeIndexOperationClient.java
Original file line number Diff line number Diff line change
@@ -1,136 +1,130 @@
package io.pinecone;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.pinecone.exceptions.FailedRequestInfo;
import io.pinecone.exceptions.HttpErrorMapper;
import io.pinecone.exceptions.PineconeConfigurationException;
import io.pinecone.model.ConfigureIndexRequest;
import io.pinecone.model.CreateIndexRequest;
import io.pinecone.model.IndexMeta;
import okhttp3.*;
import io.pinecone.exceptions.PineconeException;
import org.openapitools.client.ApiClient;
import org.openapitools.client.ApiException;
import org.openapitools.client.api.ManageIndexesApi;
import org.openapitools.client.model.*;

import okhttp3.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class PineconeIndexOperationClient {
private final OkHttpClient client;
private final PineconeClientConfig clientConfig;
private final String url;
public static final String ACCEPT_HEADER = "accept";
public static final String API_KEY_HEADER_NAME = "Api-Key";
public static final String BASE_URL_PREFIX = "https://controller.";
public static final String BASE_URL_SUFFIX = ".pinecone.io/databases";
public static final String CONTENT_TYPE = "content-type";
public static final String CONTENT_TYPE_JSON = "application/json";
public static final String CONTENT_TYPE_CHARSET_UTF8 = "charset=utf-8";
public static final String EMPTY_RESOURCE_PATH = "";
public static final String HTTP_METHOD_DELETE = "DELETE";
public static final String HTTP_METHOD_GET = "GET";
public static final String HTTP_METHOD_PATCH = "HTTP_METHOD_PATCH";
public static final String HTTP_METHOD_POST = "POST";
public static final String TEXT_PLAIN = "text/plain";
public static final String USER_AGENT_HEADER = "User-Agent";

private final ManageIndexesApi manageIndexesAPi;

private PineconeIndexOperationClient(PineconeClientConfig clientConfig, OkHttpClient client, String url) {
this.client = client;
this.clientConfig = clientConfig;
this.url = url;
public PineconeIndexOperationClient(String apiKey, OkHttpClient okHttpClient) {
ApiClient apiClient = new ApiClient(okHttpClient);
apiClient.setApiKey(apiKey);
this.manageIndexesAPi = new ManageIndexesApi(apiClient);
}

public PineconeIndexOperationClient(PineconeClientConfig clientConfig, OkHttpClient client) {
this(clientConfig, client, createUrl(clientConfig));
public PineconeIndexOperationClient(String apiKey) {
this(apiKey, new OkHttpClient());
}

public PineconeIndexOperationClient(PineconeClientConfig clientConfig) {
this(clientConfig, new OkHttpClient());
public void deleteIndex(String indexName) throws IOException {
try {
this.manageIndexesAPi.deleteIndex(indexName);
}
catch (ApiException e) {
handleApiException(e);
}
}

private static String createUrl(PineconeClientConfig clientConfig) {
if (clientConfig.getApiKey() == null || clientConfig.getEnvironment() == null) {
throw new PineconeConfigurationException("Both API key and environment name are required for index operations.");
public IndexModel createIndex(CreateIndexRequest createIndexRequest) throws IOException {
IndexModel createdIndex = null;
try {
this.manageIndexesAPi.createIndex(createIndexRequest);
}

return BASE_URL_PREFIX + clientConfig.getEnvironment() + BASE_URL_SUFFIX;
catch (ApiException e) {
handleApiException(e);
}
return createdIndex;
}

public void deleteIndex(String indexName) throws IOException {
Request request = buildRequest(HTTP_METHOD_DELETE, indexName, TEXT_PLAIN, null);
try (Response response = client.newCall(request).execute()) {
handleResponse(response);
public IndexModel describeIndex(String indexName) throws IOException {
IndexModel index = null;
try {
index = this.manageIndexesAPi.describeIndex(indexName);
}
catch (ApiException e) {
handleApiException(e);
}
return index;
}

public void createIndex(CreateIndexRequest createIndexRequest) throws IOException {
MediaType mediaType = MediaType.parse(CONTENT_TYPE_JSON + ";" + CONTENT_TYPE_CHARSET_UTF8);
RequestBody requestBody = RequestBody.create(createIndexRequest.toJson(), mediaType);
Request request = buildRequest(HTTP_METHOD_POST, EMPTY_RESOURCE_PATH, TEXT_PLAIN, requestBody);
try (Response response = client.newCall(request).execute()) {
handleResponse(response);
public IndexList listIndexes() throws ApiException {
IndexList indexList = null;
try {
indexList = this.manageIndexesAPi.listIndexes();
}
catch (ApiException e) {
handleApiException(e);
}
return indexList;
}

public IndexMeta describeIndex(String indexName) throws IOException {
Request request = buildRequest(HTTP_METHOD_GET, indexName, CONTENT_TYPE_JSON, null);
try (Response response = client.newCall(request).execute()) {
handleResponse(response);
return new IndexMeta().fromJsonString(response.body().string());
public IndexModel configureIndex(String indexName, ConfigureIndexRequest configureIndexRequest) throws IOException {
IndexModel configuredIndex = null;
try {
this.manageIndexesAPi.configureIndex(indexName, configureIndexRequest);
}
catch (ApiException e) {
handleApiException(e);
}
return configuredIndex;
}

public List<String> listIndexes() throws IOException {
String acceptHeaders = CONTENT_TYPE_JSON + "; " + CONTENT_TYPE_CHARSET_UTF8;
List<String> indexList;
ObjectMapper objectMapper = new ObjectMapper();
Request request = buildRequest(HTTP_METHOD_GET, EMPTY_RESOURCE_PATH, acceptHeaders, null);
try (Response response = client.newCall(request).execute()) {
handleResponse(response);
String responseBodyString = response.body().string();
indexList = objectMapper.readValue(responseBodyString, ArrayList.class);
public CollectionModel createCollection(CreateCollectionRequest createCollectionRequest) throws ApiException {
CollectionModel createdCollection = null;
try {
createdCollection = this.manageIndexesAPi.createCollection(createCollectionRequest);
}
return indexList;
catch (ApiException e) {
handleApiException(e);
}
return createdCollection;
}

public void configureIndex(String indexName, ConfigureIndexRequest configureIndexRequest) throws IOException {
MediaType mediaType = MediaType.parse(CONTENT_TYPE_JSON + ";" + CONTENT_TYPE_CHARSET_UTF8);
RequestBody requestBody = RequestBody.create(configureIndexRequest.toJson(), mediaType);
Request request = buildRequest(HTTP_METHOD_PATCH, indexName, TEXT_PLAIN, requestBody);
try (Response response = client.newCall(request).execute()) {
handleResponse(response);
public CollectionList listCollections() throws ApiException {
CollectionList collectionList = null;
try {
collectionList = this.manageIndexesAPi.listCollections();
}
catch (ApiException e) {
handleApiException(e);
}
return collectionList;
}

private Request buildRequest(String method, String path, String acceptHeader, RequestBody requestBody) {
String completeUrl = (path.equals(EMPTY_RESOURCE_PATH)) ? url : url + "/" + path;
Request.Builder builder = new Request.Builder()
.url(completeUrl)
.addHeader(ACCEPT_HEADER, acceptHeader)
.addHeader(API_KEY_HEADER_NAME, clientConfig.getApiKey())
.addHeader(USER_AGENT_HEADER, clientConfig.getUserAgent());
if (HTTP_METHOD_POST.equals(method)) {
builder.post(requestBody);
builder.addHeader(CONTENT_TYPE, CONTENT_TYPE_JSON);
} else if(HTTP_METHOD_PATCH.equals(method)) {
builder.patch(requestBody);
builder.addHeader(CONTENT_TYPE, CONTENT_TYPE_JSON);
} else if (HTTP_METHOD_DELETE.equals(method)) {
builder.delete();
}
return builder.build();
public CollectionModel describeCollection(String collectionName) throws ApiException {
CollectionModel collection = null;
try {
collection = this.manageIndexesAPi.describeCollection(collectionName);
}
catch (ApiException e) {
handleApiException(e);
}
return collection;
}

private void handleResponse(Response response) throws IOException {
if (!response.isSuccessful()) {
int statusCode = response.code();
String responseBodyString = (response.body() != null) ? response.body().string() : null;
FailedRequestInfo failedRequestInfo = new FailedRequestInfo(statusCode, responseBodyString);
HttpErrorMapper.mapHttpStatusError(failedRequestInfo);
public String deleteCollection(String collectionName) throws ApiException {
String deleteResponse = null;
try {
deleteResponse = this.manageIndexesAPi.deleteCollection(collectionName);
}
catch (ApiException e) {
handleApiException(e);
}
return deleteResponse;
}

public void close() {
client.dispatcher().executorService().shutdown();
client.connectionPool().evictAll();
private void handleApiException(ApiException exception) throws PineconeException {
int statusCode = exception.getCode();
String responseBody = exception.getResponseBody();
FailedRequestInfo failedRequestInfo = new FailedRequestInfo(statusCode, responseBody);
HttpErrorMapper.mapHttpStatusError(failedRequestInfo);
}
}
Loading

0 comments on commit 63eaf79

Please sign in to comment.