Azure Cognitive Search is the search engine of choice when using Microsoft Azure. It comes with the same search features as search engines like Elastic Search and SOLR Search (you can even use the SOLR search query language).
One cool feature is the ability to create and delete an index based off a C# model class. This is very useful, as it enables you to store the index definition in code alongside your application, and you can create a command line interface to do index modifications easily.
The code is slightly longer than usual, but hold on, it’s not what complicated at all.
STEP 1: THE NUGET PACKAGES AND RFERENCES
You need the following references:
- Microsoft.Azure.Search
- Microsoft.Rest.ClientRuntime.Azure
- Newtonsoft.Json
- System.ComponentModel.DataAnnotations
STEP 2: CREATE A MANAGEMENT CONTEXT
This management context class is a class that will help create the index. It consists of an interface and a implementation.
namespace MyCode { public interface IIndexManagementContext { /// <summary> /// Create or update the index /// </summary> /// <typeparam name="T">The type of the index definition for the index to create or update</typeparam> void CreateOrUpdateIndex<T>() where T : IIndexDefinition, new(); /// <summary> /// Delete the index given by a given index definition. /// </summary> /// <typeparam name="T">The type of the index definition for the index to delete</typeparam> void DeleteIndex<T>() where T : IIndexDefinition, new(); } }
using System; using Microsoft.Azure.Search; using Microsoft.Azure.Search.Models; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; namespace MyCode { public class AzureIndexManagementContext : IIndexManagementContext { // Since the index name is stored in the index definition class, but should not // become an index field, the index name have been marked as "JSON ignore" // and the field indexer should therefore ignore the index name when // creating the index fields. private class IgnoreJsonIgnoreMarkedPropertiesContractResolver : DefaultContractResolver { protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization) { IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization); properties = properties.Where(p => !p.Ignored).ToList(); return properties; } } private readonly ISearchServiceClient _searchServiceClient; public AzureIndexManagementContext(string searchServiceName, string adminApiKey) { _searchServiceClient = new SearchServiceClient(searchServiceName, new SearchCredentials(adminApiKey)); } public void CreateOrUpdateIndex<T>() where T : IIndexDefinition, new() { string name = new T().IndexName; var definition = new Index { Name = name, Fields = FieldBuilder.BuildForType<T>(new IgnoreJsonIgnoreMarkedPropertiesContractResolver()) }; try { _searchServiceClient.Indexes.CreateOrUpdate(definition); } catch (Microsoft.Rest.Azure.CloudException e) { // TODO: Log the error and throw exception } } public void DeleteIndex<T>() where T : IIndexDefinition, new() { string name = new T().IndexName; try { _searchServiceClient.Indexes.Delete(name); } catch (Microsoft.Rest.Azure.CloudException e) { // TODO: Log the error and throw exception } } } }
STEP 3: CREATE A MODEL CLASS THAT DEFINES THE INDEX
This class will define the actual index. It uses attributes like IsFilterable and IsSearchable to define the properties for the index. You create one model class per index, and this is just one example of such a model class.
This also consists of one interface and one implementation.
using Newtonsoft.Json; namespace MyCode { public interface IIndexDefinition { // The name of the index. // Property is ignored when serialized to JSON [JsonIgnore] string IndexName { get; } } }
using System; using Microsoft.Azure.Search; using System.ComponentModel.DataAnnotations; using Sitecore.Configuration; namespace MyCode { // This is just an example index. You must create your own class // to define your index. public class UserIndexDefinition : IIndexDefinition { public string IndexName = "MyUserIndex"; // All indexes needs a key. [Key] public string IndexKey { get; set; } [IsFilterable] public string UserID { get; set; } [IsFilterable, IsSearchable] public string Firstname { get; set; } [IsFilterable, IsSearchable] public string LastName { get; set; } [IsFilterable, IsSearchable] public string FullName { get; set; } [IsFilterable, IsSearchable] public string Email { get; set; } [IsSortable] public DateTime CreatedDate { get; set; } } }
STEP 4: USE THE MANAGEMENT CONTEXT TO CREATE OR DELETE THE INDEX
First you need to create the context and the index model class. The “name” is the search index instance name, and the apikey1 is the “Primary Admin Key” as found in your Azure Search Index:
IIndexManagementContext indexManagementContext => new AzureIndexManagementContext("name", "apikey1"); IIndexDefinition userIndexDefinition => new UserIndexDefinition();
To create the index, use the following code:
var methodInfo = typeof(IIndexManagementContext).GetMethod("CreateOrUpdateIndex"); var genericMethod = methodInfo.MakeGenericMethod(userIndexDefinition.GetType()); genericMethod.Invoke(indexManagementContext, null);
To delete the index, use the following code:
var methodInfo = typeof(IIndexManagementContext).GetMethod("DeleteIndex"); var genericMethod = methodInfo.MakeGenericMethod(userIndexDefinition.GetType()); genericMethod.Invoke(indexManagementContext, null);
MORE TO READ:
- Azure Search Properties from Microsoft Documentation
- Azure Cognitive Search from Microsoft
- Using full Lucene Query Syntax in Azure Search from briancaos