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; }
}
結果をスキップするか、上位の結果を選択する
topの SearchAsync<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 式のセットは、各データベースでサポートされる機能によって異なりますが、すべてのデータベースは、等しい、等しくない、 and、 orなど、一般的な式の広範な基本をサポートします。
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; }
}
.NET