Azure AI Search: Indexers and Indexes using C# Code
In this article, we will implement the Azure AI Search Service Data Source, Index, and Indexer creation using the C# code. We will implement the process using the ASP.NET Core 9 APIs. The application targets not only to configure Azure AI Search but also the application exposes API endpoints to perform search operations on the Data Source configured with Azure AI Search. Formally known as Azure Cognitive Search, the Azure AI Search is an enterprise-ready information retrieval system. We can build the heterogeneous contents information ingestion into search index e.g. Documents, Relational Data, etc to query so that the data can be retrieved. Teh Azure AI Service is designed for high-performance and scalability. Some of the features of Azure AI Search are as follows:
- Rich Indexing capabilities with content transformation, data chunking, vectorization for RAG.
- Vector and full-text search for data retrieval with efficiency.
- Advanced Query syntax
- Integration with other Azure Cloud hosted services
- Security and compliance
SELECT OrderID, Customers.ContactName AS CustomerName, Employees.FirstName + ' ' + Employees.LastName AS EmployeeName, OrderDate, RequiredDate, ShippedDate, Shippers.CompanyName AS ShipperName, Freight, ShipName, ShipAddress, ShipCity, ShipPostalCode, ShipCountry INTO OrdersReport FROM Orders, Customers, Employees, Shippers WHERE Customers.CustomerID = Orders.CustomerID AND Employees.EmployeeID = Orders.EmployeeID AND Shippers.ShipperID = Orders.ShipVia;
- Azure.Identity
- Azure.Search.Documents Version 11.6.0
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*", "AzureSettings": { "AzureAISearchEndPoint": "https://[AZURE-AI-SEARCH-ENDPOINT].search.windows.net", "AzureAISearchKey": "[AZURE-AI-SEARCH-PRIMARY-ADMIN-KEY]", "AzureAISearchIndexName": "shipping-index", "AzureAISearchIndexerName": "shipping-indexer", "AzureAISearchDataSourceName": "shipping-datasource", "AzureSQLDbConnectionString": "[AZURE-SQL-DATABASE-CONNECTION-STRING]" } }
using Azure.Search.Documents.Indexes; namespace Core_AISearch_Code.Models { public class ShippingIndex { [SimpleField(IsKey = true)] public string OrderID { get; set; } [SearchableField(IsFilterable = true)] public string? CustomerName { get; set; } [SearchableField(IsFilterable = true)] public string? EmployeeName { get; set; } public DateTime? OrderDate { get; set; } public DateTime? RequiredDate { get; set; } public DateTime? ShippedDate { get; set; } [SearchableField(IsFilterable = true)] public string? ShipperName { get; set; } [FieldBuilderIgnore] public decimal? Freight { get; set; } // Manually define in SearchField [SearchableField(IsFilterable = true)] public string? ShipName { get; set; } public string? ShipAddress { get; set; } [SearchableField(IsFilterable = true)] public string? ShipCity { get; set; } public string? ShipPostalCode { get; set; } [SearchableField(IsFilterable = true, IsSortable = true)] public string? ShipCountry { get; set; } } }
namespace Core_AISearch_Code.Models { public class Query { public string? SearchText { get; set; } } }
- AzureKeyCredential:
- This is a key-based authentication mechanism used in Azure SDKs to authenticate requests to Azure services. It allows to securely manage API keys without needing to create a new client when updating credentials. This class has the following features like:
- Secure authentication: This uses an API key to authenticate requests from the client application.
- Key rotation support: This allows updating the key dynamically without creating a new client.
- SearchIndexClient:
- This is a class in Azure AI Search that allows developers to manage search indexes programmatically. This provides methods for creating, updating, and deleting indexes, as well as configuring search settings. This class has following Key Features:
- Index Management: Used to Create, update, or delete search indexes.
- Alias Handling: Used to Manage search aliases for index versioning.
- Text Analysis: Use analyzers to process text for indexing.
- SearchIndexerDataSourceConnection:
- This is a class in Azure AI Search that defines a connection to a data source for an indexer. This class allows to configure how an indexer retrieves data from external sources like Azure Blob Storage, Azure SQL databases, or Cosmos DB, etc. The class has the following properties:
- ConnectionString: This Specifies the connection string to the data source so that the data can be queried.
- Container: This is used to define the data container for indexing e.g. Database Table, Azure Blob Container.
- DataChangeDetectionPolicy: This determines how changes in the data source are detected.
- DataDeletionDetectionPolicy: This configures how deleted records are handled.
- EncryptionKey: This supports encryption using Azure Key Vault for added security.
- SearchIndexerClient:
- This class in Azure AI Search is used to provide operations for managing indexers, data source connections, and skillsets. This class allows developers to automate data ingestion and indexing from external sources like Azure Blob Storage, SQL databases, and Cosmos DB. The class has the following features:
- Create, update, and delete indexers for automated data ingestion.
- Manage data source connections to link external data sources.
- Run and reset indexers to refresh indexed data.
- Retrieve indexer status to monitor indexing operations.
- SearchIndexer:
- This component in Azure AI Search is used to automates the process of extracting, transforming, and loading data into a search index. This is used to connects to various data sources, applies AI-powered enrichment, and ensures that indexed content remains up to date. The class has the following features:
- Automated Data Ingestion: This pulls data from the configured sources with Azure AI Search service like Azure Blob Storage, SQL databases, and Cosmos DB.
- AI-Powered Enrichment: This uses skillsets to enhance search results with natural language processing, image analysis, and entity recognition.
- Incremental Indexing: This detect and updates only changed records to optimize performance.
- Data Change & Deletion Detection: This ensures accurate indexing by tracking modifications and removals.
- IndexingParameters:
- This class in Azure AI Search is used to define parameters for indexer execution. This class allows developers to configure how data is processed during indexing. The class has following key features:
- Batch Size: This property is used to specify the number of items read from the data source and indexed as a single batch.
- Max Failed Items: This property sets the maximum number of items that can fail indexing before the process is considered unsuccessful.
- Max Failed Items Per Batch: This property defines the failure threshold for individual batches.
- Configuration: This property provides indexer-specific settings, such as parsing mode and data extraction preferences.
- SearchDocument:
- This class in Azure AI Search is used to represents an untyped document returned from a search query or document lookup. This class allows developers to access search results dynamically as either a dictionary or a dynamic object. The class has following properties:
- Flexible Data Access: This can be accessed using key-value pairs or dynamic properties.
- Supports JSON Serialization: This enables an easy conversion between JSON and search results.
using System.Reflection.Metadata; using Azure; using Azure.Search.Documents; using Azure.Search.Documents.Indexes; using Azure.Search.Documents.Indexes.Models; using Azure.Search.Documents.Models; using Core_AISearch_Code.Models; using Microsoft.Identity.Client.Platforms.Features.DesktopOs.Kerberos; namespace Core_AISearch_Code.Services { public class SearchServiceManager { AzureKeyCredential _credential; SearchIndexClient _indexClient; IConfiguration configuration; string searchKey, searchEndpoint; IConfiguration _configuration; public SearchServiceManager(IConfiguration configuration) { _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); searchKey = _configuration["AzureSettings:AzureAISearchKey"] ?? throw new ArgumentNullException("AzureSettings:AzureAISearchKey"); searchEndpoint = _configuration["AzureSettings:AzureAISearchEndPoint"] ?? throw new ArgumentNullException("AzureSettings:AzureAISearchEndPoint"); _credential = new AzureKeyCredential(searchKey); _indexClient = new SearchIndexClient(new Uri(searchEndpoint), _credential); } public void CreateIndex() { var fields = new FieldBuilder().Build(typeof(ShippingIndex)); var definition = new SearchIndex("shipping-index", fields); _indexClient.CreateOrUpdateIndex(definition); var connectionString = _configuration["AzureSettings:AzureSQLDbConnectionString"] ?? throw new ArgumentNullException("AzureSettings:AzureSQLDbConnectionString"); var dataSource = new SearchIndexerDataSourceConnection( name: "shipping-datasource", type: SearchIndexerDataSourceType.AzureSql, connectionString: connectionString, container: new SearchIndexerDataContainer("OrdersReport") ); var indexerClient = new SearchIndexerClient(new Uri(searchEndpoint), _credential); indexerClient.CreateOrUpdateDataSourceConnection(dataSource); var indexer = new SearchIndexer( name: "shipping-indexer", dataSourceName: dataSource.Name, targetIndexName: "shipping-index" ); indexer.Parameters = new IndexingParameters { BatchSize = 1, MaxFailedItems = -1, MaxFailedItemsPerBatch = -1 }; indexerClient.CreateOrUpdateIndexer(indexer); } public SearchResults<SearchDocument> Search(string searchText) { var client = new SearchClient(new Uri(searchEndpoint), "shipping-index", _credential); var options = new SearchOptions { Size = 10 }; return client.Search<SearchDocument>(searchText, options); } } }
............... builder.Services.AddSingleton<SearchServiceManager>(); ...............
................ app.MapGet("/index", () => { var searchServiceManager = app.Services.GetRequiredService<SearchServiceManager>(); searchServiceManager.CreateIndex(); return Results.Ok("Index created successfully."); }); app.MapGet("/search", (string searchText) => { var searchServiceManager = app.Services.GetRequiredService<SearchServiceManager>(); var results = searchServiceManager.Search(searchText); var output = new List<SearchDocument>(); foreach (var result in results.GetResults()) { output.Add(result.Document); } return Results.Ok(output); }); app.MapPost("/data", (Query query) => { var searchServiceManager = app.Services.GetRequiredService<SearchServiceManager>(); var results = searchServiceManager.Search(query.SearchText); var output = new List<SearchDocument>(); foreach (var result in results.GetResults()) { output.Add(result.Document); } return Results.Ok(output); }); ................