Any tutorials or blog posts on adding a new custom field to an existing examine index?
u
I'm looking to add a single new field to the external index. This seemed like a trivial task and quite easy in v8 but all I can seem to find so far for modern Umbraco are articles about creating new indexes. TIA, tom
j
a
p
I came here to ask the same thing. Using the v12 docs I attempted to inherit from
ContentValueSetBuilder
and override
GetValueSets
to insert my custom field but it seems to have failed and it never seems to get called. I registered it in my startup.cs class as follows:
Copy code
public void ConfigureServices(IServiceCollection services)
{
    services.AddUnique<IContentValueSetBuilder, MyContentValueSetBuilder>();
    ...
}
I then have an
IComposer
as follows:
Copy code
public class ExamineComposer : IComposer
{
    public void Compose(IUmbracoBuilder builder)
    {
        builder.Services.AddSingleton<MyContentValueSetBuilder>(factory =>
            new MyContentValueSetBuilder(
                factory.GetRequiredService<PropertyEditorCollection>(),
                factory.GetRequiredService<UrlSegmentProviderCollection>(),
                factory.GetRequiredService<IUserService>(),
                factory.GetRequiredService<IShortStringHelper>(),
                factory.GetRequiredService<IScopeProvider>(),
                true,
                factory.GetRequiredService<ILocalizationService>(),
                factory.GetRequiredService<IUmbracoContextFactory>()));
    }
}
I had all sorts of trouble with the example in the documentation and the dependency injection so had to dig into the v12 source code to come up with the above. If anyone has had success with this I'd be interested in any pointers. I don't think the example from @Jemayn is suited to my situation when I have 50,000+ nodes to index and it seems like a legacy way of doing it (but could be wrong!).
l
I was able to create new fields, transformed from existing properties, in v12/13 by using the ConfigureOptions instructions in the documentation Ambert linked, and creating an Examine Component that did the value setting/transforming. Adding both to a composer of course. Didn't have to do anything with IValueSetValidator or adding to startup, though your case may be different. It is very similar to that article from Jemayn tho! Component trimmed snippet:
Copy code
public class ExamineComponents : IComponent
{
  // ... inits'n such
  private void IndexProviderTransformNewsValues(object? sender, IndexingItemEventArgs e) {
    // validate
  
    // Transform dates to use author set fields
    var aliases = new[] { "article", "event" };
    const string customSortField = "sortedDate"; // match custom index field name
    try
    {
      var contentTypeIds = _contentTypeService.GetAllContentTypeIds(aliases).ToList().ConvertAll(i => i.ToString());
      var values = e.ValueSet.Values.ToDictionary(
            x => x.Key, x => x.Value.ToList());
  
      values.TryGetValue("nodeType", out var nodeType);
      values.TryGetValue("createDate", out var fallbackDate);
  
      // document fields; 'good to know': dates are saved in DateTime.Ticks
      values.TryGetValue("publishedDate", out var publishedDate);
      values.TryGetValue("updatedDate", out var updatedDate);
  
      var nodeId = nodeType?.FirstOrDefault()?.ToString();
  
      // validation here
  
      if (publishedDate == null)
      { // fallbacks, see below for sample }
      else
      {
          values[customSortField] = updatedDate?.FirstOrDefault()?.ToString() != null
              ? updatedDate
              : publishedDate;
      }
  
      e.SetValues(values.ToDictionary(x => x.Key, x => (IEnumerable<object>)x.Value));
Didn't find any walkthroughs for setup from a very brief look around. I think I got this from Umbraco search training. Doesn't mean there aren't any out there though :3
u
I needed something quick to implement and @Jemayn blog post with a small change to prevent adding a field twice worked for me. I intend to go back to the docs later to fully understand it but I had to be able to demo something asap and that worked for me.
p
I don't think the docs are actually correct since if you follow them directly you get DI errors on start up when adding IndexValueSetBuilder as a Singleton. At the moment I don't know for sure what is the best approach but I'll take any that work which will allow me to continue until I can invest more time in it so thanks for sharing what you found does work.
j
My approach was based on some comments from Shannon (creator of Examine) in early v9 when it all changed (can't find the GH thread anymore). Can't say if it is still the best approach, but works fine and haven't had performance issues with large indexes as long as the code within the event is quick
p
At the moment I am implementing this in v12 but can't imagine it would be drastically different so thanks for the info. The main reason I need to insert the custom field is because it is a multi-site install and I need to limit search results so will be injecting a siteId into the index.
I think I have spotted what I was missing in my previous implementation. Working on it now and will share on here once finished if it works. It actually makes sense now I think about it and requires the
INotificationHandler
in conjunction with my
ContentValueSetBuilder
Not sure if it's just me but this seemed way more complicated than it perhaps should be to get here, but here goes... EDIT: After writing it all out I got told my message was too long so [see this Github Gist](https://gist.github.com/ProNotion/c1377570afa1a2ebe43fe27799c2ace9) Long story short, create a notification handler for
UmbracoApplicationStartedNotification
and register it in your composer. Inside your handler you will add an event handler for the Examine Index
TransformingIndexValues
(thanks @Jemayn & @Lamont) My original approach of using a
ContentValueSetBuilder
was fine but only works (for me) when publishing nodes but I need this to happen whenever the index is updated.
202 Views