Azure AI Search SDK pour TypeScript
Créez des applications de recherche avec des capacités de recherche vectorielle, hybride et sémantique.
Installation
npm install @azure/search-documents @azure/identity
Variables d'environnement
AZURE_SEARCH_ENDPOINT=https://<service-name>.search.windows.net
AZURE_SEARCH_INDEX_NAME=my-index
AZURE_SEARCH_ADMIN_KEY=<admin-key> # Optionnel si vous utilisez Entra ID
AZURE_TOKEN_CREDENTIALS=prod # Requis uniquement si DefaultAzureCredential est utilisé en production
Authentification
import { SearchClient, SearchIndexClient } from "@azure/search-documents";
import { DefaultAzureCredential, ManagedIdentityCredential } from "@azure/identity";
const endpoint = process.env.AZURE_SEARCH_ENDPOINT!;
const indexName = process.env.AZURE_SEARCH_INDEX_NAME!;
// Dev local : DefaultAzureCredential. Production : définir AZURE_TOKEN_CREDENTIALS=prod ou AZURE_TOKEN_CREDENTIALS=<specific_credential>
const credential = new DefaultAzureCredential({requiredEnvVars: ["AZURE_TOKEN_CREDENTIALS"]});
// Ou utiliser une credential spécifique directement en production :
// Voir https://learn.microsoft.com/javascript/api/overview/azure/identity-readme?view=azure-node-latest#credential-classes
// const credential = new ManagedIdentityCredential();
// Pour la recherche
const searchClient = new SearchClient(endpoint, indexName, credential);
// Pour la gestion d'index
const indexClient = new SearchIndexClient(endpoint, credential);
Flux de travail principal
Créer un index avec champ vectoriel
import { SearchIndex, SearchField, VectorSearch } from "@azure/search-documents";
const index: SearchIndex = {
name: "products",
fields: [
{ name: "id", type: "Edm.String", key: true },
{ name: "title", type: "Edm.String", searchable: true },
{ name: "description", type: "Edm.String", searchable: true },
{ name: "category", type: "Edm.String", filterable: true, facetable: true },
{
name: "embedding",
type: "Collection(Edm.Single)",
searchable: true,
vectorSearchDimensions: 1536,
vectorSearchProfileName: "vector-profile",
},
],
vectorSearch: {
algorithms: [
{ name: "hnsw-algorithm", kind: "hnsw" },
],
profiles: [
{ name: "vector-profile", algorithmConfigurationName: "hnsw-algorithm" },
],
},
};
await indexClient.createOrUpdateIndex(index);
Indexer des documents
const documents = [
{ id: "1", title: "Widget", description: "A useful widget", category: "Tools", embedding: [...] },
{ id: "2", title: "Gadget", description: "A cool gadget", category: "Electronics", embedding: [...] },
];
const result = await searchClient.uploadDocuments(documents);
console.log(`Indexed ${result.results.length} documents`);
Recherche en texte intégral
const results = await searchClient.search("widget", {
select: ["id", "title", "description"],
filter: "category eq 'Tools'",
orderBy: ["title asc"],
top: 10,
});
for await (const result of results.results) {
console.log(`${result.document.title}: ${result.score}`);
}
Recherche vectorielle
const queryVector = await getEmbedding("useful tool"); // Votre fonction d'embedding
const results = await searchClient.search("*", {
vectorSearchOptions: {
queries: [
{
kind: "vector",
vector: queryVector,
fields: ["embedding"],
kNearestNeighborsCount: 10,
},
],
},
select: ["id", "title", "description"],
});
for await (const result of results.results) {
console.log(`${result.document.title}: ${result.score}`);
}
Recherche hybride (texte + vecteur)
const queryVector = await getEmbedding("useful tool");
const results = await searchClient.search("tool", {
vectorSearchOptions: {
queries: [
{
kind: "vector",
vector: queryVector,
fields: ["embedding"],
kNearestNeighborsCount: 50,
},
],
},
select: ["id", "title", "description"],
top: 10,
});
Recherche sémantique
// L'index doit avoir une configuration sémantique
const index: SearchIndex = {
name: "products",
fields: [...],
semanticSearch: {
configurations: [
{
name: "semantic-config",
prioritizedFields: {
titleField: { name: "title" },
contentFields: [{ name: "description" }],
},
},
],
},
};
// Rechercher avec classement sémantique
const results = await searchClient.search("best tool for the job", {
queryType: "semantic",
semanticSearchOptions: {
configurationName: "semantic-config",
captions: { captionType: "extractive" },
answers: { answerType: "extractive", count: 3 },
},
select: ["id", "title", "description"],
});
for await (const result of results.results) {
console.log(`${result.document.title}`);
console.log(` Caption: ${result.captions?.[0]?.text}`);
console.log(` Reranker Score: ${result.rerankerScore}`);
}
Filtrage et facettes
// Syntaxe de filtre
const results = await searchClient.search("*", {
filter: "category eq 'Electronics' and price lt 100",
facets: ["category,count:10", "brand"],
});
// Accéder aux facettes
for (const [facetName, facetResults] of Object.entries(results.facets || {})) {
console.log(`${facetName}:`);
for (const facet of facetResults) {
console.log(` ${facet.value}: ${facet.count}`);
}
}
Autocomplétion et suggestions
// Créer un suggesteur dans l'index
const index: SearchIndex = {
name: "products",
fields: [...],
suggesters: [
{ name: "sg", sourceFields: ["title", "description"] },
],
};
// Autocomplétion
const autocomplete = await searchClient.autocomplete("wid", "sg", {
mode: "twoTerms",
top: 5,
});
// Suggestions
const suggestions = await searchClient.suggest("wid", "sg", {
select: ["title"],
top: 5,
});
Opérations par lot
// Upload, fusion, suppression par lot
const batch = [
{ upload: { id: "1", title: "New Item" } },
{ merge: { id: "2", title: "Updated Title" } },
{ delete: { id: "3" } },
];
const result = await searchClient.indexDocuments({ actions: batch });
Types principaux
import {
SearchClient,
SearchIndexClient,
SearchIndexerClient,
SearchIndex,
SearchField,
SearchOptions,
VectorSearch,
SemanticSearch,
SearchIterator,
} from "@azure/search-documents";
Bonnes pratiques
- Utilisez la recherche hybride - Combinez vecteur + texte pour les meilleurs résultats
- Activez le classement sémantique - Améliore la pertinence pour les requêtes en langage naturel
- Chargez les documents par lot - Utilisez
uploadDocumentsavec des tableaux, pas des documents individuels - Utilisez des filtres pour la sécurité - Implémentez la sécurité au niveau des documents avec des filtres
- Indexez progressivement - Utilisez
mergeOrUploadDocumentspour les mises à jour - Supervisez les performances des requêtes - Utilisez
includeTotalCount: trueavec parcimonie en production