Leaders Logo

Beyond Full-Text Search: Exploring the Potential of SqlVector in the .NET 10 Ecosystem

Introduction

Going beyond Full-Text Search (FTS) does not mean abandoning a mature technology, but recognizing that many modern queries depend less on literal matching and more on semantic proximity. When the application needs to understand that “recurring default” and “frequent payment delays” describe the same phenomenon, embeddings start to complement the classic textual index. This advancement stems from the consolidation of dense language representations and the use of neural retrieval in production (DEVLIN et al., 2019) (REIMERS; GUREVYCH, 2019).

In the .NET 10 ecosystem, this shift becomes more practical because EF Core 10 already offers native support for the SQL Server vector type. In the application layer, the data appears as SqlVector<float>; in the database, it is persisted as vector(n). The result is a simpler design for semantic search, recommendation, content deduplication, and RAG pipelines scenarios, without requiring the entire architecture to be moved to a specialized database.

Why FTS alone is not enough

FTS remains excellent for lexical filters, boolean operators, prefixes, textual proximity, and term-based relevance rules. The problem arises when the user asks questions using vocabulary different from the indexed text. Embeddings reduce this gap because they project meaning into a vector space where semantically similar texts tend to be close neighbors (DEVLIN et al., 2019).

In practice, the best answer is rarely “FTS or vectors,” but rather “FTS first, vectors afterwards.” The textual filter reduces the set of candidates at a low cost; vector distance refines the final ranking for ambiguous, lengthy, or natural language questions. This hybrid pattern also aligns well with dense retrieval pipelines used in QA and RAG (KARPUKHIN et al., 2020) (LEWIS et al., 2020).

SVG Image of the Article

Modeling in .NET 10 with EF Core 10

The cleanest modeling approach is to keep textual content, metadata, and embedding within the same entity when the application requires transactional consistency and centralized governance. This simplifies auditing, backup, permissions, and versioning of the domain.

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;

public sealed class KnowledgeDocument
{
    [Key]
    public Guid Id { get; set; }

    [MaxLength(200)]
    public string Title { get; set; } = string.Empty;

    public string Content { get; set; } = string.Empty;

    [Column(TypeName = "vector(1536)")]
    public SqlVector<float> Embedding { get; set; } = default!;

    [MaxLength(80)]
    public string Category { get; set; } = string.Empty;
}

public sealed class SearchDbContext(DbContextOptions<SearchDbContext> options)
    : DbContext(options)
{
    public DbSet<KnowledgeDocument> Documents => Set<KnowledgeDocument>();
}

This format is more aligned with the current state of the platform than handcrafted conversions to JSON strings or simulated proprietary types. In .NET 10, it is preferable to use native mapping and let the ORM layer translate vector operations into SQL.

Generation and persistence of embeddings

Embedding generation should be handled outside the database, in an application service or ingestion pipeline. This preserves flexibility to switch models, control per-document costs, and version reprocessing tasks. In enterprise search scenarios, sentence embedding models usually offer a better balance between quality and operational simplicity (REIMERS; GUREVYCH, 2019).

using Microsoft.Extensions.AI;

public sealed class DocumentIngestionService(
    SearchDbContext dbContext,
    IEmbeddingGenerator<string, Embedding<float>> embeddingGenerator)
{
    public async Task<Guid> SaveAsync(string title, string content, string category, CancellationToken cancellationToken = default)
    {
        var embedding = await embeddingGenerator.GenerateVectorAsync(content, cancellationToken: cancellationToken);

        var document = new KnowledgeDocument
        {
            Id = Guid.NewGuid(),
            Title = title,
            Content = content,
            Category = category,
            Embedding = new SqlVector<float>(embedding)
        };

        dbContext.Documents.Add(document);
        await dbContext.SaveChangesAsync(cancellationToken);

        return document.Id;
    }
}

From a governance perspective, it is also advisable to persist the embedding model version and the generation date. When the model changes, comparing old and new vectors may degrade ranking consistency; therefore, broad re-indexing should be treated as explicit operational events.

Exact Vector Search with LINQ

For small databases or previously filtered sets, exact search is usually sufficient. The advantage here does not come from “semantic magic,” but from exposing a way to order candidates by the distance between the query vector and the persisted vectors.

public sealed class SemanticSearchService(
    SearchDbContext dbContext,
    IEmbeddingGenerator<string, Embedding<float>> embeddingGenerator)
{
    public async Task<List<KnowledgeDocument>> SearchAsync(string question, CancellationToken cancellationToken = default)
    {
        var queryEmbedding = await embeddingGenerator.GenerateVectorAsync(question, cancellationToken: cancellationToken);
        var queryVector = new SqlVector<float>(queryEmbedding);

        return await dbContext.Documents
            .OrderBy(d => EF.Functions.VectorDistance("cosine", d.Embedding, queryVector))
            .Take(5)
            .ToListAsync(cancellationToken);
    }
}

This pattern solves the central case of the article: moving from pure FTS to a search closer to the user's intent, without breaking the existing relational model.

Hybrid search: textual filtering with semantic refinement

In production, the most pragmatic design is often hybrid. First, FTS is used to ensure thematic selection and low initial filtering cost. Then, vector distance reorders the remaining candidates. This arrangement tends to improve perceived accuracy without sacrificing operational predictability (KARPUKHIN et al., 2020).

public async Task<List<KnowledgeDocument>> SearchHybridAsync(
    string question,
    string keywords,
    CancellationToken cancellationToken = default)
{
    var queryEmbedding = await embeddingGenerator.GenerateVectorAsync(question, cancellationToken: cancellationToken);
    var queryVector = new SqlVector<float>(queryEmbedding);

    return await dbContext.Documents
        .FromSql($"""
            SELECT TOP (10) Id, Title, Content, Category, Embedding
            FROM dbo.Documents
            WHERE CONTAINS(Content, {keywords})
            ORDER BY VECTOR_DISTANCE('cosine', Embedding, {queryVector})
            """)
        .ToListAsync(cancellationToken);
}

