Condividi tramite


Ricerca vettoriale con fornitori di store vettoriali

La libreria Microsoft.Extensions.VectorData offre funzionalità di ricerca vettoriale come parte delle astrazioni dell'archivio vettoriale. Queste funzionalità includono il filtro e molte altre opzioni.

Il SearchAsync metodo esegue una ricerca di somiglianza, restituendo record la cui proprietà vector è più simile a un determinato valore. Supponendo di avere una raccolta che contiene già dati, di seguito è riportato un esempio minimo che mostra la ricerca vettoriale usando Qdrant:

// Create a Qdrant VectorStore object and get a VectorStoreCollection for a collection that already contains records
VectorStore vectorStore = new QdrantVectorStore(new QdrantClient("localhost"), ownsClient: true);
VectorStoreCollection<ulong, Hotel> collection = vectorStore.GetCollection<ulong, Hotel>("skhotels");

// Get the 3 hotels whose vector property is most similar to the query text
IAsyncEnumerable<VectorSearchResult<Hotel>> results = collection.SearchAsync("Big rooms with a view", top: 3);

// Inspect the returned hotels and their similarity scores
await foreach (VectorSearchResult<Hotel> record in results)
{
    Console.WriteLine("Found hotel description: " + record.Record.Description);
    Console.WriteLine("Found record score: " + record.Score);
}

Per altre informazioni sulla generazione di incorporamento, vedere Proprietà vettoriali e generazione di incorporamento.

Numero di risultati e risultati saltati

SearchAsync ha un parametro obbligatorio top che controlla il numero massimo di record restituiti dalla ricerca. Considerare sempre quanti record principali sono effettivamente necessari, perché l'overfetching può ridurre le prestazioni dell'applicazione:

IAsyncEnumerable<VectorSearchResult<Hotel>> searchResult = collection.SearchAsync("Big rooms with a view", top: 3);

Inoltre, è possibile scegliere di ignorare i record. Ad esempio, la ricerca seguente restituisce i 20 prodotti più rilevanti dopo aver ignorato 40:

IAsyncEnumerable<VectorSearchResult<Product>> results = collection.SearchAsync(
    "Green socks",
    top: 20,
    new() { Skip = 40 });

top e Skip possono essere usati per eseguire il paging per recuperare un numero elevato di risultati usando chiamate separate. Tuttavia, questa tecnica potrebbe non funzionare correttamente nel database, perché deve comunque trovare ed elaborare i record ignorati. Per altre informazioni, vedere la documentazione del database.

Filtro dei metadati

Usare l'opzione VectorSearchOptions<TRecord>.Filter per filtrare i record nella raccolta scelta prima di applicare la ricerca vettoriale. Questo offre diversi vantaggi:

  • Riduce la latenza e i costi di elaborazione, poiché è necessario confrontare solo i record rimanenti dopo il filtro con il vettore di ricerca e quindi è necessario eseguire un minor numero di confronti vettoriali.
  • Limita il set di risultati. Ad esempio, è possibile implementare il controllo di accesso escludendo i dati a cui l'utente non deve avere accesso o eseguire ricerche solo all'interno di una categoria specifica di prodotti.

Per i campi da usare per filtrare, molti archivi vettoriali richiedono prima di tutto l'indicizzazione di tali campi. Per altre informazioni su come abilitare l'indicizzazione sulle proprietà dei dati, vedere Proprietà dati.

I filtri vengono espressi usando espressioni LINQ in base al tipo del modello di dati. Il set di espressioni LINQ supportate varia a seconda delle funzionalità supportate da ogni database, ma tutti i database supportano un'ampia base di espressioni comuni, ad esempio uguale, non uguale, ande or.

class Glossary
{
    // ...

    // Category is marked as indexed, since you want to filter using this property.
    [VectorStoreData(IsIndexed = true)]
    public required string Category { get; set; }

