Azure Search Documents Dotnet
MicrosoftOfficialCreated by Microsoft
- Skill
- Tool integration
- Software development
- MIT
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
The Azure.Search.Documents SDK provides a comprehensive set of tools for .NET developers to integrate Azure AI Search into their applications. It supports advanced search paradigms including full-text search, vector search for AI-driven similarity, and semantic ranking for natural language understanding. The SDK is structured around three primary clients: SearchClient for document operations and querying, SearchIndexClient for managing index schemas, and SearchIndexerClient for automating data ingestion and skillsets.
What it does
- Perform full-text, vector, and hybrid search queries
- Manage search indexes, synonym maps, and indexers programmatically
- Execute document CRUD operations including batch updates
- Implement semantic search with captions and answers
- Configure vector search profiles and algorithms
- Support authentication via Microsoft Entra ID or API keys
When to use it
- When building search-enabled .NET applications on Azure
- When implementing RAG (Retrieval-Augmented Generation) pipelines
- When you need to perform semantic or vector-based similarity searches
- When managing search index infrastructure via code
Advantages
- Strongly-typed index definition using FieldBuilder
- Native support for modern search techniques like hybrid and semantic ranking
- Flexible authentication options including managed identity
- Comprehensive batch processing for efficient data ingestion
Usage examples
- “How do I perform a hybrid search using Azure.Search.Documents in C#?”
- The agent provides a code snippet using SearchOptions with both VectorSearchOptions and standard search text to combine keyword and vector retrieval.
- “Show me how to define a search index with a vector field.”
- The agent demonstrates using the FieldBuilder attribute [VectorSearchField] or manual SearchField definition to configure vector dimensions and profiles.
- “How can I enable semantic search for my articles index?”
- The agent provides a configuration example using SemanticSearch and SemanticConfiguration to prioritize fields for semantic ranking.
- “What is the best way to authenticate the SearchClient in production?”
- The agent explains using DefaultAzureCredential with environment variables to leverage managed identities instead of hardcoded API keys.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/microsoft/azure-search-documents-dotnet/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip azure-search-documents-dotnet.zip -d .agents/skills
Documentation by Microsoft
Azure.Search.Documents (.NET)
Build search applications with full-text, vector, semantic, and hybrid search capabilities.
Installation
dotnet add package Azure.Search.Documents
dotnet add package Azure.IdentityCurrent Versions: Stable v11.7.0, Preview v11.8.0-beta.1
Environment Variables
SEARCH_ENDPOINT=https://<search-service>.search.windows.net # Required: search service endpoint
SEARCH_INDEX_NAME=<index-name> # Required: search index name
AZURE_TOKEN_CREDENTIALS=prod # Required only if DefaultAzureCredential is used in production
SEARCH_API_KEY=<api-key> # Only required for AzureKeyCredential authAuthentication
Microsoft Entra Token Credential:
using Azure.Identity;
using Azure.Search.Documents;
// Local dev: DefaultAzureCredential. Production: set AZURE_TOKEN_CREDENTIALS=prod or AZURE_TOKEN_CREDENTIALS=<specific_credential>
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:
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)
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<float>? 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
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
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
var options = new SearchOptions
{
Filter = "rating ge 4",
OrderBy = { "rating desc" },
Select = { "hotelId", "hotelName", "rating" },
Size = 10,
Skip = 0,
IncludeTotalCount = true
};
SearchResults<Hotel> results = await searchClient.SearchAsync<Hotel>("luxury", options);
Console.WriteLine($"Total: {results.TotalCount}");
await foreach (SearchResult<Hotel> result in results.GetResultsAsync())
{
Console.WriteLine($"{result.Document.HotelName} (Score: {result.Score})");
}Faceted Search
var options = new SearchOptions
{
Facets = { "rating,count:5", "category" }
};
var results = await searchClient.SearchAsync<Hotel>("*", options);
foreach (var facet in results.Value.Facets["rating"])
{
Console.WriteLine($"Rating {facet.Value}: {facet.Count}");
}Autocomplete and Suggestions
// 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<Hotel>("lux", "suggester-name", suggestOptions);Vector Search
See references/vector-search.md for detailed patterns.
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<Hotel>(null, options);Semantic Search
See references/semantic-search.md for detailed patterns.
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<Hotel>("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)
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<Hotel>("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
using Azure;
try
{
var results = await searchClient.SearchAsync<Hotel>("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
DefaultAzureCredentialover API keys for productionUse
FieldBuilderwith model attributes for type-safe index definitionsUse
CreateOrUpdateIndexAsyncfor idempotent index creationBatch document operations for better throughput
Use
Selectto return only needed fieldsConfigure 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 |
Files
- ATTRIBUTION.mdAdded by AutoGineer998 B
- LICENSELicence file added by AutoGineer1.1 KiB
- SKILL.md10.1 KiB
- references/semantic-search.md6.8 KiB
- references/vector-search.md5.8 KiB
references/vector-search.md
Vector Search Patterns
Detailed patterns for vector and hybrid search with Azure.Search.Documents.
Index Configuration for Vector Search
using Azure.Search.Documents.Indexes.Models;
var index = new SearchIndex("products")
{
Fields =
{
new SimpleField("id", SearchFieldDataType.String) { IsKey = true },
new SearchableField("name"),
new SearchableField("description"),
new SearchField("descriptionVector", SearchFieldDataType.Collection(SearchFieldDataType.Single))
{
VectorSearchDimensions = 1536, // Must match embedding model
VectorSearchProfileName = "vector-profile"
}
},
VectorSearch = new VectorSearch
{
Profiles =
{
new VectorSearchProfile("vector-profile", "hnsw-algo")
{
VectorizerName = "openai-vectorizer" // Optional: for integrated vectorization
}
},
Algorithms =
{
new HnswAlgorithmConfiguration("hnsw-algo")
{
Parameters = new HnswParameters
{
M = 4,
EfConstruction = 400,
EfSearch = 500,
Metric = VectorSearchAlgorithmMetric.Cosine
}
}
},
Vectorizers =
{
new AzureOpenAIVectorizer("openai-vectorizer")
{
Parameters = new AzureOpenAIVectorizerParameters
{
ResourceUri = new Uri("https://<resource>.openai.azure.com"),
DeploymentName = "text-embedding-ada-002",
ModelName = "text-embedding-ada-002"
}
}
}
}
};Pure Vector Search
using Azure.Search.Documents.Models;
// Get embedding from your embedding model
float[] embedding = await GetEmbeddingAsync("luxury hotel with pool");
var vectorQuery = new VectorizedQuery(embedding)
{
KNearestNeighborsCount = 10,
Fields = { "descriptionVector" },
Exhaustive = false // Use HNSW index (faster)
};
var options = new SearchOptions
{
VectorSearch = new VectorSearchOptions
{
Queries = { vectorQuery }
},
Select = { "id", "name", "description" }
};
// Pass null for search text in pure vector search
var results = await searchClient.SearchAsync<Product>(null, options);
await foreach (var result in results.Value.GetResultsAsync())
{
Console.WriteLine($"{result.Document.Name} (Score: {result.Score})");
}Hybrid Search (Vector + Keyword)
var vectorQuery = new VectorizedQuery(embedding)
{
KNearestNeighborsCount = 10,
Fields = { "descriptionVector" }
};
var options = new SearchOptions
{
VectorSearch = new VectorSearchOptions
{
Queries = { vectorQuery }
},
Select = { "id", "name", "description" },
Size = 10
};
// Pass search text for hybrid search
var results = await searchClient.SearchAsync<Product>("luxury pool", options);Multi-Vector Search
Search across multiple vector fields:
var titleVector = new VectorizedQuery(titleEmbedding)
{
KNearestNeighborsCount = 10,
Fields = { "titleVector" }
};
var descriptionVector = new VectorizedQuery(descriptionEmbedding)
{
KNearestNeighborsCount = 10,
Fields = { "descriptionVector" }
};
var options = new SearchOptions
{
VectorSearch = new VectorSearchOptions
{
Queries = { titleVector, descriptionVector }
}
};Vector Search with Filters
var vectorQuery = new VectorizedQuery(embedding)
{
KNearestNeighborsCount = 10,
Fields = { "descriptionVector" }
};
var options = new SearchOptions
{
VectorSearch = new VectorSearchOptions
{
Queries = { vectorQuery }
},
Filter = "category eq 'Electronics' and price lt 500",
Select = { "id", "name", "price", "category" }
};
var results = await searchClient.SearchAsync<Product>(null, options);Integrated Vectorization (Text-to-Vector)
When a vectorizer is configured, you can search with text directly:
var vectorQuery = new VectorizableTextQuery("luxury hotel with ocean view")
{
KNearestNeighborsCount = 10,
Fields = { "descriptionVector" }
};
var options = new SearchOptions
{
VectorSearch = new VectorSearchOptions
{
Queries = { vectorQuery }
}
};
// No need to generate embeddings client-side
var results = await searchClient.SearchAsync<Hotel>(null, options);Algorithm Configuration
HNSW (Hierarchical Navigable Small World)
Best for most scenarios - fast approximate nearest neighbor search:
new HnswAlgorithmConfiguration("hnsw-algo")
{
Parameters = new HnswParameters
{
M = 4, // Connections per layer (4-10 typical)
EfConstruction = 400, // Index build quality (higher = better, slower)
EfSearch = 500, // Search quality (higher = better, slower)
Metric = VectorSearchAlgorithmMetric.Cosine
}
}Exhaustive KNN
Exact nearest neighbor search (slower but precise):
new ExhaustiveKnnAlgorithmConfiguration("exhaustive-algo")
{
Parameters = new ExhaustiveKnnParameters
{
Metric = VectorSearchAlgorithmMetric.Cosine
}
}Vector Search Metrics
| Metric | Use Case |
|---|---|
Cosine | Text embeddings (most common) |
Euclidean | When magnitude matters |
DotProduct | Normalized vectors, performance |
Best Practices
Match dimensions to your embedding model (e.g., 1536 for text-embedding-ada-002)
Use HNSW for production workloads (faster than exhaustive)
Tune EfSearch based on latency vs. recall requirements
Apply filters to reduce search space before vector comparison
Use integrated vectorization to simplify client code
Combine with semantic ranking for best relevance
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs an API key
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- Microsoft
- Publisher
- Microsoft (Official)
- Source
- microsoft/skills · .github/plugins/azure-sdk-dotnet/skills/azure-search-documents-dotnet · commit 0696600
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Microsoft.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download azure-search-documents-dotnet.zip