<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Blog posts by Stellan Danald</title><link href="http://world.optimizely.com" /><updated>2017-08-01T11:51:05.0000000Z</updated><id>https://world.optimizely.com/blogs/stellan-danald/</id> <generator uri="http://world.optimizely.com" version="2.0">Optimizely World</generator> <entry><title>Running Find and Commerce on Azure/DXC? Read this...</title><link href="https://world.optimizely.com/blogs/stellan-danald/dates/2017/8/running-find-and-commerce-on-azuredxc-read-this/" /><id>&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;I recently ran into an issue which required a lot of time and effort to solve, and wanted to share my findings in case someone else runs into similar issues.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2&gt;Background&lt;/h2&gt;
&lt;p&gt;A client of ours is currently running a sizable Episerver Commerce site hosted in Azure by Episerver DXC.&lt;br /&gt;This particular site is one of the most integration heavy sites I&#39;ve had the pleasure to work with recently. As with many commerce sites, this one too is integrated with both a PIM and an ERP among other back-end systems. With well over 15K products and 150K variants, needless to say, it is a challenge to keep all information up to date on the site, with both new and updated products, variants and even inventory.&lt;/p&gt;
&lt;p&gt;To manage this, we have created an API that constantly receives product updates from the PIM and scheduled batch jobs that update the inventory from the clients ERP system.&lt;/p&gt;
&lt;p&gt;In the best interest of the end user (and for best performance), we put all this information in Episerver Find.&lt;br /&gt;When products/variants or inventory are updated, Episerver Find events are triggered which adds the related products or variants into the Find Indexing Queue (stored in the DDS in the CMS database). Any of currently running Episerver instances will process the queue as soon as there are any and update the document in Find, usually within seconds.&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;The Issue&lt;/h2&gt;
&lt;p&gt;After an internal effort by our client to improve the quality of the metadata of the products on the site, they came to us with some strange findings.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;After products/variants were imported from the PIM, they noticed that a few of the variants were missing information which they knew were in the PIM. And stranger yet, this wasn&#39;t happening all the time.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This particular subset of nested information is currently feeding an alternative navigation feature on the site, which made it very apparent when the product/variant they were looking for wasn&#39;t listed.&lt;br /&gt;&lt;br /&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Related findings&lt;/h2&gt;
&lt;p&gt;After realizing this was not a data/user issue, I did some additional digging and found the following things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If I reimported the same product, the same variants that were previously incorrect were correct, but other variants were incorrect.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;After manually re-indexing the product and variants from an Admin Plug-in we built, everything looked correct on the site. The difference here is that the content is being indexed by the instance I&#39;m currently on.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;To add even more to this mystery, there was nothing in the error logs that indicated that anything was wrong.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;This issue only occurred in the production environment. And we couldn&#39;t replicate this in any other environment.&lt;br /&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Page Types that were explicitly excluded in our Find client conventions still ended up in the index.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;When comparing the same Find document when it was incorrectly indexed, and later a correct one, I noticed that some of our properties which had nested conventions were missing the &quot;$$nested&quot; part of the name in the Find index.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;Knowing how an incorrect document looked in Find, I could now query it directly to get the exact number of failed products and variants, which showed that this issue actually had affected 5-10% of the entire catalog.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Hypothesis&lt;/h2&gt;
&lt;p&gt;My initial thought, however unlikely, was that one (or more) instances were not indexing correctly or wasn&#39;t initialized.&lt;br /&gt;Obviously, since all instances in Azure are running the same codebase, it wasn&#39;t completely logical, but either way, there are things I can do to confirm this theory, which I wanted to do before submitting a ticket with Episerver Developer support.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2&gt;Steps taken&lt;/h2&gt;
&lt;p&gt;The first thing I did was add additional logging and logging levels to our EPiServerLog.config, to make sure everything is initialized in the intended order.&lt;/p&gt;
&lt;pre class=&quot;language-xml&quot;&gt;&lt;code&gt;&amp;lt;logger name=&quot;EPiServer.Framework.Initialization&quot;&amp;gt;
    &amp;lt;level value=&quot;Debug&quot; /&amp;gt;
&amp;lt;/logger&amp;gt;

