Semantic Search Patterns
Detailed patterns for semantic ranking, captions, and answers with Azure.Search.Documents.
Index Configuration for Semantic Search
using Azure.Search.Documents.Indexes.Models;
var index = new SearchIndex("articles")
{
Fields =
{
new SimpleField("id", SearchFieldDataType.String) { IsKey = true },
new SearchableField("title"),
new SearchableField("content"),
new SearchableField("summary"),
new SimpleField("category", SearchFieldDataType.String) { IsFilterable = true }
},
SemanticSearch = new SemanticSearch
{
DefaultConfigurationName = "my-semantic-config",
Configurations =
{
new SemanticConfiguration("my-semantic-config", new SemanticPrioritizedFields
{
TitleField = new SemanticField("title"),
ContentFields =
{
new SemanticField("content"),
new SemanticField("summary")
},
KeywordsFields =
{
new SemanticField("category")
}
})
}
}
};
await indexClient.CreateOrUpdateIndexAsync(index);Basic Semantic Search
using Azure.Search.Documents.Models;
var options = new SearchOptions
{
QueryType = SearchQueryType.Semantic,
SemanticSearch = new SemanticSearchOptions
{
SemanticConfigurationName = "my-semantic-config"
},
Select = { "id", "title", "content" },
Size = 10
};
var results = await searchClient.SearchAsync<Article>(
"What are the best practices for cloud security?",
options);
await foreach (var result in results.Value.GetResultsAsync())
{
Console.WriteLine($"{result.Document.Title} (Score: {result.Score})");
}Semantic Search with Captions
Captions provide highlighted excerpts showing why a document matched:
var options = new SearchOptions
{
QueryType = SearchQueryType.Semantic,
SemanticSearch = new SemanticSearchOptions
{
SemanticConfigurationName = "my-semantic-config",
QueryCaption = new QueryCaption(QueryCaptionType.Extractive)
{
HighlightEnabled = true
}
}
};
var results = await searchClient.SearchAsync<Article>("cloud security best practices", options);
await foreach (var result in results.Value.GetResultsAsync())
{
Console.WriteLine($"Title: {result.Document.Title}");
if (result.SemanticSearch?.Captions != null)
{
foreach (var caption in result.SemanticSearch.Captions)
{
// Highlights contains <em> tags around key phrases
Console.WriteLine($"Caption: {caption.Highlights ?? caption.Text}");
}
}
}Semantic Search with Answers
Answers extract direct responses from the content:
var options = new SearchOptions
{
QueryType = SearchQueryType.Semantic,
SemanticSearch = new SemanticSearchOptions
{
SemanticConfigurationName = "my-semantic-config",
QueryAnswer = new QueryAnswer(QueryAnswerType.Extractive)
{
Count = 3, // Number of answers to return
Threshold = 0.7 // Minimum confidence threshold
},
QueryCaption = new QueryCaption(QueryCaptionType.Extractive)
}
};
var results = await searchClient.SearchAsync<Article>(
"What is zero trust security?",
options);
// Check for semantic answers (appear before documents)
if (results.Value.SemanticSearch?.Answers != null)
{
foreach (var answer in results.Value.SemanticSearch.Answers)
{
Console.WriteLine($"Answer: {answer.Highlights ?? answer.Text}");
Console.WriteLine($"Score: {answer.Score}");
Console.WriteLine($"Document Key: {answer.Key}");
}
}
// Process documents with captions
await foreach (var result in results.Value.GetResultsAsync())
{
Console.WriteLine($"\nDocument: {result.Document.Title}");
Console.WriteLine($"Reranker Score: {result.SemanticSearch?.RerankerScore}");
}Semantic Hybrid Search (Vector + Keyword + Semantic)
Combines all three search modalities for best relevance:
var vectorQuery = new VectorizedQuery(embedding)
{
KNearestNeighborsCount = 50,
Fields = { "contentVector" }
};
var options = new SearchOptions
{
QueryType = SearchQueryType.Semantic,
SemanticSearch = new SemanticSearchOptions
{
SemanticConfigurationName = "my-semantic-config",
QueryCaption = new QueryCaption(QueryCaptionType.Extractive),
QueryAnswer = new QueryAnswer(QueryAnswerType.Extractive)
},
VectorSearch = new VectorSearchOptions
{
Queries = { vectorQuery }
},
Select = { "id", "title", "content" },
Size = 10
};
// Keyword search + vector search + semantic reranking
var results = await searchClient.SearchAsync<Article>(
"best practices for securing cloud infrastructure",
options);Semantic Configuration Options
SemanticPrioritizedFields
| Field | Purpose | Recommendation |
|---|---|---|
TitleField |
Document title | Short, descriptive field |
ContentFields |
Main content (ordered by priority) | Up to 10 fields, most important first |
KeywordsFields |
Keywords/tags | Categorical or tag fields |
QueryCaption Options
new QueryCaption(QueryCaptionType.Extractive)
{
HighlightEnabled = true // Wrap key phrases in <em> tags
}QueryAnswer Options
new QueryAnswer(QueryAnswerType.Extractive)
{
Count = 3, // Max answers to return (1-10)
Threshold = 0.7 // Minimum confidence (0.0-1.0)
}Semantic Ranking Scores
| Score | Description |
|---|---|
result.Score |
BM25 keyword relevance score |
result.SemanticSearch.RerankerScore |
Semantic relevance (0-4 scale) |
answer.Score |
Answer confidence (0-1 scale) |
Error Handling
var results = await searchClient.SearchAsync<Article>(query, options);
// Check if semantic search was applied
if (results.Value.SemanticSearch?.ErrorReason != null)
{
Console.WriteLine($"Semantic search warning: {results.Value.SemanticSearch.ErrorReason}");
// Results still returned, but without semantic ranking
}Best Practices
- Configure semantic fields carefully - Title and content fields significantly impact quality
- Use answers for Q&A scenarios - Set appropriate threshold to filter low-confidence answers
- Combine with vector search - Semantic hybrid provides best relevance
- Monitor reranker scores - Scores below 1.0 indicate weak semantic match
- Enable captions - Helps users understand why documents matched
- Set answer count appropriately - More answers = more latency
- Use filters before semantic ranking - Reduces documents to rerank