Change default analyzers

See Customization - Default Analyzers for details

It is possible to change the default analyzer used for each index by replacing the IUmbracoIndexesCreator in your own Umbraco composer

Example:

[ComposeAfter(typeof(ExamineXComposer))]
[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
public class MyComposer : IUserComposer
{
    public void Compose(Composition composition)
    {
        // Replace the default ExamineX implementation
        composition.RegisterUnique<IUmbracoIndexesCreator, MyUmbracoIndexesCreator>();
    }
}

// Override the default ExamineX implementation
public class MyUmbracoIndexesCreator : ExamineXIndexFactory
{
    public MyUmbracoIndexesCreator(
        ExamineXConfig examineXConfig, IUmbracoIndexConfig umbracoIndexConfig, IExamineXLogger logger, 
        ILicenseManager licenceManager, IRuntimeState runtimeState, UmbracoIndexesCreator defaultFactory) 
    : base(examineXConfig, umbracoIndexConfig, logger, licenceManager, runtimeState, defaultFactory)
    {
    }

    // Replace the default analyzer for the internal index to be 
    // Microsoft's English Analyzer
    protected override IIndex CreateInternalIndex(string defaultAnalyzer) 
        => base.CreateInternalIndex(AnalyzerName.AsString.EnMicrosoft);
}

Default field types & analyzers

See Customization - Default field types & analyzers for details

Set the field definition for “productPrice” to be a Double

index.FieldDefinitionCollection.TryAdd(
    new FieldDefinition("productPrice", AzureSearchFieldDefinitionTypes.Double));
}

Custom field types & analyzers

See Customization - Custom field types & analyzers for details

If you want to define a custom field type, you can do that during index creation by passing in a value to the indexValueTypesFactory parameter of the AzureSearchIndex constructor. The value for this parameter is: IReadOnlyDictionary<string, IAzureSearchFieldValueTypeFactory> indexValueTypesFactory. The dictionary Key is the name of the field type and the Value is a factory that returns a IAzureSearchFieldValueTypeFactory for a given field name. ExamineX has a default implementation of this which includes all of the above default field types. If this parameter is specified, all of ExamineX’s default field types will still be used but you can override the custom implementations if a Key that you provide matches a default implementation.

This will create a Japanese field type with a “ja.microsoft” analyzer.

protected override IIndex CreateInternalIndex(string defaultAnalyzer)
{
    var customFieldTypeFactory = new Dictionary<string, IAzureSearchFieldValueTypeFactory>
    {
        // The name of this field type will be "ja.microsoft",
        // based on the value of this constant
        [AnalyzerName.AsString.JaMicrosoft] =
        // define the factory
        new AzureSearchFieldValueTypeFactory(fieldName =>
            new AzureSearchFieldValueType(
                fieldName,
                // This example will allow multiple values 
                // per field
                AzureSearchFieldValueType.StringCollectionType,
                // Use microsoft's Japanese analyzer
                AnalyzerName.AsString.JaMicrosoft))
    };

    var index = new UmbracoAzureSearchContentIndex(
        Constants.UmbracoIndexes.InternalIndexName,
        _licenceManager,
        _logger,
        _examineXConfig,
        _runtimeState,
        _umbracoIndexConfig.GetContentValueSetValidator(),
        new UmbracoFieldDefinitionCollection(),
        defaultAnalyzer,
        // Pass in the custom field types
        customFieldTypeFactory);

    return index;
}

The safest way to add/remove/modify field value types is to create a custom ExamineXIndexFactory (as in the above example) and override the OnCreatingIndexes to modify the FieldDefinitionCollection an index by using any of the following methods:

  • index.FieldDefinitionCollection.TryAdd
  • index.FieldDefinitionCollection.AddOrUpdate
  • index.FieldDefinitionCollection.GetOrAdd

Because this is a factory, this could be done to create a generic Language field type factory if your fields were named with the language name reference. For example, if your fields were suffixed with a language ISO code like: bodyText_ja-jp, bodyText_it-it, etc… you could return a specific language analyzer for the matched field name suffix.

To wire this up you need to pass this parameter to the index constructor which means you need to have a custom ExamineXIndexFactory (see above) and override the Create... methods for the index you want to customize.

Include custom indexes for ExamineX

By default, ExamineX only knows about the indexes created by Umbraco: Internal, External and Members indexes. If you have a custom index that you want to configure as an ExamineX index, you will need to implement a custom IUmbracoIndexesCreator that inherits from ExamineXIndexFactory, and then register it using a composer (see above example).

This example assumes that your custom index is based on Umbraco data which uses the UmbracoAzureSearchContentIndex, however, if your index is based on your own custom data source, than you would use UmbracoAzureSearchIndex. (Its worth noting that this process is much easier with modern versions of Umbraco).

public class MyUmbracoIndexesCreator : ExamineXIndexFactory
{
    private readonly ExamineXConfig _examineXConfig;
    private readonly IUmbracoIndexConfig _umbracoIndexConfig;
    private readonly IExamineXLogger _logger;
    private readonly ILicenseManager _licenceManager;
    private readonly IRuntimeState _runtimeState;

    public MyUmbracoIndexesCreator(
        ExamineXConfig examineXConfig, IUmbracoIndexConfig umbracoIndexConfig, IExamineXLogger logger,
        ILicenseManager licenceManager, IRuntimeState runtimeState, UmbracoIndexesCreator defaultFactory)
    : base(examineXConfig, umbracoIndexConfig, logger, licenceManager, runtimeState, defaultFactory)
    {
        _examineXConfig = examineXConfig;
        _umbracoIndexConfig = umbracoIndexConfig;
        _logger = logger;
        _licenceManager = licenceManager;
        _runtimeState = runtimeState;
    }

    protected override void OnCreatingIndexes(List<IIndex> indexes)
    {
        base.OnCreatingIndexes(indexes);

        const string indexName = "MyCustomIndex";
        IIndex index;

        // Check if this index has been disabled for ExamineX
        if (_examineXConfig.DisabledIndexes.Contains(indexName, StringComparer.OrdinalIgnoreCase))
        {
            // TODO: This is where your logic would be to create the normal Examine index
        }
        else
        {
            // Create the ExamineX index
            index = new UmbracoAzureSearchContentIndex(
                // Custom index Name
                indexName,
                _licenceManager, _logger, _examineXConfig, _runtimeState,
                // The IValueSetValidator to use (i.e. specify ParentId, etc...)
                _umbracoIndexConfig.GetPublishedContentValueSetValidator(),
                // The field definition collection to use
                new UmbracoFieldDefinitionCollection(),
                // The analyzer to use
                LexicalAnalyzerName.StandardLucene);
        }

        indexes.Add(index);
    }
}