&amp;lt;logger name=&quot;EPiServer.Commerce.Initialization&quot;&amp;gt;
    &amp;lt;level value=&quot;Debug&quot; /&amp;gt;
&amp;lt;/logger&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;After deploying this, the logs clearly showed that our Find client conventions were initialized correctly on every single instance. At this point, we even re-indexed the whole site (which takes 2-3 hours), and everything seemed to be working. I queried the Find index and saw that the number of failed documents were counting down.&lt;/p&gt;
&lt;p&gt;However, the day after the deploy, the number had gone up again.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Still not convinced that this wasn&#39;t the root cause, I wanted to know which instance(s) that were failing, so I added an &quot;IndexedBy&quot; property to the product and variation models.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;public string IndexedBy =&amp;gt; EnvironmentUtility.GetEnviroment();&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;public class EnvironmentUtility
{
    public static string GetEnviroment()
    {
        var environment = $&quot;{Environment.GetEnvironmentVariable(&quot;WEBSITE_SITE_NAME&quot;)}:{Dns.GetHostName()}:{Environment.GetEnvironmentVariable(&quot;WEBSITE_INSTANCE_ID&quot;)}&quot;;

        return (environment.Length &amp;gt; 2 ? environment : Environment.MachineName);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Intriguingly enough, this did confirm my theory. I could see that all incorrect Find documents were indexed by the same Azure instance(s)!&lt;/p&gt;
&lt;p&gt;Even though the logs looked fine, I updated our initialization module containing our Find conventions so that they were executed at the very end of the initialization process, but that still didn&#39;t help. I also tried setting the nested convention using a typed implementation, instead of an interface, which also didn&#39;t help.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2&gt;The Solution&lt;/h2&gt;
&lt;p&gt;Obviously, this was a harder nut to crack than I initially thought, so at this point, I had reached out to Episerver developer support. Thanks to the work I had already put in, I did get a confirmation that this was a bug (which later turned out to be two) that will be fixed in future releases of Find.&lt;/p&gt;
&lt;p&gt;The final step I took (with the support of the Epi dev team), was instead of implementing our Find conventions in an &lt;em&gt;IInitializationModule&lt;/em&gt;, we let it inherit from &lt;em&gt;IConfigurableModule&lt;/em&gt;, and add the following&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;public void ConfigureContainer(ServiceConfigurationContext context)
{
    EventedIndexingSettings.Instance.IndexingQueueBatchSize = 0;

    if (Logger.IsEnabled(Level.Information)) 
        Logger.Log(Level.Information, &quot;Setting IndexingQueueBatchSize to 0 #find&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then adding the following lines to the Initialize() method&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;var batchSize = EPiServer.Find.Configuration.GetConfiguration().IndexingQueueBatchSize;

EventedIndexingSettings.Instance.IndexingQueueBatchSize = batchSize;

if (Logger.IsEnabled(Level.Information)) 
    Logger.Log(Level.Information, $&quot;Setting IndexingQueueBatchSize to {batchSize} #find&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;&lt;br /&gt;Root Cause&lt;/h2&gt;
&lt;p&gt;As you probably can tell by the code above, the root cause was that WHEN and IF there are items in the Find Indexing Queue, when an Azure web site (re)starts, it will start processing the queue before our Find conventions (which are commerce dependent) were completely initialized(!). At that point, it doesn&#39;t help to re-apply the conventions (I built an admin plug-in to try that as well).&lt;/p&gt;
&lt;p&gt;This is probably one of those edge cases where you have to have a site that is constantly updating the Find index, while utilizing CMS, Commerce and Find and is hosted in a load balanced environment, but please rate and/or comment if you find this article interesting or helpful!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;/em&gt;&lt;/strong&gt;&lt;strong&gt;Thanks!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Stellan Danald&lt;br /&gt;&lt;em&gt;Solutions Architect @ Making Waves&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S.&lt;/strong&gt; Have you checked out the EPiServer Slack Community?&lt;br /&gt; &lt;a href=&quot;https://episervercommunity.net/&quot;&gt;https://episervercommunity.net/&lt;/a&gt; - Read about it at &lt;a href=&quot;/link/c26f2ae236034e47882ee706a3875a18.aspx&quot;&gt;https://world.episerver.com/blogs/stellan-danald/dates/2017/6/episerver-slack-community/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;An additional tip*&lt;/em&gt;&lt;/strong&gt;&lt;br /&gt;If you want to see how many references are in your Find indexing queue, run the following SQL script in your CMS database&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;SELECT COUNT(1)
FROM [dbo].[tblBigTable]
WHERE [StoreName] = &#39;EPiServer.Find.Cms.IndexingQueueReference&#39;

SELECT COUNT(1)
FROM [dbo].[tblBigTableIdentity]
WHERE [StoreName] = &#39;EPiServer.Find.Cms.IndexingQueueReference&#39;&lt;/code&gt;&lt;/pre&gt;
&lt;/body&gt;
&lt;/html&gt;</id><updated>2017-08-01T11:51:05.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Episerver Slack Community</title><link href="https://world.optimizely.com/blogs/stellan-danald/dates/2017/6/episerver-slack-community/" /><id>&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;p&gt;For the last couple of years, we have been utilizing &lt;a href=&quot;https://slack.com/&quot;&gt;Slack&lt;/a&gt; as our primary communication tool. It&#39;s fast, searchable, direct, (practically) spam free and lets you effortlessly collaborate easier in or across offices without cluttering your inbox.&lt;/p&gt;
&lt;p&gt;Not too long ago, I&#39;ve started to join other slack teams/communities within my field or with my friends. What appeared to me is there currently is no Episerver Slack community. I&#39;ve seen several other targeted at other CMS&#39;s, like SiteCore, Drupal etc., but not Episerver, which somewhat surprises me considering the huge effort Episerver has put into building a community. Ever since I started working with the Episerver platform, I&#39;ve always thought that the community was really great. They have frequent meetups all over the world, Blogs, the world.episerver.com portal with the forum and support pages, the EMVP initiative to encourage the Episerver community, Episerver Ascends, the recently started &lt;a href=&quot;/link/4d36bbc1d75940b5ab798c8924d423f5.aspx&quot;&gt;Episerver Coders webinars&lt;/a&gt; and other sales and/or dev related events.&lt;/p&gt;
&lt;p&gt;In our internal Slack group, we do have #episerver channels where anyone can ask the MW epi developers random Q/A, which is not only a great brain-trust to quickly tap into, but also a simple way to help junior developers to ramp up quickly. I don&#39;t mean to devalue the dev-to-dev forum on world.episerver.com, but imagine the vast amount of knowledge and experience we could gather if we get some, or even most, of the distinguished Episerver minds together in a tool that I believe many of us are already using. It&#39;s a natural step and will make the Episerver community become even closer!&lt;/p&gt;
&lt;p&gt;To kick this off I&#39;ve started both the Episerver slack community, set up a dedicated website for easy (and automated) registration, created a bunch of more or less obvious channels/topics related to Episerver related products/features.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/13d6d656f7654a28a4377550f2268b06.aspx&quot; alt=&quot;Image epi-heart-slack.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;It is totally free, non-exclusive and not affiliated with the company Episerver.&lt;/p&gt;
&lt;p&gt;Register now at&amp;nbsp;&lt;a href=&quot;https://episervercommunity.net&quot;&gt;https://episervercommunity.net&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Code of conduct can be read &lt;a href=&quot;https://episervercommunity.net/codeofconduct&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Happy coding and see you there!&lt;br /&gt;Stellan Danald,&lt;br /&gt;Solutions Architect @ Making Waves&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;</id><updated>2017-06-26T02:49:10.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Episerver Find - Conditional Sorting?</title><link href="https://world.optimizely.com/blogs/stellan-danald/dates/2016/12/episerver-find---conditional-sorting/" /><id>&lt;p&gt;A client asked me if it was possible to push a specific variation to the top of a list that is coming from Find. I immediately replied &quot;Of course!&quot;, since like most things working with development, almost everything is possible; It&#39;s just a matter of time/effort, and I thought it would be a quick&amp;nbsp;change.&lt;/p&gt;
&lt;p&gt;When I first looked into the task, I noticed that the list was set to order by the variations &lt;em&gt;SortOrder&amp;nbsp;&lt;/em&gt;and not score, so boosting wasn&#39;t really an option.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;SearchClient.Instance.Search&amp;lt;VariationContent&amp;gt;()
	.Filter(x =&amp;gt; x.Parents.Match(refId.ToString()))
	&amp;hellip;&amp;hellip; // Other visibility conditions, facets/terms/skip/take etc
	.OrderBy(x =&amp;gt; x.SortOrder)
	.GetResult();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;My next step was to see if there are any possibilities do to a conditional sort, as in sorting with filters, or perhaps using &lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-sort.html&quot;&gt;custom script sorting&lt;/a&gt; which you can do with &lt;a href=&quot;https://www.elastic.co/products/elasticsearch&quot;&gt;Elasticsearch&lt;/a&gt;&amp;nbsp;that&amp;nbsp;&lt;a href=&quot;http://find.episerver.com/&quot;&gt;Episerver Find&lt;/a&gt; is based upon. After &lt;em&gt;a lot&lt;/em&gt; of googling and plowing through a lot of interesting blog posts and questions on &lt;a href=&quot;/link/6c9478a8761c41d88dfc32e9ef56e714.aspx&quot;&gt;world.episerver.com&lt;/a&gt;, I couldn&#39;t find anything that was related to my task.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;Next step was to do some reflection of the &lt;strong&gt;Episerver.Find&lt;/strong&gt; assembly. What I found there was that it &lt;strong&gt;IS&lt;/strong&gt; possible, &lt;strong&gt;IF&lt;/strong&gt; you were sorting by nested objects, using the following method in the &lt;em&gt;Episerver.Find.NestedSortingExtensions&lt;/em&gt; class&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;.OrderBy(enumerableFieldSelector, itemFieldSelector, filterExpression)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unfortunately, there aren&#39;t any existing methods that does what I was looking for, e.g.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;.OrderBy(fieldSelector, filterExpression)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;Taking another look at the &lt;a href=&quot;/link/8b77b657138f45cfb78b2b583905101e.aspx&quot;&gt;Find SDK&lt;/a&gt;, I stumbled upon &lt;a href=&quot;/link/e11091db0e424a3c92eb39ae12b58a24.aspx&quot;&gt;.Include(filterExpression, boostMultiplier)&lt;/a&gt;, which, together with the extension &lt;a href=&quot;https://gist.github.com/lindstromhenrik/9779858&quot;&gt;.ThenByScore()&lt;/a&gt;, written by &lt;a href=&quot;/link/d99f9563c9ff482c98393641f4e03dc5.aspx?page=1&quot;&gt;Henrik Lindstr&amp;ouml;m&lt;/a&gt;, that we already use, would help me with my task.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;.Include(filterExpression, boostMultiplier)&lt;/em&gt;&amp;nbsp;allowes&amp;nbsp;me to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Search for my specific item, using the regular &lt;em&gt;.For(query)&amp;nbsp;&lt;/em&gt;with the &lt;em&gt;.InField(fieldSelector)&lt;/em&gt; and &lt;em&gt;.Filter(filterExpression)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Get the rest of the variations with the same boosting score (since they don&#39;t get a hit in the .For), that I can then order using the field SortOrder, just like before.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The final solution was&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;SearchClient.Instance.Search&amp;lt;VariationContent&amp;gt;()
	.For(itemId)
	.InField(x =&amp;gt; x.ItemId)
	.Filter(x =&amp;gt; x.Parents.Match(refId.ToString()))
	.Include(x =&amp;gt; x.Parents.Match(refId.ToString()), 1)
	&amp;hellip;&amp;hellip; // Other visibility conditions, facets/terms/skip/take etc
	.OrderByScore()
	.ThenBy(x =&amp;gt; x.SortOrder)
	.GetResult();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;I&#39;m sure there are multiple ways to achieve the same results, but this was the simplest way I could do it and it might help someone else.&lt;/p&gt;
&lt;p&gt;Cheers! /&lt;br /&gt;Stellan Danald,&lt;br /&gt;Solutions Architect @ &lt;a href=&quot;http://www.nansen.com&quot;&gt;Nansen&lt;/a&gt;&lt;/p&gt;
</id><updated>2016-12-06T02:53:35.0000000Z</updated><summary type="html">Blog post</summary></entry></feed>