Umbraco 16, unable to change Examine field from Examine.Lucene.Indexing.FullTextType

I’ve tried various things, including AI assistance, without remedy. I seem to be unable to change Examine field from Examine.Lucene.Indexing.FullTextType on custom fields I add to examine.

I’m setting a custom field value like so:

EventsExamineComponent.cs:

private IndexingItemEventArgs SetSearchableValues(IndexingItemEventArgs args, IPublishedContent contentNode)
{
try
{
var updatedValues = args.ValueSet.Values.ToDictionary(x => x.Key, x => x.Value.ToList());

    //event
    if (contentNode?.ContentType.Alias == "event")
    {
        var eventNode = contentNode as Event;

        //dates, not working?
        if (eventNode != null)
        {
            var eventEndDateTimeKey = "event_endingDateTime";
            if (updatedValues.ContainsKey(eventEndDateTimeKey))
            {
                updatedValues.Remove(eventEndDateTimeKey);
            }
            var endDateValue = eventNode.DateTime;
            if (eventNode.EndDateTime > DateTime.MinValue)
            {
                endDateValue = eventNode.EndDateTime;
            }
            updatedValues.Add(eventEndDateTimeKey, new List<object> { endDateValue.ToUniversalTime().Ticks }); //.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss")
        }
    }

    args.SetValues(updatedValues.ToDictionary(x => x.Key, x => (IEnumerable<object>)x.Value));
}
catch (Exception e)
{
    \_logger.LogError(e, "SetSearchableValues: Exception: {0} | Message: {1} | Stack Trace: {2}", e.InnerException != null ? e.InnerException.ToString() : "", e.Message != null ? e.Message.ToString() : "", e.StackTrace);
}

return args;

}

I’m also telling umbraco to change from the default Examine.Lucene.Indexing.FullTextType:
ExternalIndexOptionsOverwrite.cs

using Examine;
using Examine.Lucene;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.DependencyInjection;

namespace My.Core.Composers
{
    
    public class ExamineComposer : IComposer
    {
        public void Compose(IUmbracoBuilder builder)
        {
            builder.Services.AddSingleton<IConfigureOptions<LuceneDirectoryIndexOptions>, ConfigureExternalIndexOptions>();
        }
    }
    public class ConfigureExternalIndexOptions : IConfigureNamedOptions<LuceneDirectoryIndexOptions>
    {
        public void Configure(string? name, LuceneDirectoryIndexOptions options)
        {
            if (name == Umbraco.Cms.Core.Constants.UmbracoIndexes.ExternalIndexName) // or your custom index name
            {
                options.FieldDefinitions.AddOrUpdate(new FieldDefinition("event_endingDateTime", FieldDefinitionTypes.Long));
            }
        }
        public void Configure(LuceneDirectoryIndexOptions options) { }
    }
    

    /*public class ExamineComposer : IComposer
    {
        public void Compose(IUmbracoBuilder builder)
        {
            builder.Services.ConfigureOptions<ExternalIndexOptionsOverwrite>();
        }
    }

    public class ExternalIndexOptionsOverwrite : IConfigureNamedOptions<LuceneDirectoryIndexOptions>
    {
        public void Configure(LuceneDirectoryIndexOptions options) => Configure(string.Empty, options);

        public void Configure(string? name, LuceneDirectoryIndexOptions options)
        {
            if (name?.Equals(Umbraco.Cms.Core.Constants.UmbracoIndexes.ExternalIndexName) is not true) return;

            options.FieldDefinitions.AddOrUpdate(new FieldDefinition("event_endingDateTime", FieldDefinitionTypes.Long));
        }
    }*/
}

I then try to use a range search, as my field event_endingDateTime should now be a Long:

 examineQuery = examineQuery.And().RangeQuery<long>(new[] { "event_endingDateTime" }, min: DateTime.UtcNow.Ticks, max: null);

And the result is:

InvalidOperationException: Could not perform a range query on the field event_endingDateTime, it’s value type is Examine.Lucene.Indexing.FullTextType

  • Examine.Lucene.Search.LuceneSearchQuery+<>c__DisplayClass13_0.b__0()

  • Examine.Lucene.Search.LateBoundQuery.get_Wrapped()

  • Examine.Lucene.Search.LuceneSearchExecutor.CheckQueryForExtractTerms(Query query)

  • Examine.Lucene.Search.LuceneSearchExecutor.CheckQueryForExtractTerms(Query query)

  • Examine.Lucene.Search.LuceneSearchExecutor.Execute()

  • Examine.Lucene.Search.LuceneSearchQuery.Search(QueryOptions options)

  • Examine.Lucene.Search.LuceneSearchQuery.Execute(QueryOptions options)

  • Examine.Lucene.Search.LuceneBooleanOperation.Execute(QueryOptions options)

You can do a rangeQuery on a DateTime too, rather than having to resort to tick conversion. Indeed I think for dateTime field definitions Lucene stores as ticks anyway.

query.And().RangeQuery<DateTime>(new[] { "expires"}, min: DateTime.Now, max: null);

you can also sort..
query.OrderBy(new SortableField("expires", SortType.Long));

with the corresponding index configuration..

public void Configure(string? name, LuceneDirectoryIndexOptions options)
{
    switch (name)
    {
        //NB you need to rebuild the examine index for these changes to take effect
        case Constants.UmbracoIndexes.ExternalIndexName:                    
            options.FieldDefinitions.TryAdd(new FieldDefinition("expires", FieldDefinitionTypes.DateTime));           
            break;
    }
}

Also I noticed I have a different registration to you, could that be your issue?
(docs Custom indexing | CMS | Umbraco Documentation)

 public class SearchComposer : IComposer
 {
     public void Compose(IUmbracoBuilder builder)
     {
         // Custom Examine configuration
         builder.Services.ConfigureOptions<ConfigureExamineIndexOptions>();
     }
 }

Finally you did rebuild the externalIndex after your changes? :thinking:

Thanks, I haven’t tried this yet as sorting ticks as strings seems to work for now, but hopefully I’ll have time to try your composer binding solution, thanks.

Wow! That was it! My composer was wrong. I used SearchComposer and it works. Thanks!

1 Like