Skip to content

Releases: pinecone-io/pinecone-dotnet-client

v4.0.1

15 May 18:45
5e1b448
Compare
Choose a tag to compare

Pinecone .NET SDK 4.0.1 Release Notes

This release adds the API for listing backups for a specific index.

using Pinecone;

var pinecone = new PineconeClient("PINECONE_API_KEY");
var backups = await pinecone.Backups.ListByIndexAsync("index-name", new ListBackupsByIndexRequest());
foreach (var backup in backups.Data)
{
    Console.WriteLine($"BackupId: {backup.BackupId}");
    Console.WriteLine($"Name: {backup.Name}");
    Console.WriteLine($"CreatedAt: {backup.CreatedAt}");
    Console.WriteLine($"Status: {backup.Status}");
    Console.WriteLine($"RecordCount: {backup.RecordCount}");
}

Full Changelog: 4.0.0...4.0.1

v4.0.0

14 May 15:01
34cea65
Compare
Choose a tag to compare

Pinecone .NET SDK 4.0.0 Release Notes

This release introduces APIs for namespace management, backup and restore for indexes, and listing of available models.

Breaking Changes

  • CreateIndexRequestMetric has been renamed to MetricType for better consistency.
  • CreateIndexForModelRequestEmbedMetric has been renamed to MetricType
  • ModelIndexEmbedMetric has been renamed to MetricType
  • SparseEmbedding.SparseIndices type has changed from IEnumerable<int> to IEnumerable<long>

New Features

Namespace Management

Namespaces provide logical separation of data within your indexes. You don't need to explicitly create namespaces before using them - they're automatically created when you upsert records.

List Namespaces

using Pinecone;

var pinecone = new PineconeClient("PINECONE_API_KEY");
var index = pinecone.Index("example-index");
var namespaces = await index.ListNamespacesAsync(new ListNamespacesRequest());

foreach(var @namespace in namespaces.Namespaces)
{
    Console.WriteLine($"Namespace: {@namespace.Name}");
    Console.WriteLine($"Record Count: {@namespace.RecordCount}");
}

Describe a Namespace

using Pinecone;

var pinecone = new PineconeClient("PINECONE_API_KEY");
var index = pinecone.Index("example-index");
var @namespace = await index.DescribeNamespaceAsync("namespace-name");

Console.WriteLine($"Namespace: {@namespace.Name}");
Console.WriteLine($"Record Count: {@namespace.RecordCount}");

Delete a Namespace

using Pinecone;

var pinecone = new PineconeClient("PINECONE_API_KEY");
var index = pinecone.Index("example-index");
await index.DeleteNamespaceAsync("namespace-name");

Backup and Restore Operations

New backup functionality enables data protection and migration scenarios.

Backup an Index

using Pinecone;

var pinecone = new PineconeClient("PINECONE_API_KEY");
var backup = await pinecone.Backups.BackupIndexAsync("index-name", new BackupIndexRequest());

Restore a Backup

using Pinecone;

var pinecone = new PineconeClient("PINECONE_API_KEY");
var response = await pinecone.Backups.CreateIndexFromBackupAsync("backup-id", new CreateIndexFromBackupRequest {
    Name = "new-index-name"
});

Console.WriteLine($"Restore Job ID: {response.RestoreJobId}");
Console.WriteLine($"New Index ID: {response.IndexId}");

Get a Backup

using Pinecone;

var pinecone = new PineconeClient("PINECONE_API_KEY");
var backup = await pinecone.Backups.GetAsync("backup-id");

List Backups

using Pinecone;

var pinecone = new PineconeClient("PINECONE_API_KEY");
var backups = await pinecone.Backups.ListAsync();

foreach (var backup in backups.Data)
{
    Console.WriteLine($"BackupId: {backup.BackupId}");
    Console.WriteLine($"Name: {backup.Name}");
    Console.WriteLine($"CreatedAt: {backup.CreatedAt}");
    Console.WriteLine($"Status: {backup.Status}");
    Console.WriteLine($"RecordCount: {backup.RecordCount}");
}

Delete Backup

using Pinecone;

var pinecone = new PineconeClient("PINECONE_API_KEY");
await pinecone.Backups.DeleteAsync("backup-id");

Restore Jobs

Track and manage the progress of index restore operations.

List Restore Jobs

using Pinecone;

var pinecone = new PineconeClient("PINECONE_API_KEY");
var jobs = await pinecone.RestoreJobs.ListAsync(new ListRestoreJobsRequest());

