diff --git a/pom.xml b/pom.xml index cdbfe43f26b..a048368e8bc 100644 --- a/pom.xml +++ b/pom.xml @@ -184,7 +184,7 @@ 8.13.3 2.3.4 2.3.0 - 0.8.0 + 2.1.0 2.0.46 11.6.1 4.5.1 diff --git a/vector-stores/spring-ai-pinecone-store/src/main/java/org/springframework/ai/vectorstore/PineconeVectorStore.java b/vector-stores/spring-ai-pinecone-store/src/main/java/org/springframework/ai/vectorstore/PineconeVectorStore.java index 59a7f7ff8e1..bc11d5108b4 100644 --- a/vector-stores/spring-ai-pinecone-store/src/main/java/org/springframework/ai/vectorstore/PineconeVectorStore.java +++ b/vector-stores/spring-ai-pinecone-store/src/main/java/org/springframework/ai/vectorstore/PineconeVectorStore.java @@ -16,7 +16,6 @@ package org.springframework.ai.vectorstore; -import java.time.Duration; import java.util.List; import java.util.Map; import java.util.Optional; @@ -43,15 +42,11 @@ import com.google.protobuf.util.JsonFormat; import io.micrometer.observation.ObservationRegistry; -import io.pinecone.PineconeClient; -import io.pinecone.PineconeClientConfig; -import io.pinecone.PineconeConnection; -import io.pinecone.PineconeConnectionConfig; -import io.pinecone.proto.DeleteRequest; -import io.pinecone.proto.QueryRequest; -import io.pinecone.proto.QueryResponse; -import io.pinecone.proto.UpsertRequest; -import io.pinecone.proto.Vector; +import io.pinecone.clients.Index; +import io.pinecone.clients.Pinecone; +import io.pinecone.unsigned_indices_model.QueryResponseWithUnsignedIndices; +import io.pinecone.unsigned_indices_model.VectorWithUnsignedIndices; +import static io.pinecone.commons.IndexInterface.buildUpsertVectorWithUnsignedIndices; /** * A VectorStore implementation backed by Pinecone, a cloud-based vector database. This @@ -72,7 +67,9 @@ public class PineconeVectorStore extends AbstractObservationVectorStore { private final EmbeddingModel embeddingModel; - private final PineconeConnection pineconeConnection; + private final Pinecone pinecone; + + private final Index index; private final String pineconeNamespace; @@ -91,6 +88,8 @@ public class PineconeVectorStore extends AbstractObservationVectorStore { */ public static final class PineconeVectorStoreConfig { + private final String apiKey; + // The free tier (gcp-starter) doesn't support Namespaces. // Leave the namespace empty (e.g. "") for the free tier. private final String namespace; @@ -99,32 +98,18 @@ public static final class PineconeVectorStoreConfig { private final String distanceMetadataFieldName; - private final PineconeConnectionConfig connectionConfig; - - private final PineconeClientConfig clientConfig; + private final String indexName; - // private final int defaultSimilarityTopK; - - /** - * Constructor using the builder. - * @param builder The configuration builder. - */ /** * Constructor using the builder. * @param builder The configuration builder. */ public PineconeVectorStoreConfig(Builder builder) { + this.apiKey = builder.apiKey; this.namespace = builder.namespace; this.contentFieldName = builder.contentFieldName; this.distanceMetadataFieldName = builder.distanceMetadataFieldName; - - // this.defaultSimilarityTopK = builder.defaultSimilarityTopK; - this.connectionConfig = new PineconeConnectionConfig().withIndexName(builder.indexName); - this.clientConfig = new PineconeClientConfig().withApiKey(builder.apiKey) - .withEnvironment(builder.environment) - .withProjectName(builder.projectId) - .withApiKey(builder.apiKey) - .withServerSideTimeoutSec((int) builder.serverSideTimeout.toSeconds()); + this.indexName = builder.indexName; } /** @@ -146,10 +131,6 @@ public static class Builder { private String apiKey; - private String projectId; - - private String environment; - private String indexName; // The free-tier (gcp-starter) doesn't support Namespaces! @@ -159,12 +140,6 @@ public static class Builder { private String distanceMetadataFieldName = DISTANCE_METADATA_FIELD_NAME; - /** - * Optional server-side timeout in seconds for all operations. Default: 20 - * seconds. - */ - private Duration serverSideTimeout = Duration.ofSeconds(20); - private Builder() { } @@ -178,26 +153,6 @@ public Builder withApiKey(String apiKey) { return this; } - /** - * Pinecone project id. - * @param projectId Project id to use. - * @return this builder. - */ - public Builder withProjectId(String projectId) { - this.projectId = projectId; - return this; - } - - /** - * Pinecone environment name. - * @param environment Environment name (e.g. gcp-starter). - * @return this builder. - */ - public Builder withEnvironment(String environment) { - this.environment = environment; - return this; - } - /** * Pinecone index name. * @param indexName Pinecone index name to use. @@ -239,16 +194,6 @@ public Builder withDistanceMetadataFieldName(String distanceMetadataFieldName) { return this; } - /** - * Pinecone server side timeout. - * @param serverSideTimeout server timeout to use. - * @return this builder. - */ - public Builder withServerSideTimeout(Duration serverSideTimeout) { - this.serverSideTimeout = serverSideTimeout; - return this; - } - /** * {@return the immutable configuration} */ @@ -285,10 +230,11 @@ public PineconeVectorStore(PineconeVectorStoreConfig config, EmbeddingModel embe this.embeddingModel = embeddingModel; this.pineconeNamespace = config.namespace; - this.pineconeIndexName = config.connectionConfig.getIndexName(); + this.pineconeIndexName = config.indexName; this.pineconeContentFieldName = config.contentFieldName; this.pineconeDistanceMetadataFieldName = config.distanceMetadataFieldName; - this.pineconeConnection = new PineconeClient(config.clientConfig).connect(config.connectionConfig); + this.pinecone = new Pinecone.Builder(config.apiKey).build(); + this.index = pinecone.getIndexConnection(pineconeIndexName); this.objectMapper = new ObjectMapper(); this.batchingStrategy = batchingStrategy; } @@ -300,20 +246,13 @@ public PineconeVectorStore(PineconeVectorStoreConfig config, EmbeddingModel embe */ public void add(List documents, String namespace) { this.embeddingModel.embed(documents, EmbeddingOptionsBuilder.builder().build(), this.batchingStrategy); - List upsertVectors = documents.stream() - .map(document -> Vector.newBuilder() - .setId(document.getId()) - .addAllValues(EmbeddingUtils.toList(document.getEmbedding())) - .setMetadata(metadataToStruct(document)) - .build()) - .toList(); - UpsertRequest upsertRequest = UpsertRequest.newBuilder() - .addAllVectors(upsertVectors) - .setNamespace(namespace) - .build(); + List upsertVectors = documents.stream() + .map(document -> buildUpsertVectorWithUnsignedIndices(document.getId(), + EmbeddingUtils.toList(document.getEmbedding()), null, null, metadataToStruct(document))) + .toList(); - this.pineconeConnection.getBlockingStub().upsert(upsertRequest); + this.index.upsert(upsertVectors, namespace); } /** @@ -361,13 +300,7 @@ private Value contentValue(Document document) { */ public Optional delete(List documentIds, String namespace) { - DeleteRequest deleteRequest = DeleteRequest.newBuilder() - .setNamespace(namespace) // ignored for free tier. - .addAllIds(documentIds) - .setDeleteAll(false) - .build(); - - this.pineconeConnection.getBlockingStub().delete(deleteRequest); + this.index.deleteByIds(documentIds, namespace); // The Pinecone delete API does not provide deletion status info. return Optional.of(true); @@ -390,17 +323,15 @@ public List similaritySearch(SearchRequest request, String namespace) float[] queryEmbedding = this.embeddingModel.embed(request.getQuery()); - var queryRequestBuilder = QueryRequest.newBuilder() - .addAllVector(EmbeddingUtils.toList(queryEmbedding)) - .setTopK(request.getTopK()) - .setIncludeMetadata(true) - .setNamespace(namespace); - + QueryResponseWithUnsignedIndices queryResponse = null; if (StringUtils.hasText(nativeExpressionFilters)) { - queryRequestBuilder.setFilter(metadataFiltersToStruct(nativeExpressionFilters)); + queryResponse = this.index.queryByVector(request.getTopK(), EmbeddingUtils.toList(queryEmbedding), + namespace, metadataFiltersToStruct(nativeExpressionFilters)); + } + else { + queryResponse = this.index.queryByVector(request.getTopK(), EmbeddingUtils.toList(queryEmbedding), + namespace); } - - QueryResponse queryResponse = this.pineconeConnection.getBlockingStub().query(queryRequestBuilder.build()); return queryResponse.getMatchesList() .stream() diff --git a/vector-stores/spring-ai-pinecone-store/src/test/java/org/springframework/ai/vectorstore/PineconeVectorStoreIT.java b/vector-stores/spring-ai-pinecone-store/src/test/java/org/springframework/ai/vectorstore/PineconeVectorStoreIT.java index a0f8a257cd9..0fe354d3a92 100644 --- a/vector-stores/spring-ai-pinecone-store/src/test/java/org/springframework/ai/vectorstore/PineconeVectorStoreIT.java +++ b/vector-stores/spring-ai-pinecone-store/src/test/java/org/springframework/ai/vectorstore/PineconeVectorStoreIT.java @@ -281,8 +281,6 @@ public PineconeVectorStoreConfig pineconeVectorStoreConfig() { return PineconeVectorStoreConfig.builder() .withApiKey(System.getenv("PINECONE_API_KEY")) - .withEnvironment(PINECONE_ENVIRONMENT) - .withProjectId(PINECONE_PROJECT_ID) .withIndexName(PINECONE_INDEX_NAME) .withNamespace(PINECONE_NAMESPACE) .withContentFieldName(CUSTOM_CONTENT_FIELD_NAME) diff --git a/vector-stores/spring-ai-pinecone-store/src/test/java/org/springframework/ai/vectorstore/PineconeVectorStoreObservationIT.java b/vector-stores/spring-ai-pinecone-store/src/test/java/org/springframework/ai/vectorstore/PineconeVectorStoreObservationIT.java index 8fc6b41f774..4f5ee34b9fd 100644 --- a/vector-stores/spring-ai-pinecone-store/src/test/java/org/springframework/ai/vectorstore/PineconeVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-pinecone-store/src/test/java/org/springframework/ai/vectorstore/PineconeVectorStoreObservationIT.java @@ -188,8 +188,6 @@ public PineconeVectorStoreConfig pineconeVectorStoreConfig() { return PineconeVectorStoreConfig.builder() .withApiKey(System.getenv("PINECONE_API_KEY")) - .withEnvironment(PINECONE_ENVIRONMENT) - .withProjectId(PINECONE_PROJECT_ID) .withIndexName(PINECONE_INDEX_NAME) .withNamespace(PINECONE_NAMESPACE) .withContentFieldName(CUSTOM_CONTENT_FIELD_NAME)