Skip to content

Generate code for 2025-04, automate ndjson handling, add backups, restore, and namespaces. #183

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

Merged
merged 5 commits into from
May 9, 2025
Merged
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

[comment]: <> (When bumping [pc:VERSION_LATEST_RELEASE] create a new entry below)
### Unreleased version
### 5.0.0
- Add support for backups and restore
- Add support for list, describe, and delete namespaces
- Generate code based on 2025-04 api spec
- Automate ndjson handling

### 4.0.1
- Create a new config per index connection

Expand Down
133 changes: 130 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,20 @@ Maven:
<dependency>
<groupId>io.pinecone</groupId>
<artifactId>pinecone-client</artifactId>
<version>4.0.0</version>
<version>5.0.0</version>
</dependency>
```

[comment]: <> (^ [pc:VERSION_LATEST_RELEASE])

Gradle:
```
implementation "io.pinecone:pinecone-client:4.0.0"
implementation "io.pinecone:pinecone-client:5.0.0"
```

[comment]: <> (^ [pc:VERSION_LATEST_RELEASE])

Alternatively, you can use our standalone uberjar [pinecone-client-4.0.0-all.jar](https://repo1.maven.org/maven2/io/pinecone/pinecone-client/4.0.0/pinecone-client-4.0.0-all.jar), which bundles the Pinecone
Alternatively, you can use our standalone uberjar [pinecone-client-5.0.0-all.jar](https://repo1.maven.org/maven2/io/pinecone/pinecone-client/5.0.0/pinecone-client-5.0.0-all.jar), which bundles the Pinecone
SDK and all dependencies together. You can include this in your classpath like you do with any 3rd party JAR without
having to obtain the *pinecone-client* dependencies separately.

Expand Down Expand Up @@ -521,6 +521,74 @@ List<Float> values = Arrays.asList(1F, 2F, 3F);
UpdateResponse updateResponse = index.update("v1", values, "example-namespace");
```

## List namespaces

The following example shows various methods to list namespaces.

```java
import io.pinecone.clients.AsyncIndex;
import io.pinecone.clients.Index;
import io.pinecone.clients.Pinecone;
import io.pinecone.proto.ListNamespacesResponse;

import java.util.concurrent.ExecutionException;
...

String indexName = "PINECONE_INDEX_NAME";
Pinecone pinecone = new Pinecone.Builder("PINECONE_API_KEY").build();
Index index = pinecone.getIndexConnection(indexName);

// list namespaces without pagination token and limit (if no limit is passed, it'll default to 100)
ListNamespacesResponse listNamespacesResponse = index.listNamespaces();

// list namespaces with pagination token
listNamespacesResponse = index.listNamespaces("some-pagination-token");

// list namespaces with pagination token and a custom limit of 5
listNamespacesResponse = index.listNamespaces("some-pagination-token", 5);
```

## Describe namespace

The following example shows how to describe a namespace.

```java
import io.pinecone.clients.AsyncIndex;
import io.pinecone.clients.Index;
import io.pinecone.clients.Pinecone;
import io.pinecone.proto.NamespaceDescription;

import java.util.concurrent.ExecutionException;
...

String indexName = "PINECONE_INDEX_NAME";
Pinecone pinecone = new Pinecone.Builder("PINECONE_API_KEY").build();
Index index = pinecone.getIndexConnection(indexName);

// describe a namespace
NamespaceDescription namespaceDescription = index.describeName("some-namespace");
```

## Delete namespace

The following example shows how to describe a namespace.

```java
import io.pinecone.clients.AsyncIndex;
import io.pinecone.clients.Index;
import io.pinecone.clients.Pinecone;

import java.util.concurrent.ExecutionException;
...

String indexName = "PINECONE_INDEX_NAME";
Pinecone pinecone = new Pinecone.Builder("PINECONE_API_KEY").build();
Index index = pinecone.getIndexConnection(indexName);

// delete a namespace
index.deleteName("some-namespace");
```

# Collections

Collections fall under control plane operations.
Expand Down Expand Up @@ -766,6 +834,65 @@ AsyncIndex asyncIndex = pinecone.getAsyncIndexConnection("PINECONE_INDEX_NAME");
// Cancel import
asyncIndex.cancelImport("2");
```
# Backups and restore

The following example shows how to backup and restore from a serverless index.

```java
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.ApiException;
import org.openapitools.db_control.client.model.*;

...

Pinecone pinecone = new Pinecone.Builder("PINECONE_API_KEY").build();

String indexName1 = "test-index-1";
String indexName2 = "test-index-2";

// create a backup from index
BackupModel backupModel1 = pinecone.createBackup(indexName1, "backup-id-1", "description-for-backup-1");
System.out.println("backupModel1: " + backupModel1);

BackupModel backupModel2 = pinecone.createBackup(indexName2, "backup-id-2", "description-for-backup-2");
System.out.println("backupModel2: " + backupModel2);

// list all backups for an index
BackupList backupList = pinecone.listIndexBackups(indexName1);
System.out.println("backupList for index1: " + backupList);

// list all backups for a project
backupList = pinecone.listProjectBackups();
System.out.println("backupList for project: " + backupList);

// describe backup
backupModel1 = pinecone.describeBackup(backupModel1.getBackupId());
System.out.println("describe backup for index1: " + backupModel1);

backupModel2 = pinecone.describeBackup(backupModel2.getBackupId());
System.out.println("describe backup index2: " + backupModel2);

// delete backup
pinecone.deleteBackup(backupModel1.getBackupId());

// wait for the backup to be ready
Thread.sleep(10000);

// create index from a backup
CreateIndexFromBackupResponse backupResponse = pinecone.createIndexFromBackup(backupModel1.getBackupId(), "test-index-3");
System.out.println(backupResponse.getRestoreJobId());

