Labsco
microsoft logo

azure-search-documents-dotnet

✓ Official2,700

by microsoft · part of microsoft/skills

Build search applications with full-text, vector, semantic, and hybrid search capabilities.

🔥🔥🔥🔥✓ VerifiedFreeQuick setup
🧩 One of 7 skills in the microsoft/skills package — works on its own, and pairs well with its siblings.

Build search applications with full-text, vector, semantic, and hybrid search capabilities.

Inspect the full instructions your agent will receiveExpand

This is the exact playbook injected into your agent when the skill activates — shown here so you can audit it before installing. You don't need to read it to use the skill.

by microsoft

Build search applications with full-text, vector, semantic, and hybrid search capabilities. npx skills add https://github.com/microsoft/agent-skills --skill azure-search-documents-dotnet Download ZIPGitHub2.7k

Azure.Search.Documents (.NET)

Build search applications with full-text, vector, semantic, and hybrid search capabilities.

Environment Variables

Copy & paste — that's it
SEARCH_ENDPOINT=https:// .search.windows.net # Required: search service endpoint
SEARCH_INDEX_NAME= # Required: search index name
AZURE_TOKEN_CREDENTIALS=prod # Required only if DefaultAzureCredential is used in production
SEARCH_API_KEY= # Only required for AzureKeyCredential auth

Authentication

Microsoft Entra Token Credential:

Copy & paste — that's it
using Azure.Identity;
using Azure.Search.Documents;

// Local dev: DefaultAzureCredential. Production: set AZURE_TOKEN_CREDENTIALS=prod or AZURE_TOKEN_CREDENTIALS= 
var credential = new DefaultAzureCredential(
 DefaultAzureCredential.DefaultEnvironmentVariableName
);
// Or use a specific credential directly in production:
// See https://learn.microsoft.com/dotnet/api/overview/azure/identity-readme?view=azure-dotnet#credential-classes
// var credential = new ManagedIdentityCredential();
var client = new SearchClient(
 new Uri(Environment.GetEnvironmentVariable("SEARCH_ENDPOINT")),
 Environment.GetEnvironmentVariable("SEARCH_INDEX_NAME"),
 credential);

API Key:

Copy & paste — that's it
using Azure;
using Azure.Search.Documents;

var credential = new AzureKeyCredential(
 Environment.GetEnvironmentVariable("SEARCH_API_KEY"));
var client = new SearchClient(
 new Uri(Environment.GetEnvironmentVariable("SEARCH_ENDPOINT")),
 Environment.GetEnvironmentVariable("SEARCH_INDEX_NAME"),
 credential);

Client Selection

Client Purpose SearchClient Query indexes, upload/update/delete documents SearchIndexClient Create/manage indexes, synonym maps SearchIndexerClient Manage indexers, skillsets, data sources

Index Creation

Using FieldBuilder (Recommended)

Copy & paste — that's it
using Azure.Search.Documents.Indexes;
using Azure.Search.Documents.Indexes.Models;

// Define model with attributes
public class Hotel
{
 [SimpleField(IsKey = true, IsFilterable = true)]
 public string HotelId { get; set; }

 [SearchableField(IsSortable = true)]
 public string HotelName { get; set; }

 [SearchableField(AnalyzerName = LexicalAnalyzerName.EnLucene)]
 public string Description { get; set; }

