Pnecone.net ist eine vollwertige C# -Bibliothek für die Pinecone-Vektor-Datenbank.
Dies ist eine Community-Bibliothek, die erstklassige Unterstützung für Pinecone in C# und F# bietet.
dotnet add package Pinecone.NET oder Install-Package Pinecone.NET hinzufügen
Arbeiten mit Indizes
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 ) ;Arbeiten mit Vektoren
// 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 ( ) ;Arbeiten mit Sammlungen
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" ) ; Erholung von Fehlern bei einem angegriffenen parallelen Höhenmesser
// 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 } " ) ;
}
} Ein ähnlicher Ansatz kann verwendet werden, um sich von anderen gestreamten oder gegründeten Operationen zu erholen.
Siehe ListOperationException , ParallelFetchException und ParallelDeleteException in vectortypes.cs.
Bevorzugen Sie standardmäßig RestTransport . Die detaillierte Erklärung finden Sie im folgenden Szenarien.
GrpcTransport ist eine praktikable Alternative zur Reduzierung des Netzwerkverkehrs bei der Arbeit mit großen Vektoren unter niedrigen bis moderaten Durchsatzszenarien.
Protobuf codiert Vektoren viel kompaktere Weise. Wenn Sie also über hochdimensionale Vektoren (1536-3072+) verfügen, ist ein geringer Antragsgrad der Parallelität und in der Regel Vektoren in kleinen Bakthes, wenn Sie GrpcTransport für Ihren Anwendungsfall in Betracht ziehen.
Theoretisch kann ein geringer Parallelitätsdurchsatz aufgrund des reduzierten Netzwerkverkehrs mit GrpcTransport höher sein, aber da es trivial ist, mehrere Anforderungen parallel zu entsenden (und die Tatsache, dass Fetch , Upsert und Delete automatisch tun), sind die Vorteile dieses Ansatzes wahrscheinlich begrenzt.
Zum Zeitpunkt des Schreibens ist der HTTP/2 -Stack von Pinecone so konfiguriert, dass nur wenige oder sogar nur 1 gleichzeitige Stream pro einzelner HTTP/2 -Anschluss.
Da HTTP/2 für GRPC obligatorisch ist, führt dies zu einer signifikanten Anfrage zu einem GRPC -Kanal unter hohen Parallelitätsszenarien, was zu einer schlechten Skalierbarkeit des GrpcTransport mit niedriger Decke für den Durchsatz führt.
Die Benutzer, die sich dieser Begrenzung nicht bewusst sind, können eine unerwartete Latenzanstieg in ihren Abfragvorgängen unter wachsender Benutzerzahl pro Anwendungsknoten verzeichnen und/oder viel niedriger als erwartungsgemäß und durch den Durchsatz des Durchsatzes, auch wenn sie einen höheren Grad an Parallelität von Upsert und Fetch manuell angeben.
Pinecone.NET mindert dieses Problem teilweise, indem es den GRPC-Kanal so konfiguriert, dass sie den Client-Seite-Lastausgleich (DNS-Datensätze basieren) nutzen, um mehrere Subkanäle zu nutzen (derzeit gibt es 3, die von DNS-Query zurückgegeben werden), was voraussichtlich einen besseren Durchsatz bietet als noch andere Clients. Es ermöglicht auch die Verwendung mehrerer HTTP/2 -Verbindungen pro Endpunkt für die zugrunde liegende SocketsHttpHandler , aber die aktuelle GRPC -Implementierung scheint dies nicht ordnungsgemäß zu nutzen.
Die oben genannte Beobachtung des Kundenverhaltens unter Lastentests und zusätzliche Infrastrukturfaktoren könnten durch Benutzerberichte im Community-Forum-Skalierbarkeit von Pinecone in anderen Implementierungen angezeigt werden.
Expertenbenutzer, die weiterhin den GRPC-Transport in hochladigen Szenarien verwenden möchten, möchten möglicherweise weitere Aktionselemente untersuchen, die aus dem Rahmen dieser einfachen von der Community unterstützten Bibliothek liegen:
Es wird regelmäßigen Benutzern empfohlen, RestTransport stattdessen für Hochdurchsatz- und/oder hohe Parallelitätsszenarien zu verwenden, es sei denn, die Bewertung von GrpcTransport in ihrer spezifischen Umgebung führt zu besseren Ergebnissen.
Im Moment scheinen RestTransport und System.Text.Json , das für die Serialisierung verwendet wird, speichereffizienter als GrpcTransport und Protobuf zu sein. Dies ist keine inhärente Einschränkung von GRPC, sondern ein Ergebnis der aktuellen Implementierung von grpc-dotnet . System.Text.Json ist im Hinblick auf den Allokationsverkehr stark optimiert und führt zu einer erheblich niedrigeren anhaltenden Speicherverwendung sowohl unter leichter als auch bei schwerer Belastung. Angesichts des aktuellen Standes der Implementierung von grpc-dotnet -Implementierung erwarte ich nicht, dass sich dies in naher Zukunft ändert. Für die meisten Anwendungen ist es "gut genug", aber der anhaltende Unterschied zwischen Haufen unter Last ist signifikant genug, um dies ausdrücklich anzugeben.
Bitte beachten Sie, dass Pinecone.NET bereits Konstruktion/Lesung von RepeatedField<float> null kopieren, die Vektorwerte speichern, um den Zuordnungsdruck zu lindern. Es reicht jedoch nicht aus, den Vorteil der Verwendung von Plain System.Text.Json Serialisierung auszugleichen.
Beiträge sind willkommen! Fühlen Sie sich frei, ein Problem oder ein PR zu öffnen.