foreach(var job in jobs.Data)
{
    Console.WriteLine($"Restore Job ID: {job.RestoreJobId}");
    Console.WriteLine($"Status: {job.Status}");
    Console.WriteLine($"CreatedAt: {job.CreatedAt}");
    Console.WriteLine($"TargetIndexName: {job.TargetIndexName}");
}

Get Restore Job

using Pinecone;

var pinecone = new PineconeClient("PINECONE_API_KEY");
var job = await pinecone.RestoreJobs.GetAsync("job-id");

Console.WriteLine($"Restore Job ID: {job.RestoreJobId}");
Console.WriteLine($"Status: {job.Status}");
Console.WriteLine($"CreatedAt: {job.CreatedAt}");
Console.WriteLine($"TargetIndexName: {job.TargetIndexName}");

Models

Access and manage embedding models directly through the SDK.

List Available Models

using Pinecone;
using Pinecone.Inference;

var pinecone = new PineconeClient("PINECONE_API_KEY");
var models = await pinecone.Inference.Models.ListAsync(new ListModelsRequest());

foreach (var model in models.Models)
{
    Console.WriteLine($"Name: {model.Model}");
    Console.WriteLine($"Type: {model.Type}");
    Console.WriteLine($"Vector type: {model.VectorType}");
}

Get Specific Model

using Pinecone;

var pinecone = new PineconeClient("PINECONE_API_KEY");
var model = await pinecone.Inference.Models.GetAsync("pinecone-sparse-english-v0");

Console.WriteLine($"Name: {model.Model}");
Console.WriteLine($"Type: {model.Type}");
Console.WriteLine($"Vector type: {model.VectorType}");

Migration Guide

The renaming of various metric types to MetricType requires updating any code that creates indexes. If you're using CreateIndexRequestMetric, CreateIndexForModelRequestEmbedMetric, or ModelIndexEmbedMetric in your code, you'll need to update those to MetricType.

Full Changelog: 3.1.0...4.0.0

v3.1.0

15 Apr 18:17
fc0dc16
Compare
Choose a tag to compare

Pinecone .NET SDK 3.1.0 Release Notes

This release introduces new record-based APIs that simplify working with Pinecone indexes, especially for semantic search applications. These new APIs allow you to focus on your data rather than vector details, making the SDK more accessible for application developers.

New Features

Record-Based APIs

Two new endpoints have been added that offer a simplified interface for working with Pinecone:

UpsertRecordsAsync

await client.UpsertRecordsAsync(
    namespace,
    [
        new UpsertRecord
        {
            Id = "rec1",
            AdditionalProperties =
            {
                ["chunk_text"] = "Your text content here",
                ["category"] = "Your category",
            },
        },
        // Additional records...
    ]
);
  • Allows direct insertion of records with structured data
  • Automatically handles vector embedding behind the scenes
  • Supports custom metadata through AdditionalProperties dictionary

SearchRecordsAsync

var response = await client.SearchRecordsAsync(
    namespace,
    new SearchRecordsRequest
    {
        Query = new SearchRecordsRequestQuery
        {
            TopK = 4,
            Inputs = new Dictionary<string, object?> { { "text", "Your search query" } },
        },
        Fields = ["category", "chunk_text"],
    }
);
  • Search using natural language queries instead of vectors
  • Specify which fields to include in the response
  • Automatically handles query embedding and vector similarity search

Migration Guide

These new APIs are complementary to the existing vector-based APIs. If you're building semantic search applications, we recommend using these new record-based APIs for a more streamlined development experience.

Full Changelog: 3.0.0...3.1.0

v3.0.0 Release

03 Feb 16:21
a420d98
Compare
Choose a tag to compare

This release updates the SDK for Pinecone API version 2025-01. It introduces new features, several breaking changes, and improvements to the Pinecone .NET Client.

New Features

Support for Sparse Indexes

Pinecone's API now lets you create sparse indexes.
Here's an example of how to use the Pinecone SDK with sparse vectors.

using Pinecone;

// Initialize Pinecone client with your API key
var pinecone = new PineconeClient(Environment.GetEnvironmentVariable("PINECONE_API_KEY"));


var indexName = "test-sparse-index";

// Create a sparse serverless index
Console.WriteLine("Creating serverless index...");
await pinecone.CreateIndexAsync(new CreateIndexRequest
{
    Name = indexName,
    VectorType = VectorType.Sparse,
    Spec = new ServerlessIndexSpec
    {
        Serverless = new ServerlessSpec
        {
            Cloud = ServerlessSpecCloud.Aws,
            Region = "us-east-1",
        }
    }
});

