Sarıkaya Dev Logo

Implement AI-Powered Semantic Search in .NET 8 with Azure Cognitive Search

Mahmut Sarıkaya 5 min read 7 Views 0
Implement AI-Powered Semantic Search in .NET 8 with Azure Cognitive Search

Why semantic search matters in modern .NET apps

Imagine a user typing a natural‑language query and instantly receiving documents that understand intent, not just keyword matches. In 2023, Microsoft reported that 62% of enterprise search implementations failed to meet user expectations because they relied on classic keyword algorithms. Semantic search bridges that gap by leveraging vector embeddings that capture meaning, enabling .NET 8 applications to deliver relevance comparable to large language models.

Prerequisites and system requirements

Before writing code, ensure you have .NET 8 SDK installed (download from dotnet.microsoft.com), an Azure subscription with Cognitive Search and Azure OpenAI enabled, and a vector‑compatible database such as Azure Cognitive Search vector search or an external service like Pinecone. Your development machine should run Windows 10/11 or a recent Linux distribution, with at least 8 GB RAM and 2 CPU cores for local testing.

Setting up Azure Cognitive Search service

Create a Search service in the Azure portal (Standard S1 tier is sufficient for proof‑of‑concept). Note the service name, endpoint URL, and admin key. Next, define an index that stores both raw text and its vector representation. The following C# snippet uses the Azure.Search.Documents SDK to create an index named documents with a 1536‑dimensional vector field.

using Azure;
using Azure.Search.Documents.Indexes;
using Azure.Search.Documents.Indexes.Models;

var endpoint = new Uri("https://mysearch.search.windows.net");
var credential = new AzureKeyCredential("YOUR-ADMIN-KEY");
var client = new SearchIndexClient(endpoint, credential);

var vectorField = new SearchField("contentVector", SearchFieldDataType.Collection(SearchFieldDataType.Single))
{
IsSearchable = true,
Dimensions = 1536,
VectorSearchConfiguration = "my-vector-config"
};

var index = new SearchIndex("documents")
{
Fields = new[]
{
new SimpleField("id", SearchFieldDataType.String) { IsKey = true },
new SearchableField("content") { AnalyzerName = LexicalAnalyzerName.EnLucene },
vectorField
},
VectorSearch = new VectorSearch
{
Algorithms = new[]
{
new HnswAlgorithmConfiguration("my-vector-config") { M = 16, EfConstruction = 200 }
}
}
};

client.CreateOrUpdateIndex(index);

The index definition includes a standard searchable field (content) for fallback keyword queries and a contentVector field that will store embeddings generated by Azure OpenAI.

Choosing a vector database for .NET 8

Azure Cognitive Search now supports native vector search, eliminating the need for a separate vector store for many scenarios. If you need multi‑region low‑latency or want to experiment with open‑source tools, consider Azure Cosmos DB with the vectorSearch preview or third‑party services like Pinecone. For a seamless .NET experience, stick with the built‑in vector capabilities: they integrate with the same SearchClient used for classic search, reducing operational overhead.

Integrating embeddings with C# and Azure AI

Generating embeddings is the first step toward semantic indexing. Azure OpenAI provides the text-embedding-ada-002 model, which returns a 1536‑dimensional float array. The SDK call below sends a document string and receives the vector. Remember to store the vector alongside the original text in the documents index.

using Azure.AI.OpenAI;

var openAiClient = new OpenAIClient(new Uri("https://YOUR-RESOURCE.openai.azure.com/"), new AzureKeyCredential("YOUR-KEY"));
var response = await openAiClient.GetEmbeddingsAsync("text-embedding-ada-002", new EmbeddingsOptions(new[] { "Your document text goes here" }));
var vector = response.Value.Data[0].Embedding;
// Save 'vector' to the 'contentVector' field of the Azure Search document.

Batch processing can be parallelized with Parallel.ForEach to ingest thousands of records within minutes. For large corpora, respect the OpenAI rate limits (typically 60 RPM for the free tier) and implement exponential back‑off.

Building the semantic search pipeline

At query time, the user’s phrase is transformed into an embedding, then a VectorQuery is sent to Azure Search. The service returns the top‑k most similar vectors, optionally combined with a traditional keyword filter. The code below demonstrates the end‑to‑end flow in a .NET 8 Web API controller.

using Azure;
using Azure.Search.Documents;
using Azure.Search.Documents.Models;
using Azure.AI.OpenAI;

[ApiController]
[Route("api/search")] public class SearchController : ControllerBase { private readonly SearchClient _searchClient; private readonly OpenAIClient _openAiClient; public SearchController(IConfiguration config) { var endpoint = new Uri(config["Search:Endpoint"]); var credential = new AzureKeyCredential(config["Search:Key"]); _searchClient = new SearchClient(endpoint, "documents", credential); _openAiClient = new OpenAIClient(new Uri(config["OpenAI:Endpoint"]), new AzureKeyCredential(config["OpenAI:Key"])); } [HttpGet] public async Task Get([FromQuery] string q) { var embedResponse = await _openAiClient.GetEmbeddingsAsync("text-embedding-ada-002", new EmbeddingsOptions(new[] { q })); var queryVector = embedResponse.Value.Data[0].Embedding; var vectorQuery = new VectorQuery("contentVector", queryVector, k: 5); var options = new SearchOptions { Vector = vectorQuery, QueryType = SearchQueryType.Semantic, SemanticConfigurationName = "my-semantic-config" }; var results = await _searchClient.SearchAsync("*", options); var docs = results.Value.GetResults().Select(r => r.Document); return Ok(docs); } }

The SemanticConfigurationName ties the query to a custom semantic ranking profile you define in the Azure portal. Adjust k based on latency requirements; a value of 5 typically yields sub‑200 ms response times on an S1 tier.

Performance tuning and cost considerations

Vector search adds CPU overhead for distance calculations. Monitor the SearchUnits metric; a spike above 70% utilization suggests scaling the service tier or enabling the “Standard S3” tier for larger workloads. Cache frequently used query embeddings in Redis to cut OpenAI calls by up to 40%, especially for repetitive support‑ticket queries. From a cost perspective, Azure Cognitive Search charges per search unit hour, while Azure OpenAI charges per 1,000 tokens processed for embeddings (approximately $0.0004 per 1,000 tokens as of 2024). Estimating 50 KB per document and 10 queries per second yields an annual cost under $2,000 for a medium‑size enterprise.

Conclusion

Implementing AI‑powered semantic search in .NET 8 is now a matter of wiring three components: a .NET 8 API, Azure OpenAI for embeddings, and Azure Cognitive Search with vector capabilities. By defining a proper index, handling batch embedding ingestion, and constructing a vector‑aware query pipeline, developers can deliver relevance that feels human. The approach scales from a prototype with a few hundred records to production workloads handling millions of vectors, all while staying within familiar C# idioms.

Sources

  • Microsoft Azure Cognitive Search documentation
  • Azure OpenAI Service quickstart guide
  • Official .NET 8 release notes

Author: Mahmut Sarıkaya — sarikayadev.com

Tags: #.NET 8 #semantic search #Azure Cognitive Search #vector database #C#
Share:
M

Written by

Mahmut Sarıkaya

Software Developer

Comments

No comments yet. Be the first to share your thoughts!

Leave a Comment

3 + 0 =