Configuring a Suggester with ExamineX and Azure AI Search

Configuring a Suggester with ExamineX and Azure AI Search

We recently had a customer ask about integrating the Azure AI Search suggester API with ExamineX and this turns out to be quite straight forward :)

First thing is to ensure that the fields you want to use the Suggester for are configured correctly:

// Configuration for the External Index for the City and Country fields.
// The Azure AI Search Suggester requires fields to be 'string fields only'
// and using the Standard Analyzer (default on the External Index)
services.Configure<AzureSearchIndexOptions>(
    Constants.UmbracoIndexes.ExternalIndexName,
    options =>
    {
         options.FieldDefinitions = new FieldDefinitionCollection(
            new FieldDefinition("City", AzureSearchFieldDefinitionTypes.FullText),
            new FieldDefinition("Country", AzureSearchFieldDefinitionTypes.FulText));
    });

Next up, is to create the Suggester which is done as part of the CreatingOrUpdatingIndex event:

externalIndex.CreatingOrUpdatingIndex += AzureIndex_CreatingOrUpdatingIndex_ScoringProfile;

private void AzureIndex_CreatingOrUpdatingIndex_Suggester(object sender, CreatingOrUpdatingIndexEventArgs e)
{
    switch (e.EventType)
    {
        case IndexModifiedEventType.Creating:
        case IndexModifiedEventType.Rebuilding:
            var index = e.AzureSearchIndexDefinition;

            var suggester = new SearchSuggester(
                "sg",
                new[] { "Country", "City" });

            index.Suggesters.Add(suggester);

            break;
    }
}

When data has been indexed for these fields, using the Suggester API is simple. For example, lets assume that the following ValueSets were indexed:

externalIndex.IndexItems(new[]
{
    ValueSet.FromObject(id1, new { City = "Calgary", Country = "Canada" }),
    ValueSet.FromObject(id2, new { City = "Sydney", Country = "Australia" }),
    ValueSet.FromObject(id3, new { City = "Copenhagen", Country = "Denmark" }),
    ValueSet.FromObject(id4, new { City = "Vienna", Country = "Austria" }),
});

Then to get suggestions for "Au":

// cast to AzureSearchIndex to expose underlying Azure Search APIs
var azureSearchIndex = (AzureSearchIndex)externalIndex;
var result = await  azureSearchIndex.IndexClient.SuggestAsync<ExamineDocument>(
    "Au",
    "sg");

The result will contain 2x entries, one for the Australia and one for the Austria documents. Super easy!

One thing to watch out for is if your index is not configured to use the Standard Analyzer by default (i.e. like the Internal Index in Umbraco). In that case, you'll need to define a custom field type with that indexer:

services.Configure<AzureSearchIndexOptions>(
    Constants.UmbracoIndexes.ExternalIndexName,
    options =>
    {
        // This adds a custom field type that uses the Standard Analyzer
        options.IndexValueTypesFactory = new Dictionary<string, IAzureSearchFieldValueTypeFactory>
        {
            ["standard"] = new AzureSearchFieldValueTypeFactory(s =>
                new AzureSearchFieldValueType(s, SearchFieldDataType.String, LexicalAnalyzerName.StandardLucene.ToString()))
        };

        // Set these field types to the one defined above
        options.FieldDefinitions = new FieldDefinitionCollection(
            new FieldDefinition("City", "standard"),
            new FieldDefinition("Country", "standard"));
    });

Happy Searching!

Author

Shannon Thompson

I'm a Senior Software Engineer working full time at Microsoft. Previously, I was working at Umbraco HQ for about 10 years. I maintain several open source projects (many related to Umbraco) such as Articulate, Examine and Smidge, and I also have a commercial software offering called ExamineX. Welcome to my blog :)

comments powered by Disqus