// Wait for index to be ready
Console.WriteLine("Waiting for index to be ready...");
while (true)
{
    var indexInfo = await pinecone.DescribeIndexAsync(indexName);
    if (indexInfo.Status.State == IndexModelStatusState.Ready)
    {
        break;
    }

    Console.WriteLine("Index not ready yet, waiting...");
    await Task.Delay(TimeSpan.FromSeconds(2));
}

// Get index instance
var index = pinecone.Index(indexName);

// Prepare sparse vector data
var sparseIndices = new uint[] { 1, 2 };
var sparseValues = new ReadOnlyMemory<float>([1f, 2f]);

// Create vector with sparse values
var vector = new Vector
{
    Id = "v1",
    SparseValues = new SparseValues
    {
        Indices = sparseIndices,
        Values = sparseValues
    }
};

// Upsert vector
Console.WriteLine("Upserting vector...");
var upsertResponse = await index.UpsertAsync(new UpsertRequest
{
    Vectors = new List<Vector> { vector }
});
Console.WriteLine($"Upserted {upsertResponse.UpsertedCount} vector");

// Query by vector ID
Console.WriteLine("Querying vector by ID...");
var queryResponse = await index.QueryAsync(new QueryRequest
{
    Id = vector.Id,
    TopK = 1,
    IncludeValues = true,
});
// Note: It can take up to 1 minute before upserted records are available to query.
// https://docs.pinecone.io/guides/indexes/sparse-indexes#upsert-sparse-vectors

// Display query results
Console.WriteLine("Query results:");
foreach (var match in queryResponse.Matches)
{
    Console.WriteLine($"ID: {match.Id}");
    if (match.SparseValues != null)
    {
        var indicesString = string.Join(", ", match.SparseValues.Indices);
        Console.WriteLine($"Sparse Indices: [{indicesString}]");
        var valuesString = string.Join(", ", match.SparseValues.Values.ToArray());
        Console.WriteLine($"Sparse Values: [{valuesString}]");
    }
}

// Delete the index
Console.WriteLine("Deleting index...");
await pinecone.DeleteIndexAsync(indexName);
Console.WriteLine("Index deleted successfully");

New Operations

  • client.CreateIndexForModelAsync(CreateIndexForModelRequest { ... }) -> Index

Breaking Changes

Embedding Type Changes

The Embedding type has changed from a simple object to a discriminated union, supporting both DenseEmbedding and SparseEmbedding. This change provides better type safety but requires code updates.

New helper methods available on the Embedding type:

  • IsDense & IsSparse - Type checking
  • AsDense() & AsSparse() - Type conversion
  • Match() and Visit() - Pattern matching

Example of updating your code:

// Before
Embedding embedding = GetEmbedding();
foreach (var value in embedding.Values.Span)
{
    Console.WriteLine(value);
}

// After
Embedding embedding = GetEmbedding();
switch (embedding.VectorType)
{
    case VectorType.Dense:
        DenseEmbedding denseEmbedding = embedding.AsDense();
        foreach (var value in denseEmbedding.Values.Span)
        {
            Console.WriteLine(value);
        }
        break;
    case VectorType.Sparse:
        SparseEmbedding sparseEmbedding = embedding.AsSparse();
        foreach (var value in sparseEmbedding.SparseValues.Span)
        {
            Console.WriteLine(value);
        }
        break;
}

Type Changes

EmbedRequest

The Parameters property now uses Dictionary<string, object?>? instead of EmbedRequestParameters:

public record EmbedRequest
{
    public Dictionary<string, object?>? Parameters { get; set; }
}

RankedDocument

The Document property now uses Dictionary<string, object?>? instead of Dictionary<string, string>?:

public record RankedDocument
{
    public Dictionary<string, object?>? Document { get; set; }
}

RerankRequest

Update property types for more flexibility:

public record RerankRequest
{
    public IEnumerable<Dictionary<string, object?>> Documents { get; set; }
    public Dictionary<string, object?>? Parameters { get; set; }
}

Optional Properties

The following properties are now nullable:

  • Index.Dimension: int?
  • Index.Tags: Dictionary<string, string>?
  • PodSpec.Replicas: int?
  • PodSpec.Shards: int?
  • PodSpec.Pods: int?
  • Vector.Values: int?

