Using EPiServer CMS 11Using EPiServer Find 13
I've a requirement to get all decendent pages in couple of places in a site I'm working on, we may also want to narrow the results to a particular type of page.
Is using EPiServer Find a good alternative to GetDescendants? Part of me thinks querying the database by hand may be the fastest option, though that is not as easy to maintain as just using the EPiServer CMS API, but I see other blog posts mentioning that EPiFind may be the best option? This seams dubious to me as EPiFind would require an http call etc etc, while the API should just be able to query the sql server db and get results out real quick, unless EPiFind has some clever caching going on? What is the accepted wisdom on this one?
The use case is we wish to list all blog/news/events/etc pages, and editors add to the list by adding child pages under the parent.
IContentRepository.GetDescendents, in most of the cases, a bad choice for performance. Find is simply superior to that, it has better API and is much, much faster.
Retrieving data from Episerver database is a very expensive operation, especially in Azure.
You could install a profiler like Prefix (https://stackify.com/prefix/) to see what's going on under the hood, and how many requests are sent to a database on page load for non-cached listing pages.
Episerver Find can improve performance, but you should use projections (https://world.episerver.com/documentation/developer-guides/find/NET-Client-API/searching/Projections/). Standard .GetContentResult() method retrieves only content IDs from Elasticsearch (search index) while the actual data is fetched from the databases, which might be as slow as IContentLoader.GetDescendents().
When it comes to caching, you could also take a look at ContentOutputCache (https://world.episerver.com/documentation/class-library/?documentId=cms/7/14a5c664-1e28-e329-2d1d-9d862485c529) and object caching using ISynchronizedObjectInstanceCache (https://world.episerver.com/documentation/Items/Developers-Guide/Episerver-CMS/9/Caching/Object-caching/)
A word of caution regarding Stackify https://vimvq1987.com/a-curious-case-of-memory-dump-diagnostic-how-stackify-can-cause-troubles-to-your-site/, especially if you are using Application Insights.
Regardless of what method you are using, I completely agree with Dejan - this sounds like a heavy task - and you should cache the result for later uses.
Adding that you should add some container or sub listing pages (somehing like a year-month structrure or similiar) below the blog/news/events so that the editors don't put hundreds of pages as direct children.
Find is superior especially when the amount of decendents grow. I would say anything over perhaps just 50 items works a lot faster in Find when you need to sort by some data and get the .Top(x). Sorting and returned items might be not 100% correct at all times if indexing has a queue but I've never heard of this being an actual problem somewhere.
If you put paging in place (bad UX to show huge lists anyway) I wouldn't worry at all about GetContentResult() since the actual db call would be GetContents(pagesize ID array) and by using that you are sure that the actual data shown is correct and that you get the live published version.
One thing to remember here though is that even that Find usually is faster it is an external call and there is a lot more that can go wrong with it, like http-traffic, Amazon or Azure beeing down, Find beeing down, someone has deleted the index, something has gone wrong when indexing so there is not all content there, you have excluded to much so you will not find what you need, the index has been full so no new item are being indexed and so on and so on.
Find is great for search and for listning pages but I would never use it for system critical tasks (I have accually removed it in a couple of places since it was so unstable with server going down a lot).
So use Find, but use it smart!
It sounds like you making a case for both techiniques?
It's more Henrik making a case for both techniques in some type of fallback pattern when Find service has issues.
When you reach a certain level of items it's really hard to accomplish though since Find is really good with searching/listing from big pools of items but the local internal APIs are not.
GetContentResult() is a method you use on your Find query. It works using a remote Find HTTP call (or not if results are in the cache already) that will return an array of content IDs for the skip/take and sorting you specified. Then it uses a "local" Epi API call to populate the ContentData for each ID. I tried to clarify that the listing might not be "live" but each ContentData in it will be (on its own).
ah, my apologies missed that slight detail that makes all the difference.