Compartilhar via


Pesquisa de vetor usando provedores de repositório de vetores

A biblioteca Microsoft.Extensions.VectorData fornece recursos de pesquisa de vetor como parte de suas abstrações de repositório de vetores. Esses recursos incluem filtragem e muitas outras opções.

O SearchAsync método executa uma pesquisa de similaridade, retornando registros cuja propriedade de vetor é mais semelhante a um determinado valor. Supondo que você tenha uma coleção que já contenha dados, aqui está um exemplo mínimo mostrando a pesquisa de vetor 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);
}

Para obter mais informações sobre a geração de inserção, consulte as propriedades do Vector e a geração de inserção.

Número de resultados e resultados ignorados

SearchAsync tem um parâmetro obrigatório top que controla o número máximo de registros retornados da pesquisa. Sempre considere quantos registros de maior relevância você realmente precisa, pois a coleta excessiva de dados pode reduzir o desempenho do aplicativo.

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

Além disso, opcionalmente, você pode ignorar registros. Por exemplo, a pesquisa a seguir retorna os 20 produtos mais relevantes depois de ignorar 40:

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

top e Skip podem ser usados para executar paginação para recuperar um grande número de resultados por meio de chamadas separadas. No entanto, essa técnica pode não funcionar bem em seu banco de dados, pois ainda deve encontrar e processar os registros ignorados. Para obter mais informações, consulte a documentação do banco de dados.

Filtragem de metadados

Use a opção VectorSearchOptions<TRecord>.Filter para filtrar os registros na coleção escolhida antes de aplicar a pesquisa de vetor. Isso tem vários benefícios:

  • Reduz a latência e o custo de processamento, pois somente os registros restantes após a filtragem precisam ser comparados com o vetor de pesquisa e, portanto, menos comparações de vetor precisam ser feitas.
  • Limita o conjunto de resultados. Por exemplo, você pode implementar o controle de acesso excluindo dados aos quais o usuário não deve ter acesso ou pesquisar apenas dentro de uma categoria específica de produtos.

Para que os campos sejam usados para filtragem, muitos repositórios de vetores exigem que esses campos sejam indexados primeiro. Para obter mais informações sobre como habilitar a indexação em propriedades de dados, consulte a propriedade Data.

Os filtros são expressos usando expressões LINQ com base no tipo do modelo de dados. O conjunto de expressões LINQ com suporte varia dependendo da funcionalidade suportada por cada banco de dados, mas todos os bancos de dados dão suporte a uma base ampla de expressões comuns, por exemplo, iguais, não iguais e andor.

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

Incluir vetores nos resultados

Por padrão, as propriedades de vetor não são incluídas nos resultados da pesquisa, o que reduz a transferência de dados. Você pode configurar a pesquisa para incluí-las:

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

Especifique a propriedade vetorial

Na maioria dos cenários, apenas uma única propriedade de vetor é definida no modelo de dados e SearchAsync pesquisa automaticamente nele. No entanto, quando várias propriedades de vetor são definidas, você deve especificar qual deve ser usada:

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

A pesquisa híbrida combina a pesquisa de similaridade de vetor com a pesquisa de palavra-chave tradicional, executando em paralelo e retornando uma combinação dos dois conjuntos de resultados. Isso pode melhorar a qualidade da pesquisa, já que a correspondência de palavras-chave pode capturar correspondências exatas de termos que a similaridade do vetor pode perder e vice-versa.

Observação

A pesquisa híbrida só está disponível em bancos de dados que dão suporte a ela. Somente os provedores desses bancos de dados implementam a IKeywordHybridSearchable<TRecord> interface.

Para usar a pesquisa híbrida, seu modelo de dados precisa de um campo de texto com pesquisa de texto completo habilitada por meio de 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; }
}

Em seguida, chame HybridSearchAsync, passando texto de pesquisa e palavras-chave:

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

Todas as opções descritas para pesquisa de vetor (top, , Skip, Filter, IncludeVectors, VectorProperty) também estão disponíveis para pesquisa híbrida via HybridSearchOptions<TRecord>.

Além disso, a pesquisa híbrida dá suporte a uma AdditionalProperty opção para especificar qual propriedade de pesquisa de texto completo deseja direcionar. Se o modelo de dados tiver apenas uma propriedade com IsFullTextIndexed = true, ela será usada automaticamente; se houver várias, especifique qual:

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