Pinecone.net-это полностью отработанная библиотека C# для базы данных векторной векторной данных Pinecone.
Это библиотека сообщества, которая обеспечивает первоклассную поддержку Pinecone в C# и F#.
dotnet add package Pinecone.NET или Install-Package Pinecone.NET
Работа с индексами
using Pinecone ;
// Initialize the client with your API key
using var pinecone = new PineconeClient ( "your-api-key" ) ;
// List all indexes
var indexes = await pinecone . ListIndexes ( ) ;
// Create a new index if it doesn't exist
var indexName = "myIndex" ;
if ( ! indexes . Contains ( indexName ) )
{
await pinecone . CreateServerlessIndex ( indexName , 1536 , Metric . Cosine , "aws" , "us-east-1" ) ;
}
// Get the Pinecone index by name (uses REST by default).
// The index client is thread-safe, consider caching and/or
// injecting it as a singleton into your DI container.
using var index = await pinecone . GetIndex ( indexName ) ;
// Configure an index
await pinecone . ConfigureIndex ( indexName , replicas : 2 , podType : "p2" ) ;
// Delete an index
await pinecone . DeleteIndex ( indexName ) ;Работа с векторами
// Assuming you have an instance of `index`
// Create and upsert vectors
var vectors = new [ ]
{
new Vector
{
Id = "vector1" ,
Values = new float [ ] { 0.1f , 0.2f , 0.3f , .. . } ,
Metadata = new MetadataMap
{
[ "genre" ] = "horror" ,
[ "duration" ] = 120
}
}
} ;
await index . Upsert ( vectors ) ;
// Fetch vectors by IDs
var fetched = await index . Fetch ( [ "vector1" ] ) ;
// Query scored vectors by ID
var scored = await index . Query ( "vector1" , topK : 10 ) ;
// Query scored vectors by a new, previously unseen vector
var vector = new [ ] { 0.1f , 0.2f , 0.3f , .. . } ;
var scored = await index . Query ( vector , topK : 10 ) ;
// Query scored vectors by ID with metadata filter
var filter = new MetadataMap
{
[ "genre" ] = new MetadataMap
{
[ "$in" ] = new [ ] { "documentary" , "action" }
}
} ;
var scored = await index . Query ( "birds" , topK : 10 , filter ) ;
// Delete vectors by vector IDs
await index . Delete ( new [ ] { "vector1" } ) ;
// Delete vectors by metadata filter
await index . Delete ( new MetadataMap
{
[ "genre" ] = new MetadataMap
{
[ "$in" ] = new [ ] { "documentary" , "action" }
}
} ) ;
// Delete all vectors in the index
await index . DeleteAll ( ) ;Работа с коллекциями
using Pinecone ;
// Assuming you have an instance of `PineconeClient` named `pinecone`
// List all collections
var collections = await pinecone . ListCollections ( ) ;
// Create a new collection
await pinecone . CreateCollection ( "myCollection" , "myIndex" ) ;
// Describe a collection
var details = await pinecone . DescribeCollection ( "myCollection" ) ;
// Delete a collection
await pinecone . DeleteCollection ( "myCollection" ) ; Восстановление после сбоев на пакетном параллельном уровне
// Upsert with recovery from up to three failures on batched parallel upsert.
//
// The parallelization is done automatically by the client based on the vector
// dimension and the number of vectors to upsert. It aims to keep the individual
// request size below Pinecone's 2MiB limit with some safety margin for metadata.
// This behavior can be further controlled by calling the 'Upsert' overload with
// custom values for 'batchSize' and 'parallelism' parameters.
//
// This is not the most efficient implementation in terms of allocations in
// GC pause frequency sensitive scenarios, but is perfectly acceptable
// for pretty much all regular back-end applications.
// Assuming there is an instance of 'index' available
// Generate 25k random vectors
var vectors = Enumerable
. Range ( 0 , 25_000 )
. Select ( _ => new Vector
{
Id = Guid . NewGuid ( ) . ToString ( ) ,
Values = Enumerable
. Range ( 0 , 1536 )
. Select ( _ => Random . Shared . NextSingle ( ) )
. ToArray ( )
} )
. ToArray ( ) ;
// Specify the retry limit we are okay with
var retries = 3 ;
while ( true )
{
try
{
// Perform the upsert
await index . Upsert ( vectors ) ;
// If no exception is thrown, break out of the retry loop
break ;
}
catch ( ParallelUpsertException e ) when ( retries -- > 0 )
{
// Create a hash set to efficiently filter out the failed vectors
var filter = e . FailedBatchVectorIds . ToHashSet ( ) ;
// Filter out the failed vectors from the batch and assign them to
// the 'vectors' variable consumed by 'Upsert' operation above
vectors = vectors . Where ( v => filter . Contains ( v . Id ) ) . ToArray ( ) ;
Console . WriteLine ( $ "Retrying upsert due to error: { e . Message } " ) ;
}
} Аналогичный подход может быть использован для восстановления после других потоковых или пакетных операций.
См. ListOperationException , ParallelFetchException и ParallelDeleteException в Vectortypes.cs.
Предпочитаю RestTransport по умолчанию. Пожалуйста, найдите подробное объяснение конкретных сценариев ниже.
GrpcTransport является жизнеспособной альтернативой для снижения сетевого трафика при работе с большими векторами при сценариях пропускной способности низкой до умеренной пропускной способности.
Protobuf кодирует векторы гораздо более компактным образом, поэтому, если у вас есть высокоразмерные векторы (1536-3072+), низкая степень параллелизма запроса и, как правило, upsert или векторы в небольших бактах, стоит рассмотреть GrpcTransport для вашего использования.
Теоретически, низкая пропускная способность параллелизма может быть выше с GrpcTransport из -за уменьшенного сетевого трафика, но, поскольку то, насколько тривиально - просто отправлять несколько запросов на параллельные (и тот факт, что Fetch , Upsert и Delete делают это автоматически), преимущества этого подхода, вероятно, будут ограничены.
Во время написания стека HTTP/2 от PineCone настраивается, чтобы позволить мало или даже 1 одновременный поток на одно соединение HTTP/2.
Поскольку HTTP/2 является обязательным для GRPC, это вызывает значительную очередь запроса по каналу GRPC в сценариях высокой параллелистики, что приводит к плохой масштабируемости GrpcTransport с низким потолком для пропускной способности.
Пользователи, которые не знают об этом ограничении, могут испытывать неожиданное увеличение задержки в своих операциях запроса при растущем подсчете пользователей на узел приложения и/или намного ниже, чем ожидалось, UPSERT и получение пропускной способности, даже если вручную указывают большую степень параллелизма операций Upsert и Fetch .
Pinecone.NET частично смягчает эту проблему, настраивая канал GRPC, чтобы воспользоваться преимуществами балансировки нагрузки на стороне клиента (на основе DNS-записей), чтобы использовать несколько подканалов (в настоящее время 3 в качестве возврата с помощью DNS-запроса), что, как ожидается, обеспечит более высокую пропускную способность, чем другие клиенты. Это также позволяет использовать несколько подключений HTTP/2 на конечную точку для базового SocketsHttpHandler но текущая реализация GRPC, по -видимому, не использует это должным образом.
Выше приведено наблюдение за поведением клиента при тестировании нагрузки, а дополнительные факторы инфраструктуры могут быть в игре, как указано в пользовательских отчетах на масштабируемости WRT Forum Forum Forum Pinecone в других реализациях.
Экспертные пользователи, которые по-прежнему хотят использовать транспорт GRPC в сценариях с высокой загрузкой, могут захотеть изучить дальнейшие элементы действий, которые выходят из этой простой библиотеки, поддерживаемой сообществом:
Регулярным пользователям рекомендуется использовать RestTransport для высокопроизводительных и/или высоких сценариев параллелистики вместо этого, если только их оценка GrpcTransport в их конкретной среде не дает лучших результатов.
На данный момент RestTransport и System.Text.Json он использует для сериализации, по-видимому, более эффективными для памяти, чем GrpcTransport и Protobuf . Это не является неотъемлемым ограничением GRPC, а скорее результатом текущей реализации grpc-dotnet . System.Text.Json сильно оптимизирован в отношении трафика распределения и приводит к значительно более низкому постоянному использованию памяти как при легкой, так и при тяжелой нагрузке. Учитывая текущее состояние реализации grpc-dotnet , я не ожидаю, что это изменится в ближайшем будущем. Это «достаточно хорошо» для большинства приложений, но устойчивая разница в размерах кучи под нагрузкой достаточно значительна, чтобы оправдать это явно.
Обратите внимание, что Pinecone.NET уже выполняет конструкцию с нулевой копией/показания RepeatedField<float> , которые хранят векторные значения, чтобы облегчить давление распределения, но этого недостаточно, чтобы компенсировать преимущество использования простой System.Text.Json .
Взносы приветствуются! Не стесняйтесь открывать проблему или PR.