Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Ismail Mayat 4511 posts 10090 karma points MVP 2x admin c-trib
    Sep 26, 2019 @ 12:25
    Ismail Mayat
    0

    How to create custom index in v8

    In v7 to create custom index you had to implement ISimpleDataService interface and over ride getdata. In 8 looking at https://our.umbraco.com/Documentation/Reference/Searching/Examine/indexing/ this seems to be for Umbraco content index.

    Looking at examine source with webdemo for custom non umbraco content seems like in startup you create index. Then create controller to rebuild the index with your data source see https://github.com/Shazwazza/Examine/blob/master/src/Examine.Web.Demo/Global.asax.cs

    Or am i reading this wrong? Has anyone already done this?

    Regards

    Ismial

  • Mark Bowser 273 posts 860 karma points c-trib
    Sep 26, 2019 @ 14:51
    Mark Bowser
    0

    I believe you need to create an IndexPopulator for your index. Make sure to implement the PopulateIndexes method. I'm pulling this pretty much directly from the v8 bridging course for searching and indexing, but I haven't put it into practice outside of that training yet. Let me know if this does the trick:

    The IndexPopulator

    public class TodoIndexPopulator : IndexPopulator
    {
    
        private readonly TodoValueSetBuilder _todoValueSetBuilder;
    
        public TodoIndexPopulator(TodoValueSetBuilder productValueSetBuilder)
        {
            _todoValueSetBuilder = productValueSetBuilder;
    
            RegisterIndex("TodoIndex");
        }
    
        protected override void PopulateIndexes(IReadOnlyList<IIndex> indexes)
        {
            using (var httpClient = new WebClient())
            {
                var jsonData = httpClient.DownloadString("https://jsonplaceholder.typicode.com/todos/");
                var data = JsonConvert.DeserializeObject<IEnumerable<ToDoModel>>(jsonData);
    
                if (data != null)
                {
                    foreach(var item in indexes)
                    {
                        item.IndexItems(_todoValueSetBuilder.GetValueSets(data.ToArray()));
                    }
                }
    
            }
        }
    }
    

    This IValueSetBuilder

    public class TodoValueSetBuilder : IValueSetBuilder<ToDoModel>
    {
        public IEnumerable<ValueSet> GetValueSets(params ToDoModel[] data)
        {
            foreach (var todo in data)
            {
                var indexValues = new Dictionary<string, object>
                {
                    ["userId"] = todo.UserId,
                    ["id"] = todo.Id,
                    ["title"] = todo.Title,
                    ["completed"] = todo.Completed
                };
    
                var valueSet = new ValueSet(todo.Id.ToString(), "todo", indexValues);
    
                yield return valueSet;
            }
        }
    }
    

    Composer

    [RuntimeLevel(MinLevel = RuntimeLevel.Run)]
    public class ExamineComposerPublic : IUserComposer
    {
        public void Compose(Composition composition)
        {
            //Add our component
            composition.Components().Append<ExamineComponents>();
    
            composition.RegisterUnique<TodoValueSetBuilder>();
            composition.Register<TodoIndexPopulator>(Lifetime.Singleton);
            composition.RegisterUnique<TodoIndexCreator>();
    
        }
    }
    
  • Ismail Mayat 4511 posts 10090 karma points MVP 2x admin c-trib
    Sep 26, 2019 @ 15:16
    Ismail Mayat
    0

    Cool, many thanks for this. I did ask the other day on umbraco slack if bridging course had been done by anyone lol.

    Im hoping to get on it soon.

    Regards

    Ismail

  • Ismail Mayat 4511 posts 10090 karma points MVP 2x admin c-trib
    Sep 26, 2019 @ 15:49
    Ismail Mayat
    0

    Whats in ExamineComponents and TodoIndexCreator ?

  • Ismail Mayat 4511 posts 10090 karma points MVP 2x admin c-trib
    Sep 26, 2019 @ 16:27
  • Mark Bowser 273 posts 860 karma points c-trib
    Sep 26, 2019 @ 16:34
    Mark Bowser
    0

    Take the rest of this as a starting point. It is also basically copy pasted from the v8 bridging course, but I think started messing with it and don't know what state I left it in.

    IndexCreator

    The IndexCreator is a LuceneIndexCreator. It returns an IEnumerable

    public class TodoIndexCreator : LuceneIndexCreator
    {
        private ILogger ProfilingLogger { get; }
    
        public TodoIndexCreator(ILogger profilingLogger)
        {
            ProfilingLogger = profilingLogger;
        }
    
        public override IEnumerable<IIndex> Create()
        {
            var index = new TodoExamineIndex("TodoIndex",
                CreateFileSystemLuceneDirectory("TodoIndex"),
                new FieldDefinitionCollection(
                new FieldDefinition("userId", FieldDefinitionTypes.Integer),
                new FieldDefinition("id", FieldDefinitionTypes.Integer),
                new FieldDefinition("title", FieldDefinitionTypes.FullTextSortable),
                new FieldDefinition("completed", FieldDefinitionTypes.FullTextSortable)),
                new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30),
                null,
                null,
                ProfilingLogger);
    
            return new[] { index };
        }
    }
    

    IndexComponent

    The IndexComponent in the example I posted is where all the custom indexing logic happens. In the bridging course, it adds the todo index to the ExamineManager's list of indexes, and combines all of the fields into one aggregated field that users can search on. I won't post the whole thing, but I'll add some snippets here:

    Add index to Examine Manager

    foreach (var data in _todoIndexCreator.Create())
    {
        _examineManager.AddIndex(data);
    }
    

    Attach to IndexProviderTransformingIndexValues to make aggregate field

        //we need to cast because BaseIndexProvider contains the TransformingIndexValues event
        if (!(index is BaseIndexProvider indexProvider))
        {
            throw new InvalidOperationException("Could not cast");
        }
    
        indexProvider.TransformingIndexValues += IndexProviderTransformingIndexValues;
    }
    
    /// <summary>
    /// Combine all fields into single aggregate field
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void IndexProviderTransformingIndexValues(object sender, IndexingItemEventArgs e)
    {
    
        //this is the replacement for the GatheringNodeData
    
        if (e.ValueSet.Category == IndexTypes.Content)
        {
            try
            {
                var combinedFields = new StringBuilder();
                foreach (var fieldValues in e.ValueSet.Values)
                {
                    foreach (var value in fieldValues.Value)
                    {
                        if (value != null)
                        {
                            combinedFields.AppendLine(value.ToString());
                        }
                    }
                }
    
                e.ValueSet.Add("contents", combinedFields.ToString());
            }
            catch (Exception ex)
            {
                _logger.Error<ExamineComponents>(ex, "Error combining fields for {ValueSetId}", e.ValueSet.Id);
            }
        }
    }
    

    Attach to DocumentWriting to do some boosting

        if (!(index is LuceneIndex luceneIndex))
        {
            throw new InvalidOperationException("Could not cast");
        }
    
        luceneIndex.DocumentWriting += LuceneIndex_DocumentWriting;
    }
    
    private void LuceneIndex_DocumentWriting(object sender, global::Examine.LuceneEngine.DocumentWritingEventArgs e)
    {
    
        //if its blog item and the blog tag is set to cheese boost it else set it to 1
        var nodeTypeAlias = e.ValueSet.ItemType;
        if (nodeTypeAlias?.ToString() == "blogpost")
        {
            var newsTag = e.ValueSet.GetValue("categories");
            if (newsTag != null && newsTag.ToString().InvariantContains("cheese"))
            {
                e.Document.Boost = 1000;
            }
            else
            {
                e.Document.Boost = 1; //may have been set to cheese before and now been changed
            }
        }
    }
    
Please Sign in or register to post replies

Write your reply to:

Draft