It's also worth noting a security detail: in .NET 10, it's advisable to prefer EF's parameterized APIs rather than manually concatenating SQL, especially when keywords or filters come from external input.

Vector indexes and operational limits

As the collection grows, the bottleneck moves from the ORM to the search strategy. Exact search remains useful, but starts to cost more CPU and latency. This is where approximate indexes come into play. Conceptually, the approximate nearest neighbors literature shows that graph-based structures can drastically reduce search costs with controlled recall loss (MALKOV; YASHUNIN, 2020).

CREATE VECTOR INDEX IX_Documents_Embedding
ON dbo.Documents (Embedding)
WITH (METRIC = 'COSINE', TYPE = 'DISKANN');

In the current SQL Server, this requires attention to the feature’s maturity stage: approximate vector search with index is the most modern path in SQL Server 2025 and Azure SQL, while exact search remains the most straightforward option for environments not yet using the full set of vector capabilities. In enterprise projects, the choice should not be ideological; it depends on cardinality, SLA, and tolerance for approximation.

DECLARE @queryVector VECTOR(1536) = @p0;

SELECT TOP (10) WITH APPROXIMATE
    d.Id,
    d.Title,
    vs.distance
FROM VECTOR_SEARCH(
        TABLE = dbo.Documents AS d,
        COLUMN = Embedding,
        SIMILAR_TO = @queryVector,
        METRIC = 'cosine'
    ) AS vs
ORDER BY vs.distance;

RAG in .NET 10 without inflating the architecture

The most compelling use of this stack appears in RAG. The database retrieves semantically relevant snippets, the application organizes the context, and the generative model responds based on the retrieved evidence. This design reduces hallucination, improves traceability, and keeps retrieval decoupled from the generation stage (LEWIS et al., 2020).

public async Task<string> AnswerAsync(string question, CancellationToken cancellationToken = default)
{
    var matches = await SearchAsync(question, cancellationToken);

    var context = string.Join(
        "\n\n",
        matches.Select(d => $"[{d.Title}] {d.Content}"));

    return await chatClient.GetResponseAsync(
        $"""
        Answer the question using only the context below.

        Question: {question}

        Context:
        {context}
        """,
        cancellationToken: cancellationToken);
}

This approach is especially useful in legal databases, knowledge bases, technical manuals, and internal policies, where contextual accuracy is more valuable than raw document volume.

Governance, security, and maintenance

Embeddings are not risk-neutral. Depending on the pipeline, they may preserve clues about the original data, and this requires the same level of discipline applied to the source text: access control, masking when applicable, audit trails, and retention policies. The security literature on language models has already demonstrated that vector artifacts and models can expose sensitive traces when poorly governed (CARLINI et al., 2021).

Operationally, three practices deserve priority: logging the embedding model version, tracking latency and hit rate by query type, and rebuilding the vector index after major corpus reprocessing. This avoids the false perception that semantic search “degrades out of nowhere”; almost always there is a distribution shift, duplicated data, or poorly calibrated filters behind the drop in quality.

Progressive Migration from Full-Text Search

The safest adoption is incremental. It begins with a subset of documents, measures quality on a controlled set of real questions, and compares the FTS ranking with the hybrid ranking. If the gain is consistent, the corpus is expanded, observability and reindexing policies are introduced, and only then does vector search become part of the main flow. This gradual migration is better suited for business scenarios than an abrupt technology switch.

Conclusion

In summary, the potential of SqlVector in the .NET 10 ecosystem lies less in “replacing everything” and more in adding semantics to what already works. FTS remains relevant; vectors come into play to solve what literal terms cannot reach. When the solution is well-modeled, the gain is not only technical: it becomes evident in the user experience, the quality of the retrieved context, and the ability to evolve the platform without disruption. For organizations already operating on SQL Server and .NET, this path offers a pragmatic evolution, with gradual adoption, centralized governance, and better adherence to enterprise search and RAG scenarios.

References

  • DEVLIN, Jacob et al. Bert: Pre-training of deep bidirectional transformers for language understanding. In: Proceedings of the 2019 conference of the North American chapter of the association for computational linguistics: human language technologies, volume 1 (long and short papers). 2019. p. 4171-4186. reference.Description
  • REIMERS, Nils; GUREVYCH, Iryna. Sentence-BERT: Sentence embeddings using siamese BERT-networks. In: Proceedings of the 2019 Conference on Empirical Methods in Natural Language Processing and the 9th International Joint Conference on Natural Language Processing (EMNLP-IJCNLP). 2019. p. 3982-3992. reference.Description
  • KARPUKHIN, Vladimir et al. Dense passage retrieval for open-domain question answering. In: Proceedings of the 2020 conference on empirical methods in natural language processing (EMNLP). 2020. pp. 6769-6781. reference.Description
  • LEWIS, Patrick et al. Retrieval-augmented generation for knowledge-intensive nlp tasks. Advances in neural information processing systems, v. 33, p. 9459-9474, 2020. reference.Description
  • MALKOV, Yu A.; YASHUNIN, Dmitry A. Efficient and robust approximate nearest neighbor search using hierarchical navigable small world graphs. IEEE transactions on pattern analysis and machine intelligence, v. 42, n. 4, p. 824-836, 2018. reference.Description
  • CARLINI, Nicholas et al. Extracting training data from large language models. In: 30th USENIX Security Symposium (USENIX Security 21). 2021. pp. 2633-2650. reference.Description
About the author