Migration Guide

  1. Update embedding handling code to use the new discriminated union pattern
  2. Replace EmbedRequestParameters usage with Dictionary<string, object?>?
  3. Update code handling RankedDocument to work with object values
  4. Review and update code that assumes non-nullable properties for Index and PodSpec
  5. Update RerankRequest implementations to use the new parameter types

Full Changelog: 2.1.0...3.0.0

v2.1.0 Release

04 Dec 19:53
9268fbf
Compare
Choose a tag to compare

This version of the Pinecone .NET Client introduces the ClientOptions.IsTlsEnabled property which you are required to set to false if you want to test the Client against an HTTP endpoint.

Features

IsTlsEnabled

Parts of the Client dynamically retrieve API hostnames to interact with which default to using HTTPS. To have the Client default to using HTTP instead, you can set the ClientOptions.IsTlsEnabled to false.

Now you can use the Pinecone Client against a local HTTP URL:

using Pinecone;

var pinecone = new PineconeClient("PINECONE_API_KEY",
    new ClientOptions
    {
        BaseUrl = "http://localhost:5080",
        IsTlsEnabled = false
    }
);

// Create serverless index
await pinecone.CreateIndexAsync(new CreateIndexRequest
{
    Name = "serverless-index",
    Dimension = 3,
    Metric = CreateIndexRequestMetric.Cosine,
    Spec = new ServerlessIndexSpec
    {
        Serverless = new ServerlessSpec
        {
            Cloud = ServerlessSpecCloud.Aws,
            Region = "us-east-1",
        }
    },
    DeletionProtection = DeletionProtection.Disabled
});

// Create pod index
await pinecone.CreateIndexAsync(new CreateIndexRequest
{
    Name = "pod-index",
    Dimension = 3,
    Metric = CreateIndexRequestMetric.Cosine,
    Spec = new PodIndexSpec
    {
        Pod = new PodSpec
        {
            Environment = "us-east-1-aws",
            PodType = "p1.x1",
            Pods = 1,
            Replicas = 1,
            Shards = 1,
        }
    },
    DeletionProtection = DeletionProtection.Disabled
});

// Describe serverless index
await pinecone.DescribeIndexAsync("serverless-index");

// Describe pod index
await pinecone.DescribeIndexAsync("pod-index");

// Get index connection object for serverless-index
var serverlessIndexConnection = pinecone.Index("serverless-index");

// Get index connection object for pod-index
var podIndexConnection = pinecone.Index("pod-index");

// Upsert records into serverless index
await serverlessIndexConnection.UpsertAsync(new UpsertRequest()
{
    Namespace = "v1",
    Vectors = new List<Vector>
    {
        new Vector { Id = "1", Values = new ReadOnlyMemory<float>([1f, 2f, 3f]) }
    }
});

// Upsert records into pod index
await podIndexConnection.UpsertAsync(new UpsertRequest()
{
    Namespace = "v1",
    Vectors = new List<Vector>
    {
        new Vector { Id = "1", Values = new ReadOnlyMemory<float>([1f, 2f, 3f]) }
    }
});

// Query by vectorId from serverless index
await serverlessIndexConnection.QueryAsync(new QueryRequest
{
    TopK = 10,
    Id = "3",
    Namespace = "v1",
});

// Query by vectorId from pod index
await podIndexConnection.QueryAsync(new QueryRequest
{
    TopK = 10,
    Id = "3",
    Namespace = "v1",
});

// Delete serverless index
await pinecone.DeleteIndexAsync("serverless-index");


// Delete pod index
await pinecone.DeleteIndexAsync("pod-index");

What's Changed

Full Changelog: 2.0.0...2.1.0

v2.0.0 Release

14 Nov 20:28
fd63e1d
Compare
Choose a tag to compare

This version of the Pinecone .NET SDK introduces inference and imports. It also supports version 2024-10 of the Pinecone API. You can read more about versioning here.

Features

Embed

The Inference has an operation called Embed which allows users to generate embeddings for input data.

using Pinecone;

var pinecone = new PineconeClient("PINECONE_API_KEY");

// Prepare input sentences to be embedded
List<EmbedRequestInputsItem> inputs =
[
    new()
    {
        Text = "The quick brown fox jumps over the lazy dog."
    },
    new()
    {
        Text = "Lorem ipsum"
    }
];

// Specify the embedding model and parameters
var embeddingModel = "multilingual-e5-large";

