RecursiveAI.OneIndex.VectorData is a vector-store collection over OneIndex for Microsoft.Extensions.VectorData (version 10.11.0 of the abstractions, the one dependency). It covers what the abstraction defines: collections, upsert, get, delete, vector search with filters, and keyword plus vector hybrid search.
var store = new OneIndexVectorStore("data/vectors"); // a directory; new OneIndexVectorStore() keeps collections in memory var hotels = store.GetCollection<string, Hotel>("hotels"); await hotels.EnsureCollectionExistsAsync(); await hotels.UpsertAsync(hotel); // every write is committed before it returns await foreach (var r in hotels.SearchAsync(queryVector, top: 5, new() { Filter = h => h.Rating >= 4 })) Console.WriteLine($"{r.Record.Name} {r.Score}");
What is supported
- Keys
string,Guid,int,long. AGuidkey is generated when the record carriesGuid.Emptyand the key is auto-generated (the default forGuid). Asking for a collection with a key type other than the record's key property throwsInvalidOperationException. - Data properties: strings (full-text indexed when
IsFullTextIndexed), integers, floating point numbers,bool,DateTime,DateTimeOffset, string collections.IsIndexedmakes a property filterable. - Vector properties
ReadOnlyMemory<float>orfloat[], with the distances cosine similarity and distance, dot product, negative dot product, and Euclidean (squared) distance. Scores come back in the unit of the chosen distance function. The vector index is the engine's: flat below the segment threshold, HNSW above. - Filters are the abstraction's LINQ predicates; they are applied while the neighbours are chosen, so a filtered search returns a full page when enough records pass.
Skip,ScoreThreshold,IncludeVectorswork. - Hybrid search (
IKeywordHybridSearchable): the keywords search one full-text property (the one named byAdditionalProperty, or the only one; none or several without a choice throws), fused with the vector by reciprocal rank fusion (hybrid.md). - Records are described by the abstraction's attributes or by a
VectorStoreCollectionDefinition.
What is not
- Dynamic collections (
GetDynamicCollection, dictionary records) and embedding generation by the store:NotSupported. Pass vectors yourself. - Distance functions Manhattan and Hamming.
- Data-type suite. Each of its tests also creates a dynamic collection, so all 16 are excluded; the typed path (
Guid,DateOnly,TimeOnly, nullable values, string collections) is covered byContractTests. Filters comparing a whole array (r.StringArray == array) are not translatable. - Registration extensions. The package ships no
AddOneIndex...dependency-injection extension (it would add a dependency beyond the abstraction); applications registerOneIndexVectorStoreand their collections as services, as the tests do. Embedding generators are not resolved from the container (EmbeddingGeneratorIsResolvedis excluded). - A caveat on
Guidkeys: the abstraction's key-type test also exercises a dynamic collection, which is not supported, so that one test is excluded.
Reflection, trimming and AOT
The adapter reads and writes user record types through reflection, as the abstraction itself does. OneIndexVectorStore.GetCollection and OneIndexRecords<TKey, TRecord> carry RequiresUnreferencedCode and RequiresDynamicCode, so a trimmed or NativeAOT application gets warnings at the call, not silent breakage. The package is therefore not marked IsAotCompatible or IsTrimmable. The core package stays reflection-free; an application that needs AOT uses SearchIndex<T> with the generated mapping directly.
Conformance
The tests run the abstraction's own conformance suite (Microsoft.Extensions.VectorData.ConformanceTests 10.11.0) against a store over a temporary directory, plus 8 contract tests of our own.
| Tests | |
|---|---|
Contract tests, wired conformance suites, dependency-injection suite (dotnet test) | 168 passed, 0 failed, the unsupported cases below reported as skipped |
Skipped with a reason (tests/OneIndex.VectorData.Tests/Unsupported.cs) | Manhattan and Hamming distance (2); the Guid key test, which also needs a dynamic collection (1); EmbeddingGeneratorIsResolved in 9 variants (lifetime and service key); the 16 data-type tests, which need a dynamic collection |
Filters comparing with null and Contains / Any over a collection property, excluded before, now pass (10 tests). Wired suites: collection management, distance functions, index kinds, filters (typed), basic, no-data, no-vector and multi-vector models, key types, hybrid search, dependency injection, data types (all excluded). Not wired: dynamic-model, embedding-generation and embedding-type suites (no dynamic collections, no generated embeddings). A plain dotnet test runs them all; the unsupported cases skip themselves, each naming the feature.