Wyszukiwanie wektorowe przy użyciu dostawców przechowywania wektorów

Biblioteka Microsoft.Extensions.VectorData udostępnia możliwości wyszukiwania wektorowego w ramach abstrakcji magazynu wektorów. Te możliwości obejmują filtrowanie i wiele innych opcji.

Metoda SearchAsync wykonuje wyszukiwanie podobieństwa, zwracając rekordy, których właściwość wektora jest najbardziej podobna do danej wartości. Przy założeniu, że masz już kolekcję zawierającą dane, oto minimalna próbka przedstawiająca wyszukiwanie wektorów przy użyciu funkcji 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);
}

Aby uzyskać więcej informacji na temat generowania osadzania, zobacz Właściwości wektora i generowanie osadzania.

Liczba wyników i pomijanie wyników

SearchAsync ma obowiązkowy top parametr, który kontroluje maksymalną liczbę rekordów zwracanych z wyszukiwania. Zawsze należy wziąć pod uwagę liczbę rekordów, które naprawdę potrzebujesz, ponieważ nadmierne pobieranie może zmniejszyć wydajność aplikacji.

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

Ponadto można pominąć rekordy opcjonalnie. Na przykład następujące wyszukiwanie zwraca 20 najbardziej odpowiednich produktów po pomijaniu 40:

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

top i Skip może służyć do wykonywania stronicowania w celu pobrania dużej liczby wyników przy użyciu oddzielnych wywołań. Jednak ta technika może nie działać dobrze w bazie danych, ponieważ nadal musi znajdować i przetwarzać pominięte rekordy. Aby uzyskać więcej informacji, zapoznaj się z dokumentacją bazy danych.

Filtrowanie metadanych

VectorSearchOptions<TRecord>.Filter Użyj opcji filtrowania rekordów w wybranej kolekcji przed zastosowaniem wyszukiwania wektorowego. Ma to wiele korzyści:

  • Zmniejsza opóźnienie i koszt przetwarzania, ponieważ należy porównać tylko rekordy pozostałe po filtrowaniu z wektorem wyszukiwania i dlatego należy wykonać mniej porównań wektorów.
  • Ogranicza zestaw wyników. Możesz na przykład zaimplementować kontrolę dostępu, wykluczając dane, do których użytkownik nie powinien mieć dostępu, lub wyszukiwać tylko w określonej kategorii produktów.

Aby pola były używane do filtrowania, wiele magazynów wektorów wymaga, aby te pola były najpierw indeksowane. Aby uzyskać więcej informacji na temat włączania indeksowania właściwości danych, zobacz Właściwość danych.

Filtry są wyrażane przy użyciu wyrażeń LINQ na podstawie typu modelu danych. Obsługiwany zestaw wyrażeń LINQ różni się w zależności od funkcji obsługiwanych przez każdą bazę danych, ale wszystkie bazy danych obsługują obszerną bazę typowych wyrażeń, na przykład równe, nierówne, and, i 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")
    });

Uwzględnij wektory w wynikach

Domyślnie właściwości wektorów nie są uwzględniane w wynikach wyszukiwania, co zmniejsza transfer danych. Wyszukiwanie można skonfigurować tak, aby obejmowało je:

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

Określanie właściwości wektora

W większości scenariuszy tylko jedna właściwość wektorowa jest definiowana w modelu danych i SearchAsync automatycznie wyszukuje ją. Jeśli jednak zdefiniowano wiele właściwości wektorów, należy określić, która z nich ma być używana:

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 });

Wyszukiwanie hybrydowe łączy wyszukiwanie wektorów z tradycyjnym wyszukiwaniem słów kluczowych, wykonując jednocześnie i zwracając kombinację dwóch zestawów wyników. Może to poprawić jakość wyszukiwania, ponieważ dopasowanie słów kluczowych pozwala wychwycić dokładne dopasowania terminów, które podobieństwo wektorów może pominąć, i odwrotnie.

Uwaga / Notatka

Wyszukiwanie hybrydowe jest dostępne tylko w bazach danych, które je obsługują. Tylko dostawcy dla tych baz danych implementują interfejs IKeywordHybridSearchable<TRecord>.

Aby użyć wyszukiwania hybrydowego, model danych wymaga pola ciągu z włączonym wyszukiwaniem pełnotekstowym za pomocą polecenia 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; }
}

Następnie wywołaj metodę HybridSearchAsync, przekazując zarówno tekst wyszukiwania, jak i słowa kluczowe:

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);

Wszystkie opcje opisane dla wyszukiwania wektorów (top, Skip, , FilterIncludeVectors, VectorProperty) są również dostępne do wyszukiwania hybrydowego za pośrednictwem .HybridSearchOptions<TRecord>

Ponadto wyszukiwanie hybrydowe obsługuje AdditionalProperty opcję określania, która właściwość wyszukiwania pełnotekstowego ma być docelowa. Jeśli model danych ma tylko jedną właściwość z elementem IsFullTextIndexed = true, jest używany automatycznie. Jeśli istnieje wiele, musisz określić, która z nich:

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
    });