// Generate embeddings for the input data
var embeddings = await pinecone.Inference.EmbedAsync(new EmbedRequest()
{
    Model = embeddingModel,
    Inputs = inputs,
    Parameters = new EmbedRequestParameters()
    {
        InputType = "query",
        Truncate = "END"
    }
});

// Get embedded data
var embeddedData = embeddings.Data;

Rerank

The Inference has another operation called Rerank which provides users the ability to rerank documents in descending relevance-order against a given query. Reranking documents is a common "second-pass" ranking strategy broadly used in retrieval applications.

using Pinecone;

var pinecone = new PineconeClient("PINECONE_API_KEY");

// The model to use for reranking
var model = "bge-reranker-v2-m3";

// The query to rerank documents against
var query = "The tech company Apple is known for its innovative products like the iPhone.";

// Add the documents to rerank
var documents = new List<Dictionary<string, string>>
{
    new()
    {
        ["id"] = "vec1",
        ["my_field"] = "Apple is a popular fruit known for its sweetness and crisp texture."
    },
    new()
    {
        ["id"] = "vec2",
        ["my_field"] = "Many people enjoy eating apples as a healthy snack."
    },
    new()
    {
        ["id"] = "vec3",
        ["my_field"] =
            "Apple Inc. has revolutionized the tech industry with its sleek designs and user-friendly interfaces."
    },
    new()
    {
        ["id"] = "vec4",
        ["my_field"] = "An apple a day keeps the doctor away, as the saying goes."
    }
};

// The fields to rank the documents by. If not provided, the default is "text"
var rankFields = new List<string> { "my_field" };

// The number of results to return sorted by relevance. Defaults to the number of inputs
int topN = 2;

// Whether to return the documents in the response
bool returnDocuments = true;

// Additional model-specific parameters for the reranker
var parameters = new Dictionary<string, string>
{
    ["truncate"] = "END"
};

// Send ranking request
var result = await pinecone.Inference.RerankAsync(
    new RerankRequest
    {
        Model = model,
        Query = query,
        Documents = documents,
        RankFields = rankFields,
        TopN = topN,
        Parameters = parameters
    });

// Get ranked data
var data = result.Data;

Import

Index now exposes additional methods for working with import operations. An import is a long-running, asynchronous operation that gives users the ability to import vectors directly from object storage (e.g. S3) into a Pinecone index. It is intended to be used with large-scale jobs. For small-scale jobs (e.g. <1000 vectors), we recommend continuing to use upsert.

using Pinecone;

...

// Initialize pinecone object
var pinecone = new PineconeClient("PINECONE_API_KEY");

// Get async imports connection object
var index = pinecone.Index("PINECONE_INDEX_NAME");

// s3 uri
var uri = "s3://path/to/file.parquet";

// Start an import
var startImportResponse = await index.StartBulkImportAsync(new StartImportRequest
{
    Uri = uri,
    IntegrationId = "123-456-789",
    ErrorMode = new ImportErrorMode { OnError = ImportErrorModeOnError.Continue }
});

// List imports
var listimportResponse = await index.ListBulkImportsAsync(new ListBulkImportsRequest
{
    Limit = 100,
    PaginationToken = "some-pagination-token"
});

// Describe import
var importDetails = await index.DescribeBulkImportAsync("1");

// Cancel import
var cancelResponse = await index.CancelBulkImportAsync("2");

v1.0.0 Release

26 Aug 19:05
b0dff95
Compare
Choose a tag to compare

This is the first public release of the Pinecone .NET client. The client supports both control and data plane operations for pods, serverless, and free-tier indexes. Below are the supported operations:

Control Plane Operations:

  1. Index Operations:
    1. Create Index
    2. List Index
    3. Describe Index
    4. Delete Index
    5. Configure Index
  2. Collection Operations:
    1. Create Collection
    2. List Collection
    3. Describe Collection
    4. Delete Collection

Data Plane Operations:

  1. Upsert Vectors
  2. Query Vectors
  3. Fetch Vectors
  4. Update Vectors
  5. Delete Vectors
  6. List Vectors
  7. Get Index Stats

Please note that all data plane operations use gRPC, while control plane operations use REST. Users also have the ability to configure retries, timeouts, and the HTTP proxy. For detailed information on how to use the client, please refer to the README.

1.0.0-rc.1

23 Aug 21:11
57400f8
Compare
Choose a tag to compare
1.0.0-rc.1 Pre-release
Pre-release

Initial release.