Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Microsoft.Extensions.VectorData usa un approccio model-first per interagire con i database.
Tutti i metodi per eseguire l'upsert o ottenere i record usano classi di modelli fortemente tipizzato. Esistono due modi per definire il modello di dati:
- Decorating properties on the model classes with attributes that indicate the purpose of each property.
- Definendo lo schema di archiviazione usando una definizione di record fornita separatamente dal modello di dati. La definizione del record è un oggetto VectorStoreCollectionDefinition che contiene proprietà.
Di seguito è riportato un esempio di una classe o di un modello di dati le cui proprietà sono decorate con VectorStore*Attribute attributi.
public class Hotel
{
[VectorStoreKey]
public ulong HotelId { get; set; }
[VectorStoreData(IsIndexed = true)]
public required string HotelName { get; set; }
[VectorStoreData(IsFullTextIndexed = true)]
public required string Description { get; set; }
[VectorStoreVector(Dimensions: 4, DistanceFunction = DistanceFunction.CosineSimilarity, IndexKind = IndexKind.Hnsw)]
public ReadOnlyMemory<float>? DescriptionEmbedding { get; set; }
[VectorStoreData(IsIndexed = true)]
public required string[] Tags { get; set; }
}
Proprietà del modello di dati
Annotazioni
I tipi di proprietà .NET supportati per chiavi, dati e vettori variano in base ai database. Per informazioni sui tipi supportati, vedere la documentazione del provider di archivi vettoriali scelto.
Proprietà chiave
Ogni modello di dati deve avere una proprietà chiave che identifica in modo univoco ogni record nella raccolta.
Usare l'attributo VectorStoreKeyAttribute per indicare che la proprietà è la chiave primaria del record.
[VectorStoreKey]
public ulong HotelId { get; set; }
La tabella seguente illustra i parametri per VectorStoreKeyAttribute.
| Parametro | Obbligatorio | Descrizione |
|---|---|---|
| IsAutoGenerated | No | Indica se il valore della chiave viene generato automaticamente dal database. Il valore predefinito è false. |
| StorageName | No | Può essere utilizzato per specificare un nome alternativo per la proprietà nel database. Questo parametro non è supportato da tutti i provider, ad esempio, in cui sono supportate alternative come JsonPropertyNameAttribute . |
Proprietà dati
Le proprietà dei dati contengono contenuto generico, ad esempio testo, tag o altri metadati recuperati durante la ricerca di record e possono essere indicizzati anche per il filtro.
Usare l'attributo VectorStoreDataAttribute per indicare che la proprietà contiene dati generali che non sono una chiave o un vettore.
[VectorStoreData(IsIndexed = true)]
public required string HotelName { get; set; }
La tabella seguente illustra i parametri per VectorStoreDataAttribute.
| Parametro | Obbligatorio | Descrizione |
|---|---|---|
| IsIndexed | No | Indica se la proprietà deve essere indicizzata per il filtro nei casi in cui un database richiede il consenso esplicito per l'indicizzazione per proprietà. Il valore predefinito è false. |
| IsFullTextIndexed | No | Indica se la proprietà deve essere indicizzata per la ricerca full-text per i database che supportano la ricerca full-text. Il valore predefinito è false. |
| StorageName | No | Può essere utilizzato per specificare un nome alternativo per la proprietà nel database. Questo parametro non è supportato da tutti i provider, ad esempio, in cui sono supportate alternative come JsonPropertyNameAttribute . |
Proprietà Vector
Le proprietà vettoriali contengono i vettori di incorporamento usati per la ricerca di somiglianza; negli scenari avanzati, un modello di dati può avere più proprietà vettoriali per supportare la ricerca su diversi aspetti del record.
Usare l'attributo VectorStoreVectorAttribute per indicare che la proprietà contiene un vettore.
[VectorStoreVector(Dimensions: 4, DistanceFunction = DistanceFunction.CosineSimilarity, IndexKind = IndexKind.Hnsw)]
public ReadOnlyMemory<float>? DescriptionEmbedding { get; set; }
È anche possibile usare VectorStoreVectorAttribute su proprietà che non hanno un tipo vettore, ad esempio una proprietà di tipo string. Quando una proprietà viene decorata in questo modo, è necessario fornire un'istanza IEmbeddingGenerator all'archivio vettoriale. Quando si esegue l'upserting del record, il testo presente nella string proprietà viene convertito e archiviato automaticamente come vettore nel database. Non è possibile recuperare un vettore usando questo meccanismo.
[VectorStoreVector(Dimensions: 4, DistanceFunction = DistanceFunction.CosineSimilarity, IndexKind = IndexKind.Hnsw)]
public string DescriptionEmbedding { get; set; }
Suggerimento
Per altre informazioni su come usare la generazione incorporata di incorporamento, vedere Proprietà vettoriali e generazione di incorporamento.
La tabella seguente illustra i parametri per VectorStoreVectorAttribute.
| Parametro | Obbligatorio | Descrizione |
|---|---|---|
| Dimensions | Sì | Numero di dimensioni del vettore. Questa operazione è necessaria quando si crea un indice vettoriale per una raccolta. |
| IndexKind | No | Tipo di indice con cui indicizzare il vettore. Il valore predefinito varia in base al tipo di archivio vettoriale. |
| DistanceFunction | No | Tipo di funzione da usare quando si esegue il confronto tra vettori durante la ricerca vettoriale su questo vettore. Il valore predefinito varia in base al tipo di archivio vettoriale. |
| StorageName | No | Può essere utilizzato per specificare un nome alternativo per la proprietà nel database. Questo parametro non è supportato da tutti i provider, ad esempio, in cui sono supportate alternative come JsonPropertyNameAttribute . |
I tipi di funzione di indice e di distanza comuni vengono forniti come valori statici nelle IndexKind classi e DistanceFunction . Le singole implementazioni dell'archivio vettoriale possono anche usare i propri tipi di indice e funzioni di distanza, in cui il database supporta tipi insoliti.
Proprietà vettoriali e generazione di incorporamento
I database vettoriali riguardano l'archiviazione di incorporamenti, o rappresentazioni numeriche dei dati, generati da un modello di incorporamento. Durante l'archiviazione o la ricerca di dati, è necessario prima eseguire la generazione di incorporamenti per convertire i dati ricercabili in tali incorporamenti. MEVD offre due approcci per la generazione di incorporamento: manuale e automatico.
Generazione di incorporamento manuale e di basso livello
È possibile definire la proprietà vettoriale come float[] o ReadOnlyMemory<float>, che rappresenta direttamente l'incorporamento e generare incorporamenti manualmente prima di ogni operazione:
[VectorStoreVector(Dimensions: 1536)]
public ReadOnlyMemory<float>? DescriptionEmbedding { get; set; }
Durante la ricerca, si genererà l'incorporamento per il testo della query e lo si passerà a SearchAsync:
ReadOnlyMemory<float> searchEmbedding =
(await embeddingGenerator.GenerateAsync("Find a happy hotel")).Vector;
var searchResult = collection.SearchAsync(searchEmbedding, top: 3);
Anche se funziona, è necessario gestire la generazione di incorporamento in ogni sito di chiamata.
Generazione automatica di incorporamento (scelta consigliata)
L'approccio consigliato consiste nel configurare un oggetto nell'archivio IEmbeddingGenerator<TInput,TEmbedding> vettoriale. In questo modo è possibile definire la proprietà vector usando il tipo di origine ( ad esempio , string) invece di float[] o ReadOnlyMemory<float>. MEVD gestisce quindi automaticamente la generazione di incorporamento durante le operazioni di upsert e di ricerca.
Prima di tutto, definire la proprietà vector come string:
[VectorStoreVector(Dimensions: 1536)]
public string DescriptionEmbedding { get; set; }
Configurare quindi un generatore di incorporamento durante la creazione dell'archivio vettoriale:
VectorStore vectorStore = new QdrantVectorStore(
new QdrantClient("localhost"),
ownsClient: true,
new QdrantVectorStoreOptions
{
EmbeddingGenerator = embeddingGenerator
});
È ora possibile passare il testo direttamente: MEVD genera incorporamenti sotto le quinte:
// Search with a plain text query - embedding is generated automatically.
var searchResult = collection.SearchAsync("Find a happy hotel", top: 3);
Importante
Le proprietà vettoriali configurate in questo modo non supportano il recupero del vettore generato o del testo originale dal database. Se è necessario archiviare il testo originale, aggiungere una proprietà dati separata.
I generatori di incorporamento possono anche essere configurati a livello di raccolta, definizione di record o proprietà vettoriale individuale. Diversi modelli di incorporamento supportano dimensioni vettoriali diverse; assicurarsi che il Dimensions valore corrisponda al modello configurato. Per altre informazioni sull'incorporamento dei generatori e sulle astrazioni Microsoft.Extensions.AI, vedere Embeddings in .NET.
Mapping dinamico a un dizionario .NET
In alcuni casi non è consigliabile o possibile eseguire il mapping di un tipo di .NET fortemente tipizzato al database. Si supponga, ad esempio, di non conoscere in fase di compilazione l'aspetto dello schema del database e che lo schema venga fornito solo tramite la configurazione. La creazione di un tipo di .NET che riflette lo schema sarebbe impossibile in questo caso. È invece possibile eseguire il mapping in modo dinamico usando un Dictionary<string, object?> oggetto per il tipo di record. Le proprietà vengono aggiunte a con la Dictionary chiave come nome della proprietà e il valore come valore della proprietà.
Annotazioni
La maggior parte delle app userà semplicemente tipi di .NET fortemente tipizzato per modellare i dati. Il mapping dinamico tramite Dictionary<string, object?> è per scenari avanzati e arbitrari di mapping dei dati.
Fornire informazioni sullo schema quando si usa Dictionary
Quando si usa un Dictionary, i provider devono comunque conoscere l'aspetto dello schema del database. Senza le informazioni sullo schema, il provider non sarebbe in grado di creare una raccolta o sapere come eseguire il mapping da e verso la rappresentazione di archiviazione usata da ogni database.
È possibile usare una definizione di record per fornire le informazioni sullo schema. A differenza di un modello di dati, è possibile creare una definizione di record dalla configurazione in fase di esecuzione quando le informazioni sullo schema non sono note in fase di compilazione.
Esempio
Per usare Dictionary con un provider, specificarlo come modello di dati quando si crea la raccolta. Specificare anche una definizione di record.
VectorStoreCollectionDefinition definition = new()
{
Properties =
[
new VectorStoreKeyProperty("Key", typeof(string)),
new VectorStoreDataProperty("Term", typeof(string)),
new VectorStoreDataProperty("Definition", typeof(string)),
new VectorStoreVectorProperty("DefinitionEmbedding", typeof(ReadOnlyMemory<float>), dimensions: 1536)
]
};
// Use GetDynamicCollection instead of the regular GetCollection method
// to get an instance of a collection using Dictionary<string, object?>.
VectorStoreCollection<object, Dictionary<string, object?>> dynamicDataModelCollection =
vectorStore.GetDynamicCollection("glossary", definition);
// Since schema information is available from the record definition,
// it's possible to create a collection with the right vectors,
// dimensions, indexes, and distance functions.
await dynamicDataModelCollection.EnsureCollectionExistsAsync();
// When retrieving a record from the collection,
// access key, data, and vector values via the dictionary entries.
Dictionary<string, object?>? record = await dynamicDataModelCollection.GetAsync("SK");
Console.WriteLine(record["Definition"]);