Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add collections requests to PineconeIndexOperationClient #61

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignore this, was using it locally.

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
Loading