次の方法で共有


ベクター ストア プロバイダーを使用したベクター検索

Microsoft.Extensions.VectorData ライブラリは、ベクター ストアの抽象化の一部としてベクター検索機能を提供します。 これらの機能には、フィルター処理やその他の多くのオプションが含まれます。

ヒント

埋め込みを生成せずに検索する方法については、「 ベクター ストアで埋め込みを生成できるようにする」を参照してください。

SearchAsyncメソッドを使用すると、既にベクター化されているデータを使用して検索できます。 このメソッドは、ベクターと省略可能な VectorSearchOptions<TRecord> クラスを入力として受け取ります。 SearchAsync は、次の種類で使用できます。

VectorStoreCollection<TKey,TRecord>IVectorSearchable<TRecord>を実装します。

既にデータが含まれているコレクションがあると仮定すると、簡単に検索できます。 Qdrant の使用例を次に示します。

public async Task SearchAsync()
{
    // Create a Qdrant VectorStore object and choose
    // an existing collection that already contains records.
    VectorStore vectorStore = new QdrantVectorStore(new QdrantClient("localhost"), ownsClient: true);
    VectorStoreCollection<ulong, Hotel> collection =
        vectorStore.GetCollection<ulong, Hotel>("skhotels");

    // Generate a vector for your search text, using
    // your chosen embedding generation implementation.
    ReadOnlyMemory<float> searchVector =
            await GenerateAsync("I'm looking for a hotel where customer happiness is the priority.");

    // Do the search, passing an options object with
    // a Top value to limit results to the single top match.
    IAsyncEnumerable<VectorSearchResult<Hotel>> searchResult =
        collection.SearchAsync(searchVector, top: 1);

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

ヒント

埋め込みを生成する方法の詳細については、 埋め込み生成を参照してください。

自動生成された埋め込みを使用した検索

ベクター ストアまたはコレクションで IEmbeddingGenerator<TInput,TEmbedding> を構成した場合は、事前計算されたベクターではなく、 string を直接 SearchAsync に渡すことができます。 ベクター ストアは、検索埋め込みを自動的に生成します。

public async Task SearchWithAutoEmbeddingAsync()
{
    // If an IEmbeddingGenerator is configured on the vector store or collection,
    // you can pass a string directly to SearchAsync. The store generates
    // the search embedding for you.
    VectorStore vectorStore = new QdrantVectorStore(new QdrantClient("localhost"), ownsClient: true);
    VectorStoreCollection<ulong, Hotel> collection =
        vectorStore.GetCollection<ulong, Hotel>("skhotels");

    // Pass the search text directly — no manual embedding generation required.
    IAsyncEnumerable<VectorSearchResult<Hotel>> searchResult =
        collection.SearchAsync("I'm looking for a hotel where customer happiness is the priority.", top: 1);

    await foreach (VectorSearchResult<Hotel> record in searchResult)
    {
        Console.WriteLine("Found hotel description: " + record.Record.Description);
        Console.WriteLine("Found record score: " + record.Score);
    }
}

ベクター ストアで埋め込みジェネレーターを構成する方法については、「ベクター ストア で埋め込みを生成できるようにする」を参照してください。

サポートされているベクター型

SearchAsync は、ジェネリック型をベクター パラメーターとして受け取ります。 各データ ストアでサポートされるベクターの種類は異なります。

また、検索ベクターの種類が、検索対象のターゲット ベクターと一致することも重要です。たとえば、同じレコードに異なるベクターの種類を持つ 2 つのベクターがある場合は、指定した検索ベクターが、対象とする特定のベクターの型と一致していることを確認します。 1 つのレコードに複数のターゲット ベクターがある場合にターゲット ベクターを選択する方法については、「 VectorProperty」を参照してください。

ベクター検索オプション

VectorSearchOptions<TRecord> クラスを使用して、次のオプションを指定できます。

VectorProperty

VectorProperty オプションを使用して、検索中にターゲットとするベクター プロパティを指定します。 何も指定されておらず、データ モデルに 1 つのベクターのみが含まれている場合、そのベクターが使用されます。 データ モデルにベクターまたは複数のベクトルが含まれていない場合、 VectorProperty が指定されていない場合、検索メソッドは例外をスローします。

public async Task VectorPropertySearch()
{
    var vectorStore = new InMemoryVectorStore();
    InMemoryCollection<int, Product> collection =
        vectorStore.GetCollection<int, Product>("skproducts");

    // Create the vector search options and indicate that you want to search the FeatureListEmbedding property.
    var vectorSearchOptions = new VectorSearchOptions<Product>
    {
        VectorProperty = r => r.FeatureListEmbedding
    };

    // This snippet assumes searchVector is already provided, having been created using the embedding model of your choice.
    IAsyncEnumerable<VectorSearchResult<Product>> searchResult =
        collection.SearchAsync(searchVector, top: 3, vectorSearchOptions);
}

public sealed class Product
{
    [VectorStoreKey]
    public int Key { get; set; }

    [VectorStoreData]
    public required string Description { get; set; }

    [VectorStoreData]
    public required List<string> FeatureList { get; set; }

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

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

結果をスキップするか、上位の結果を選択する

topSearchAsync<TInput>(TInput, Int32, VectorSearchOptions<TRecord>, CancellationToken) パラメーターと VectorSearchOptions<TRecord>.Skip オプションを使用すると、結果の数を制限できます。 top パラメーターは、結果を上位のn結果に制限します。 Skip オプションは、結果セットの先頭からいくつかの結果をスキップします。 個別の呼び出しを使用して多数の結果を取得する場合は、これらのコントロールを使用してページングを実行できます。

// Create the vector search options and indicate
// that you want to skip the first 40 results.
VectorSearchOptions<Product> vectorSearchOptions = new()
{
    Skip = 40
};

// This snippet assumes searchVector is already provided,
// having been created using the embedding model of your choice.
// Pass 'top: 20' to indicate that you want to retrieve
// the next 20 results after skipping the first 40.
IAsyncEnumerable<VectorSearchResult<Product>> searchResult =
    collection.SearchAsync(searchVector, top: 20, vectorSearchOptions);

// Iterate over the search results.
await foreach (VectorSearchResult<Product> result in searchResult)
{
    Console.WriteLine(result.Record.FeatureList);
}

Skip の既定値は 0 です。

IncludeVectors

VectorSearchOptions<TRecord>.IncludeVectors オプションを使用すると、検索結果にベクターを返すかどうかを指定できます。 false場合、返されるモデルのベクター プロパティは null のままです。 falseを使用すると、検索中にベクター ストアから取得されるデータの量を大幅に減らし、検索をより効率的にすることができます。

IncludeVectors の既定値は false です。

// Create the vector search options and indicate that you want to include vectors in the search results.
var vectorSearchOptions = new VectorSearchOptions<Product>
{
    IncludeVectors = true
};

// This snippet assumes searchVector is already provided,
// having been created using the embedding model of your choice.
IAsyncEnumerable<VectorSearchResult<Product>> searchResult =
    collection.SearchAsync(searchVector, top: 3, vectorSearchOptions);

// Iterate over the search results.
await foreach (VectorSearchResult<Product> result in searchResult)
{
    Console.WriteLine(result.Record.FeatureList);
}

フィルター

VectorSearchOptions<TRecord>.Filter オプションを使用して、ベクター検索を適用する前に、選択したコレクション内のレコードをフィルター処理します。 これには複数の利点があります。

  • フィルター処理後に残っているレコードのみを検索ベクターと比較する必要があるため、実行する必要があるベクター比較が少なくなるため、待機時間と処理コストが削減されます。
  • 結果セットを制限します。 たとえば、ユーザーがアクセスできないデータを除外することで、アクセス制御を実装できます。

フィルター処理に使用するフィールドの場合、多くのベクター ストアでは、最初にこれらのフィールドのインデックスを作成する必要があります。 一部のベクター ストアでは、任意のフィールドを使用したフィルター処理が可能ですが、必要に応じてインデックスを作成してフィルター処理のパフォーマンスを向上させることができます。

ベクター ストアの抽象化を使用してコレクションを作成していて、フィールドのフィルター処理を有効にする場合は、データ モデルを定義するとき、またはレコード定義を作成するときに、 IsIndexed プロパティを true に設定します。

ヒント

IsIndexedを有効にする方法の詳細については、「VectorStoreDataAttribute」または「VectorStoreDataProperty」を参照してください。

フィルターは、データ モデルの型に基づいて LINQ 式を使用して表現されます。 サポートされる LINQ 式のセットは、各データベースでサポートされる機能によって異なりますが、すべてのデータベースは、等しい、等しくない、 andorなど、一般的な式の広範な基本をサポートします。

public static async Task FilteredSearchAsync()
{
    // Create the vector search options and set the filter on the options.
    VectorSearchOptions<Glossary> vectorSearchOptions = new()
    {
        Filter = r => r.Category == "External Definitions" && r.Tags.Contains("memory")
    };

    // This snippet assumes searchVector is already provided,
    // having been created using the embedding model of your choice.
    IAsyncEnumerable<VectorSearchResult<Glossary>> searchResult =
        collection.SearchAsync(searchVector, top: 3, vectorSearchOptions);

    // Iterate over the search results.
    await foreach (VectorSearchResult<Glossary> result in searchResult)
    {
        Console.WriteLine(result.Record.Definition);

    }
}

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

    // 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; }
    [VectorStoreData]
    public required string Term { get; set; }

    [VectorStoreData]
    public required string Definition { get; set; }

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