Copied to clipboard

Flag this post as spam?

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


  • Thomas 160 posts 335 karma points
    Dec 11, 2020 @ 15:58
    Thomas
    0

    Examine Custom Index is not getting rebuilt every time I publish a node

    Hi,

    I created a custom examine index in order to use the custom fields of a document type and also to order by a custom date instead of the default updateDate. Everything works fine.

    Now i am using CMSImport, to import content to my site. From what i saw, the ExternalIndex is getting refreshed but the Custom index not. When i unpublish or unpublish a content, the ExternalIndex documents number is changing, the CustomIndex not.

    So, do i have to force reindex on publish and unpublish manually? And if yes, how to do it? Is there any sample?

    /Thomas

  • Thomas 160 posts 335 karma points
    Dec 12, 2020 @ 12:04
    Thomas
    0

    How the ExternalIndex is getting refreshed on every publish and unpublish, even more on massive imports using CMSImport? I created a component to rebuild my index on ContentSevice.Published and ContentSevice.UnPublished as follows

        [RuntimeLevel(MinLevel = RuntimeLevel.Run)]
    public class SubscribeToNewsArticleIndexRefreshComposer : ComponentComposer<NewsArticleIndexRefreshComponent>
    {
        //this automatically adds the component to the Components collection of the Umbraco composition
    }
    
    public class NewsArticleIndexRefreshComponent : IComponent
    {
        private readonly ILogger _logger;
        private readonly IExamineManager _examineManager;
        private readonly IndexRebuilder _indexRebuilder;
        private readonly IAppPolicyCache _runtimeCache;
    
        public NewsArticleIndexRefreshComponent(ILogger logger, IExamineManager examineManager, AppCaches appCaches, IndexRebuilder indexRebuilder)
        {
            _logger = logger;
            _examineManager = examineManager;
            _indexRebuilder = indexRebuilder;
            _runtimeCache = appCaches.RuntimeCache;
        }
    
        // initialize: runs once when Umbraco starts
        public void Initialize()
        {
            // subscribe to content service published event
            ContentService.Published += ContentService_Published;
            ContentService.Unpublished += ContentService_Unpublished;
        }
    
        // terminate: runs once when Umbraco stops
        public void Terminate()
        {
            // unsubscribe on shutdown
            ContentService.Published -= ContentService_Published;
            ContentService.Unpublished -= ContentService_Unpublished;
        }
    
        private void ContentService_Published(Umbraco.Core.Services.IContentService sender, Umbraco.Core.Events.ContentPublishedEventArgs e)
        {
            RebuildIndex();
        }
    
        private void ContentService_Unpublished(Umbraco.Core.Services.IContentService sender, Umbraco.Core.Events.PublishEventArgs<Umbraco.Core.Models.IContent> e)
        {
            RebuildIndex();
        }
    
        private void RebuildIndex()
        {
            bool validated = ValidateIndex("NewsArticleIndex", out var index);
            if (!validated)
                return;
    
            validated = ValidatePopulator(index);
            if (!validated)
                return;
    
            _logger.Info<NewsArticleIndexRefreshComponent>("Rebuilding index '{IndexName}'", index.Name);
    
            //remove it in case there's a handler there already
            index.IndexOperationComplete -= Indexer_IndexOperationComplete;
    
            //now add a single handler
            index.IndexOperationComplete += Indexer_IndexOperationComplete;
    
            try
            {
                //clear and replace
                index.CreateIndex();
    
                var cacheKey = "temp_indexing_op_" + index.Name;
                //put temp val in cache which is used as a rudimentary way to know when the indexing is done
                _runtimeCache.Insert(cacheKey, () => "tempValue", TimeSpan.FromMinutes(5));
    
                _indexRebuilder.RebuildIndex(index.Name);
            }
            catch (Exception ex)
            {
                //ensure it's not listening
                index.IndexOperationComplete -= Indexer_IndexOperationComplete;
                _logger.Error<NewsArticleIndexRefreshComponent>(ex, "An error occurred rebuilding index");
            }
        }
    
        private bool ValidateIndex(string indexName, out IIndex index)
        {
            if (!_examineManager.TryGetIndex(indexName, out index))
            {
                _logger.Error(GetType(), "NewsArticleIndexRefreshComponent | | Message: {0}", $"No index found by name < NewsArticleIndex >");
                return false;
            }
    
            return true;
        }
    
        private bool ValidatePopulator(IIndex index)
        {
            if (_indexRebuilder.CanRebuild(index))
                return true;
    
            _logger.Error(GetType(), $"The index {index.Name} cannot be rebuilt because it does not have an associated {typeof(IIndexPopulator)}");
            return false;
        }
    
        private void Indexer_IndexOperationComplete(object sender, EventArgs e)
        {
            var indexer = (IIndex)sender;
    
            _logger.Debug<NewsArticleIndexRefreshComponent>("Logging operation completed for index {IndexName}", indexer.Name);
    
            //ensure it's not listening anymore
            indexer.IndexOperationComplete -= Indexer_IndexOperationComplete;
    
            _logger.Info<NewsArticleIndexRefreshComponent>($"Rebuilding index '{indexer.Name}' done.");
    
            var cacheKey = "temp_indexing_op_" + indexer.Name;
            _runtimeCache.Clear(cacheKey);
        }
    }
    

    And in order the CustomIndex is getting the data from a GetAll() function which is

    public List<NewsArticle> GetAll()
        {
            try
            {
                using (UmbracoContextReference umbracoContextReference = _umbracoContextFactory.EnsureUmbracoContext())
                {
                    IPublishedContentCache contentHelper = umbracoContextReference.UmbracoContext.Content;
                    var publishedArticles = contentHelper.GetByXPath("//homeDocType/newsCategory/newsArticle")?.ToList();
                    if (publishedArticles != null)
                    {
                        var results = publishedArticles.Select(x => (NewsArticle)x).Where(x => x.IsPublished() && x.IsVisible()).ToList();
                        return results;
                    }
                    return null;
                }
    
                //To slow
                //var results = Services.ContentService.GetByLevel(3).Where(c => c.Published).ToList();
                //return results;
            }
            catch (Exception e)
            {
                _logService.Error(GetType(), "Search | Exception: {0} | Message: {1}", e.InnerException != null ? e.InnerException.ToString() : "", e.Message != null ? e.Message.ToString() : "");
            }
    
            return null;    
        }
    

    But unfortunately on the following line, I am getting a Null reference exception, probably the IPublishedCache is not available due to the publishing procedure? I don't really know

    var publishedArticles = contentHelper.GetByXPath("//homeDocType/newsCategory/newsArticle")?.ToList();
    

    So how the ExternalIndex is getting refreshed without locks and problems?

  • Thomas 160 posts 335 karma points
    Dec 14, 2020 @ 15:53
    Thomas
    0

    Any help please? This is urgent... I need to find a way to reindex the custom index on after publish event without errors.

    Thanks

  • Adriano Fabri 459 posts 1602 karma points
    Jun 01, 2021 @ 09:48
    Adriano Fabri
    0

    Hi Thomas,

    I have similar problem with my custom member index. On Save action (in backoffice or programmatically), my custom index doesn't rebuild so I cannot find new members in my search page until I manually rebuild the index.

    Have you find a solution for this problem?

    Thank you

    Adriano

  • Adriano Fabri 459 posts 1602 karma points
    Jun 01, 2021 @ 11:23
    Adriano Fabri
    0

    SOLVED

    I had to modify my Custom Index Creator as follows.

    Now I have my custom index always updated.

    Adriano

    using Examine;
    using Lucene.Net.Analysis.Standard;
    using Lucene.Net.Util;
    using System.Collections.Generic;
    using Umbraco.Core.Logging;
    using Umbraco.Core.Services;
    using Umbraco.Examine;
    using Umbraco.Web.Search;
    
    namespace AF.Examine.Index.Tools.For.UmbracoV8.Creators
    {
        public class AFMembersIndexCreator : UmbracoIndexesCreator
        {
            private readonly IProfilingLogger _profilingLogger;
            private readonly ILocalizationService _languageService;
            private readonly IPublicAccessService _publicAccessService;
            private readonly IMemberService _memberService;
            private readonly IUmbracoIndexConfig _iUmbracoIndexConfig;
    
            // Since Umbraco 8 has dependency injection out of the box, we can use it to inject
            // the different services that we need.
            public AFMembersIndexCreator(IProfilingLogger profilingLogger, 
                                            ILocalizationService languageService, 
                                            IPublicAccessService publicAccessService, 
                                            IMemberService memberService, 
                                            IUmbracoIndexConfig umbracoIndexConfig) : base(profilingLogger, languageService, publicAccessService, memberService, umbracoIndexConfig)
            {
                _profilingLogger = profilingLogger;
                _languageService = languageService;
                _publicAccessService = publicAccessService;
                _memberService = memberService;
                _iUmbracoIndexConfig = umbracoIndexConfig;
            }
    
            // Noticed that we return a collection of indexes? Technically you
            // can create multiple indexes in an indexCreator :) You can have a look at
            // UmbracoIndexesCreator.cs in the CMS core and see how the CMS does that.
            public override IEnumerable<IIndex> Create()
            {
                // create my AFMembersIndex definitions
                return new[] { CreateAFMembersIndex() };
            }
    
            private IIndex CreateAFMembersIndex()
            {
                var AFMembersIndex = new UmbracoMemberIndex(
                                                        "AFMembersIndex",
                                                        new FieldDefinitionCollection(
                                                            new FieldDefinition("memberId", FieldDefinitionTypes.FullText),
                                                            new FieldDefinition("memberNodeName", FieldDefinitionTypes.FullText),
                                                            new FieldDefinition("memberLoginName", FieldDefinitionTypes.FullText),
                                                            new FieldDefinition("memberEmail", FieldDefinitionTypes.FullText),
                                                            new FieldDefinition("memberName", FieldDefinitionTypes.FullText),
                                                            new FieldDefinition("memberSurname", FieldDefinitionTypes.FullText),
                                                            new FieldDefinition("memberIntTel", FieldDefinitionTypes.FullText),
                                                            new FieldDefinition("memberFax", FieldDefinitionTypes.FullText),
                                                            new FieldDefinition("memberCel", FieldDefinitionTypes.FullText)
                                                        ),
                                                        CreateFileSystemLuceneDirectory("AFMembersIndex"),
                                                        new StandardAnalyzer(Version.LUCENE_30),
                                                        ProfilingLogger,
                                                        UmbracoIndexConfig.GetMemberValueSetValidator());
    
                return AFMembersIndex;
            }
        }
    }
    
Please Sign in or register to post replies

Write your reply to:

Draft