// wait for index to be created
Thread.sleep(5000);

// describeRestoreJob
RestoreJobModel restoreJobModel = pinecone.describeRestoreJob(backupResponse.getRestoreJobId());
System.out.println("restore model: " + restoreJobModel);

// listRestoreJobs
RestoreJobList restoreJobList = pinecone.listRestoreJobs(2);
System.out.println("restore job list: " + restoreJobList);
```

## Examples

Expand Down
2 changes: 1 addition & 1 deletion codegen/apis
Submodule apis updated from 63e97d to daf808
2 changes: 1 addition & 1 deletion codegen/buf.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ breaking:
deps:
- buf.build/googleapis/googleapis
modules:
- path: apis/_build/2025-01
- path: apis/_build/2025-04
3 changes: 3 additions & 0 deletions codegen/build-grpc.sh
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,8 @@ rm -rf "${dest}*.java"
# Copy the new generated files to dest directory
cp codegen/gen/java/io/pinecone/proto/*.java ${dest}

# Update version reference in PineconeConnection.java
sed -i '' "s/[0-9][0-9][0-9][0-9]-[0-1][0-9]/${version}/g" src/main/java/io/pinecone/configs/PineconeConnection.java

# Cleanup the intermediate files that were generated
rm -rf codegen/gen
21 changes: 21 additions & 0 deletions codegen/build-oas.sh
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,27 @@ generate_client() {
find "${destination}/${module_name}" -name "*.java" | while IFS= read -r file; do
sed -i '' "s/org\.openapitools\.client/org\.openapitools\.${module_name}\.client/g" "$file"
done

# Add NDJSON block to ApiClient.java in the db_data module
if [ "$module_name" == "db_data" ]; then
echo "Adding NDJSON handler block to ApiClient.java"

# Use sed to insert the NDJSON block into ApiClient.java
sed -i '' '/return RequestBody.create((File) obj, MediaType.parse(contentType));/a \
} else if ("application/x-ndjson".equals(contentType)) { \
// Handle NDJSON (Newline Delimited JSON) \
if (obj instanceof Iterable) { \
StringBuilder ndjsonContent = new StringBuilder(); \
for (Object item : (Iterable<?>) obj) { \
String json = JSON.serialize(item); \
ndjsonContent.append(json).append("\\n"); \
} \
return RequestBody.create(ndjsonContent.toString(), MediaType.parse(contentType)); \
} else { \
throw new ApiException("NDJSON content requires a collection of objects."); \
} \
' src/main/java/org/openapitools/db_data/client/ApiClient.java
fi
}

update_apis_repo
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
pineconeClientVersion = 4.0.1
pineconeClientVersion = 5.0.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package io.pinecone.integration.dataPlane;

import io.pinecone.clients.AsyncIndex;
import io.pinecone.clients.Index;
import io.pinecone.helpers.RandomStringBuilder;
import io.pinecone.helpers.TestResourcesManager;
import io.pinecone.proto.ListNamespacesResponse;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Test;

import java.util.concurrent.ExecutionException;

import static io.pinecone.helpers.BuildUpsertRequest.generateVectorValuesByDimension;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class NamespacesTest {
private static final TestResourcesManager indexManager = TestResourcesManager.getInstance();
private static Index index;
private static AsyncIndex asyncIndex;
private static final int dimension = indexManager.getDimension();

@AfterAll
public static void cleanUp() {
index.close();
asyncIndex.close();
}

@Test
public void namespacesSyncTest() throws InterruptedException {
String[] namespaces = new String[3];
index = indexManager.getOrCreateServerlessIndexConnection();
ListNamespacesResponse listNamespacesResponse = index.listNamespaces();
int namespaceCount = listNamespacesResponse.getNamespacesCount();

for(int i=0; i<3; i++) {
namespaces[i] = RandomStringBuilder.build("namespace-", 3);
index.upsert("v"+i, generateVectorValuesByDimension(dimension), namespaces[i]);
}

// wait for vectors to be upserted
Thread.sleep(5000);
listNamespacesResponse = index.listNamespaces();
assertEquals(listNamespacesResponse.getNamespacesCount(), namespaceCount + 3);

index.describeNamespace(namespaces[0]);
index.deleteNamespace(namespaces[0]);

// wait for namespace to be deleted
Thread.sleep(3000);
listNamespacesResponse = index.listNamespaces();
assertEquals(listNamespacesResponse.getNamespacesCount(), namespaceCount + 2);
}

@Test
public void namespacesAsyncTest() throws InterruptedException, ExecutionException {
String[] namespaces = new String[3];
asyncIndex = indexManager.getOrCreateServerlessAsyncIndexConnection();

ListNamespacesResponse listNamespacesResponse = asyncIndex.listNamespaces().get();
int namespaceCount = listNamespacesResponse.getNamespacesCount();

for(int i=0; i<3; i++) {
namespaces[i] = RandomStringBuilder.build("namespace-", 3);
asyncIndex.upsert("v"+i, generateVectorValuesByDimension(dimension), namespaces[i]);
}

// wait for vectors to be upserted
Thread.sleep(5000);
listNamespacesResponse = asyncIndex.listNamespaces().get();
assertEquals(listNamespacesResponse.getNamespacesCount(), namespaceCount + 3);

asyncIndex.describeNamespace(namespaces[0]);
asyncIndex.deleteNamespace(namespaces[0]);

// wait for namespace to be deleted
Thread.sleep(3000);
listNamespacesResponse = asyncIndex.listNamespaces().get();
assertEquals(listNamespacesResponse.getNamespacesCount(), namespaceCount + 2);
}
}
Loading
Loading