AI Semantic Ranking
Azure AI Search Semantic Ranking uses Microsoft’s language understanding models to re-rank your search results by meaning, not just keyword matches. ExamineX makes it easy to enable this on your indexes and queries with just a few lines of code.
How it works
- Your normal search runs first (BM25 keyword scoring)
- The top 50 results are passed to a deep learning model that understands language
- Results are re-ranked by semantic relevance — the most meaningful matches float to the top
- Optionally, captions (relevant passages) and answers (direct responses to questions) are extracted
This is especially powerful for natural language queries like “hotels within walking distance to live music” where keyword matching alone falls short.
Requirements
- Semantic ranking must be enabled on your Azure Search service
- The Free tier includes semantic ranking with a limit of 1,000 queries/month — suitable for development and testing. For production workloads, a paid tier is recommended. See Azure AI Search pricing for details.
- ExamineX v7+
Index Configuration
To enable semantic ranking, add one or more AzureSearchSemanticConfiguration entries to your index options. Each configuration is a named set of field-to-role mappings that tells the language model which fields contain your title, content, and keywords.
Single configuration
For most cases, a single configuration is all you need:
services.AddUmbraco(_env, _config)
.AddBackOffice()
.AddWebsite()
.AddComposers()
.AddExamineXAzureSearch(azureSearch =>
{
azureSearch.ConfigureIndex("ExternalIndex", options =>
{
options.SemanticConfigurations = new[]
{
new AzureSearchSemanticConfiguration
{
TitleField = "nodeName",
ContentFields = new[] { "bodyText", "Description" },
KeywordsFields = new[] { "nodeTypeAlias" }
}
};
});
})
.Build();
Multiple configurations
When your index contains different document shapes (e.g. articles and products), you can define a configuration for each. The first configuration becomes the index default:
options.SemanticConfigurations = new[]
{
new AzureSearchSemanticConfiguration
{
ConfigurationName = "article-config",
TitleField = "nodeName",
ContentFields = new[] { "bodyText", "Description" }
},
new AzureSearchSemanticConfiguration
{
ConfigurationName = "product-config",
TitleField = "productName",
ContentFields = new[] { "productDescription" },
KeywordsFields = new[] { "category", "tags" }
}
};
At query time, use SemanticSearchQueryOptions.ConfigurationName to select which configuration to use. If not specified, the default (first) configuration is used.
| Property | Description | Default |
|---|---|---|
ConfigurationName |
Name for this semantic configuration. Required when using multiple configurations. | "default" |
TitleField |
The field representing the document title | null |
ContentFields |
Fields containing the main content (order matters — most important first) | Empty |
KeywordsFields |
Fields containing keywords/tags | Empty |
Tips:
ContentFieldsare the most important — they should contain your richest, most descriptive text- You can specify multiple content and keyword fields, prioritized by array order
- The
TitleFieldis optional but recommended for best results - Field names should match your Examine field definitions — ExamineX handles any necessary name formatting automatically
Querying with Semantic Ranking
Once your index has a semantic configuration, you can enable semantic ranking on any query by passing AzureSearchQueryOptions with SemanticSearchQueryOptions:
Simple text search
The simplest usage — your search text is used for both the initial BM25 keyword search and the semantic re-ranking:
var searcher = index.Searcher;
var results = searcher.Search("hotels near the beach", new AzureSearchQueryOptions(
new SemanticSearchQueryOptions
{
EnableCaptions = true
}));
Query builder
When using the query builder, your Examine query uses Lucene syntax which isn’t ideal input for the language model. In this case, set SemanticQuery to provide a plain-text natural language version of the query for the semantic model:
var results = searcher.CreateQuery("content")
.Field("bodyText", "beach hotel")
.Execute(new AzureSearchQueryOptions(
new SemanticSearchQueryOptions
{
SemanticQuery = "beach hotel with ocean views",
EnableCaptions = true,
EnableAnswers = true
}));
SemanticSearchQueryOptions
| Property | Description | Default |
|---|---|---|
ConfigurationName |
Which semantic configuration to use. Required when using multiple configurations. If not set, the index default (first) configuration is used. | Uses the index default |
SemanticQuery |
An optional plain-text query for the semantic model. When omitted, the search text is used for both the keyword search and semantic re-ranking. Recommended when using the query builder, since Lucene syntax is poor input for language understanding. | Uses the search text |
EnableCaptions |
Extract the most relevant passages from each result | false |
HighlightCaptions |
Apply emphasis tags to caption highlights | true |
EnableAnswers |
Extract direct answers to question-like queries | false |
Working with Results
Reranker Score
When semantic ranking is active, each result includes a reranker score (0–4 scale) indicating semantic relevance. Results are automatically ordered by this score. The original BM25 score remains available via ISearchResult.Score.
foreach (var result in results)
{
// Original BM25 score
var bm25Score = result.Score;
// Semantic reranker score (0-4, higher = more relevant)
if (result.Values.ContainsKey(AzureSearchFieldNames.SemanticRerankerScore))
{
var rerankerScore = double.Parse(result[AzureSearchFieldNames.SemanticRerankerScore]);
}
}
Captions
Captions are the most relevant passages extracted from your content fields. They’re available when EnableCaptions = true:
foreach (var result in results)
{
if (result.Values.ContainsKey(AzureSearchFieldNames.SemanticCaption))
{
var caption = result[AzureSearchFieldNames.SemanticCaption];
var captionHighlighted = result[AzureSearchFieldNames.SemanticCaptionHighlighted];
}
}
Semantic Answers
Answers are verbatim passages from your index that directly respond to question-like queries. They’re available at the query level (not per-result) when EnableAnswers = true:
var searchResults = (AzureSearchResults)searcher.Search("what lives in total darkness?",
new AzureSearchQueryOptions(
new SemanticSearchQueryOptions
{
EnableAnswers = true
}));
if (searchResults.SemanticAnswers != null)
{
foreach (var answer in searchResults.SemanticAnswers)
{
Console.WriteLine($"Answer: {answer.Text}");
Console.WriteLine($"From document: {answer.Key}");
Console.WriteLine($"Confidence: {answer.Score}");
}
}
Note: Answers are not guaranteed — the service only returns them when it finds a high-confidence match.
Field Name Constants
Use the AzureSearchFieldNames constants to access semantic data in results:
| Constant | Value | Description |
|---|---|---|
SemanticRerankerScore |
__semanticRerankerScore |
The reranker relevance score (0–4) |
SemanticCaption |
__semanticCaption |
Plain text caption |
SemanticCaptionHighlighted |
__semanticCaptionHighlighted |
Caption with emphasis highlights |
Limitations
- Sorting: You cannot combine
OrderBywith semantic ranking. Azure AI Search returns an error when both are used. ExamineX validates this early and throws anInvalidOperationExceptionwith a clear message. - Top 50 only: Semantic ranking reranks the top 50 results from the initial BM25 scoring pass. Results beyond position 50 keep their original BM25 ordering.
- Free tier limit: The Free tier supports semantic ranking but is limited to 1,000 queries/month. For production workloads, upgrade to a paid tier.
- Query type: ExamineX uses the
SemanticQueryapproach which is compatible with all query types (Lucene full syntax included). You do not need to change your existing queries.