Azure.Search.Documents (.NET)
Créez des applications de recherche avec des capacités de recherche textuelle, vectorielle, sémantique et hybride.
Installation
dotnet add package Azure.Search.Documents
dotnet add package Azure.Identity
Versions actuelles : Stable v11.7.0, Preview v11.8.0-beta.1
Variables d'environnement
SEARCH_ENDPOINT=https://<search-service>.search.windows.net
SEARCH_INDEX_NAME=<index-name>
# Pour l'authentification par clé API (non recommandée en production)
SEARCH_API_KEY=<api-key>
Authentification
DefaultAzureCredential (préféré) :
using Azure.Identity;
using Azure.Search.Documents;
var credential = new DefaultAzureCredential();
var client = new SearchClient(
new Uri(Environment.GetEnvironmentVariable("SEARCH_ENDPOINT")),
Environment.GetEnvironmentVariable("SEARCH_INDEX_NAME"),
credential);
Clé API :
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);
Sélection du client
| Client | Objectif |
|---|---|
SearchClient |
Interroger les index, charger/mettre à jour/supprimer des documents |
SearchIndexClient |
Créer/gérer les index, mappages de synonymes |
SearchIndexerClient |
Gérer les indexeurs, skillsets, sources de données |
Création d'index
Utilisation de FieldBuilder (recommandé)
using Azure.Search.Documents.Indexes;
using Azure.Search.Documents.Indexes.Models;
// Définir le modèle avec attributs
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; }
}
// Créer l'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);
Définition manuelle des champs
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"
}
}
};
Opérations sur les documents
var searchClient = new SearchClient(endpoint, indexName, credential);
// Charger (ajouter nouveau)
var hotels = new[] { new Hotel { HotelId = "1", HotelName = "Hotel A" } };
await searchClient.UploadDocumentsAsync(hotels);
// Fusionner (mettre à jour existant)
await searchClient.MergeDocumentsAsync(hotels);
// Fusionner ou charger (upsert)
await searchClient.MergeOrUploadDocumentsAsync(hotels);
// Supprimer
await searchClient.DeleteDocumentsAsync("hotelId", new[] { "1", "2" });
// Opérations par lot
var batch = IndexDocumentsBatch.Create(
IndexDocumentsAction.Upload(hotel1),
IndexDocumentsAction.Merge(hotel2),
IndexDocumentsAction.Delete(hotel3));
await searchClient.IndexDocumentsAsync(batch);
Modèles de recherche
Recherche basique
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})");
}
Recherche facettée
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}");
}
Autocomplétion et suggestions
// Autocomplétion
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);
Recherche vectorielle
Voir references/vector-search.md pour les modèles détaillés.
using Azure.Search.Documents.Models;
// Recherche vectorielle pure
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);
Recherche sémantique
Voir references/semantic-search.md pour les modèles détaillés.
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);
// Accéder aux réponses sémantiques
foreach (var answer in results.Value.SemanticSearch.Answers)
{
Console.WriteLine($"Answer: {answer.Text} (Score: {answer.Score})");
}
// Accéder aux captions
await foreach (var result in results.Value.GetResultsAsync())
{
var caption = result.SemanticSearch?.Captions?.FirstOrDefault();
Console.WriteLine($"Caption: {caption?.Text}");
}
Recherche hybride (vectorielle + mots-clés + sémantique)
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 }
}
};
// Combine la recherche par mots-clés, la recherche vectorielle et le classement sémantique
var results = await searchClient.SearchAsync<Hotel>("luxury beachfront", options);
Référence des attributs de champ
| Attribut | Objectif |
|---|---|
SimpleField |
Champ non interrogeable (filtres, tri, facettes) |
SearchableField |
Champ interrogeable en texte intégral |
VectorSearchField |
Champ d'embedding vectoriel |
IsKey = true |
Clé du document (obligatoire, un par index) |
IsFilterable = true |
Activer les expressions $filter |
IsSortable = true |
Activer $orderby |
IsFacetable = true |
Activer la navigation facettée |
IsHidden = true |
Exclure des résultats |
AnalyzerName |
Spécifier l'analyseur de texte |
Gestion des erreurs
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}");
}
Bonnes pratiques
- Utiliser
DefaultAzureCredentialplutôt que les clés API en production - Utiliser
FieldBuilderavec les attributs de modèle pour les définitions d'index type-safe - Utiliser
CreateOrUpdateIndexAsyncpour la création idempotente d'index - Regrouper les opérations de documents pour un meilleur débit
- Utiliser
Selectpour retourner uniquement les champs nécessaires - Configurer la recherche sémantique pour les requêtes en langage naturel
- Combiner vectoriel + mots-clés + sémantique pour la meilleure pertinence
Fichiers de référence
| Fichier | Contenu |
|---|---|
| references/vector-search.md | Recherche vectorielle, recherche hybride, vectoriseurs |
| references/semantic-search.md | Classement sémantique, captions, réponses |