    // Tags is marked as indexed, since you want to filter using this property.
    [VectorStoreData(IsIndexed = true)]
    public required List<string> Tags { get; set; }
}

IAsyncEnumerable<VectorSearchResult<Glossary>> results = collection.SearchAsync(
    "Some term",
    top: 3,
    new()
    {
        Filter = r => r.Category == "External Definitions" && r.Tags.Contains("memory")
    });

Includere vettori nei risultati

Per impostazione predefinita, le proprietà vettoriali non sono incluse nei risultati della ricerca, riducendo così il trasferimento dei dati. È possibile configurare la ricerca per includerle:

IAsyncEnumerable<VectorSearchResult<Product>> results = collection.SearchAsync(
    "Green socks",
    top: 3,
    new() { IncludeVectors = true });

Specificare la proprietà vettoriale

Nella maggior parte degli scenari viene definita solo una singola proprietà vettoriale nel modello di dati e SearchAsync ne esegue automaticamente la ricerca. Tuttavia, quando vengono definite più proprietà vettoriali, è necessario specificare quale deve essere usato:

class Product
{
    // ...

    // Multiple vector properties:
    [VectorStoreVector(1536)]
    public ReadOnlyMemory<float> DescriptionEmbedding { get; set; }

    [VectorStoreVector(1536)]
    public ReadOnlyMemory<float> FeatureListEmbedding { get; set; }
}

IAsyncEnumerable<VectorSearchResult<Hotel>> results = collection.SearchAsync(
    "I'm looking for a product with a specific feature.",
    top: 3,
    new() { VectorProperty = r => r.FeatureListEmbedding });

La ricerca ibrida combina la ricerca di somiglianza vettoriale con la ricerca di parole chiave tradizionale, eseguendo sia in parallelo che restituendo una combinazione dei due set di risultati. Ciò può migliorare la qualità della ricerca, poiché la corrispondenza delle parole chiave può acquisire corrispondenze esatte di termini che la somiglianza vettoriale potrebbe non rilevare e viceversa.

Annotazioni

La ricerca ibrida è disponibile solo nei database che lo supportano. Solo i provider per questi database implementano l'interfaccia IKeywordHybridSearchable<TRecord> .

Per usare la ricerca ibrida, il modello di dati richiede un campo stringa con la ricerca full-text abilitata tramite IsFullTextIndexed:

class Hotel
{
    [VectorStoreKey]
    public ulong Key { get; set; }

    [VectorStoreData(IsFullTextIndexed = true)]
    public required string Description { get; set; }

    [VectorStoreVector(1536)]
    public string DescriptionEmbedding { get; set; }
}

Quindi, chiamare HybridSearchAsync passando sia il testo di ricerca che le parole chiave.

var hybridCollection = (IKeywordHybridSearchable<Hotel>)collection;

IAsyncEnumerable<VectorSearchResult<Hotel>> results = hybridCollection.HybridSearchAsync(
    "I'm looking for a hotel where customer happiness is the priority.",
    ["happiness", "hotel", "customer"],
    top: 3);

Tutte le opzioni descritte per la ricerca vettoriale (, , top, , Skip) sono disponibili anche per la ricerca ibrida tramite Filter. IncludeVectorsVectorPropertyHybridSearchOptions<TRecord>

Inoltre, la ricerca ibrida supporta un'opzione AdditionalProperty per specificare quale proprietà di ricerca full-text da prendere di mira. Se il modello di dati ha una sola proprietà con IsFullTextIndexed = true, viene usato automaticamente; se sono presenti più, è necessario specificare quale:

IAsyncEnumerable<VectorSearchResult<Hotel>> results = hybridCollection.HybridSearchAsync(
    "I'm looking for a hotel where customer happiness is the priority.",
    ["happiness", "hotel", "customer"],
    top: 3,
    new()
    {
        VectorProperty = r => r.DescriptionEmbedding,
        AdditionalProperty = r => r.Description
    });