 [SimpleField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
 public double? Rating { get; set; }

 [VectorSearchField(VectorSearchDimensions = 1536, VectorSearchProfileName = "vector-profile")]
 public ReadOnlyMemory ? DescriptionVector { get; set; }
}

// Create index
var indexClient = new SearchIndexClient(endpoint, credential);
var fieldBuilder = new FieldBuilder();
var fields = fieldBuilder.Build(typeof(Hotel));

var index = new SearchIndex("hotels")
{
 Fields = fields,
 VectorSearch = new VectorSearch
 {
 Profiles = { new VectorSearchProfile("vector-profile", "hnsw-algo") },
 Algorithms = { new HnswAlgorithmConfiguration("hnsw-algo") }
 }
};

await indexClient.CreateOrUpdateIndexAsync(index);

Manual Field Definition

Copy & paste — that's it
var index = new SearchIndex("hotels")
{
 Fields =
 {
 new SimpleField("hotelId", SearchFieldDataType.String) { IsKey = true, IsFilterable = true },
 new SearchableField("hotelName") { IsSortable = true },
 new SearchableField("description") { AnalyzerName = LexicalAnalyzerName.EnLucene },
 new SimpleField("rating", SearchFieldDataType.Double) { IsFilterable = true, IsSortable = true },
 new SearchField("descriptionVector", SearchFieldDataType.Collection(SearchFieldDataType.Single))
 {
 VectorSearchDimensions = 1536,
 VectorSearchProfileName = "vector-profile"
 }
 }
};

Document Operations

Copy & paste — that's it
var searchClient = new SearchClient(endpoint, indexName, credential);

// Upload (add new)
var hotels = new[] { new Hotel { HotelId = "1", HotelName = "Hotel A" } };
await searchClient.UploadDocumentsAsync(hotels);

// Merge (update existing)
await searchClient.MergeDocumentsAsync(hotels);

// Merge or Upload (upsert)
await searchClient.MergeOrUploadDocumentsAsync(hotels);

// Delete
await searchClient.DeleteDocumentsAsync("hotelId", new[] { "1", "2" });

// Batch operations
var batch = IndexDocumentsBatch.Create(
 IndexDocumentsAction.Upload(hotel1),
 IndexDocumentsAction.Merge(hotel2),
 IndexDocumentsAction.Delete(hotel3));
await searchClient.IndexDocumentsAsync(batch);

Search Patterns

Basic Search

Copy & paste — that's it
var options = new SearchOptions
{
 Filter = "rating ge 4",
 OrderBy = { "rating desc" },
 Select = { "hotelId", "hotelName", "rating" },
 Size = 10,
 Skip = 0,
 IncludeTotalCount = true
};

SearchResults results = await searchClient.SearchAsync ("luxury", options);

Console.WriteLine($"Total: {results.TotalCount}");
await foreach (SearchResult result in results.GetResultsAsync())
{
 Console.WriteLine($"{result.Document.HotelName} (Score: {result.Score})");
}

Faceted Search

Copy & paste — that's it
var options = new SearchOptions
{
 Facets = { "rating,count:5", "category" }
};

var results = await searchClient.SearchAsync ("*", options);

foreach (var facet in results.Value.Facets["rating"])
{
 Console.WriteLine($"Rating {facet.Value}: {facet.Count}");
}

Autocomplete and Suggestions

Copy & paste — that's it
// Autocomplete
var autocompleteOptions = new AutocompleteOptions { Mode = AutocompleteMode.OneTermWithContext };
var autocomplete = await searchClient.AutocompleteAsync("lux", "suggester-name", autocompleteOptions);

// Suggestions
var suggestOptions = new SuggestOptions { UseFuzzyMatching = true };
var suggestions = await searchClient.SuggestAsync ("lux", "suggester-name", suggestOptions);

Vector Search

See references/vector-search.md for detailed patterns.

Copy & paste — that's it
using Azure.Search.Documents.Models;

// Pure vector search
var vectorQuery = new VectorizedQuery(embedding)
{
 KNearestNeighborsCount = 5,
 Fields = { "descriptionVector" }
};

var options = new SearchOptions
{
 VectorSearch = new VectorSearchOptions
 {
 Queries = { vectorQuery }
 }
};

var results = await searchClient.SearchAsync (null, options);

Semantic Search

See references/semantic-search.md for detailed patterns.

Copy & paste — that's it
var options = new SearchOptions
{
 QueryType = SearchQueryType.Semantic,
 SemanticSearch = new SemanticSearchOptions
 {
 SemanticConfigurationName = "my-semantic-config",
 QueryCaption = new QueryCaption(QueryCaptionType.Extractive),
 QueryAnswer = new QueryAnswer(QueryAnswerType.Extractive)
 }
};

var results = await searchClient.SearchAsync ("best hotel for families", options);

// Access semantic answers
foreach (var answer in results.Value.SemanticSearch.Answers)
{
 Console.WriteLine($"Answer: {answer.Text} (Score: {answer.Score})");
}

// Access captions
await foreach (var result in results.Value.GetResultsAsync())
{
 var caption = result.SemanticSearch?.Captions?.FirstOrDefault();
 Console.WriteLine($"Caption: {caption?.Text}");
}

Hybrid Search (Vector + Keyword + Semantic)

Copy & paste — that's it
var vectorQuery = new VectorizedQuery(embedding)
{
 KNearestNeighborsCount = 5,
 Fields = { "descriptionVector" }
};

var options = new SearchOptions
{
 QueryType = SearchQueryType.Semantic,
 SemanticSearch = new SemanticSearchOptions
 {
 SemanticConfigurationName = "my-semantic-config"
 },
 VectorSearch = new VectorSearchOptions
 {
 Queries = { vectorQuery }
 }
};

// Combines keyword search, vector search, and semantic ranking
var results = await searchClient.SearchAsync ("luxury beachfront", options);

Field Attributes Reference

Attribute Purpose SimpleField Non-searchable field (filters, sorting, facets) SearchableField Full-text searchable field VectorSearchField Vector embedding field IsKey = true Document key (required, one per index) IsFilterable = true Enable $filter expressions IsSortable = true Enable $orderby IsFacetable = true Enable faceted navigation IsHidden = true Exclude from results AnalyzerName Specify text analyzer

Error Handling

Copy & paste — that's it
using Azure;

try
{
 var results = await searchClient.SearchAsync ("query");
}
catch (RequestFailedException ex) when (ex.Status == 404)
{
 Console.WriteLine("Index not found");
}
catch (RequestFailedException ex)
{
 Console.WriteLine($"Search error: {ex.Status} - {ex.ErrorCode}: {ex.Message}");
}

Best Practices

  • Use DefaultAzureCredential over API keys for production

  • Use FieldBuilder with model attributes for type-safe index definitions

  • Use CreateOrUpdateIndexAsync for idempotent index creation

  • Batch document operations for better throughput

  • Use Select to return only needed fields

  • Configure semantic search for natural language queries

  • Combine vector + keyword + semantic for best relevance

Reference Files

File Contents references/vector-search.md Vector search, hybrid search, vectorizers references/semantic-search.md Semantic ranking, captions, answers