Copied to clipboard

Flag this post as spam?

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


  • Thomas 151 posts 326 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 151 posts 326 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 151 posts 326 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

  • This forum is in read-only mode while we transition to the new forum.

    You can continue this topic on the new forum by tapping the "Continue discussion" link below.

Please Sign in or register to post replies