Dan Matthews
May 31, 2016
  3787
(4 votes)

Vulcanised enhancements

These weekly updates are becoming a habit! In this edition, I’m going to share with you a couple of significant enhancements I’ve made to Vulcan, the lightweight Elasticsearch client for Episerver. The most obvious and most generally useful enhancement is the addition of an additional optional parameter to the SearchContent method that takes a ContentReference to search beneath. This was possible before but only by doing funky stuff like getting a list of the ancestors of a page and sending them all over to Elasticsearch as a search filter (ick!). Now it’s all neatly done by Vulcan for you. For example, if I wanted to search below the current content item my search might look like this (commerce example below but works just the same for CMS… note that I’m sending in null as the search query here because I don’t actually want to do a search, just pull back the contents):

model.Products = VulcanHandler.Service.GetClient().SearchContent<ProductBase>(null, false, currentContent.ContentLink).GetContents<ProductBase>();

In order to support this, Vulcan adds an additional field to the content as it indexes it (more about that field later) so that this filter can run much faster and more efficiently. You don’t really need to think about the property much… although if you look in the index, you’ll see it there something like this (again, example is for a bit of commerce content):
 
image
 
Rather than hardcode this extra bit of indexing logic, I made this mechanism generic so that it opens up some cool options for you. One thing you may well want to do is customise the object being indexed. Normally this is a bit of a black box, but I’ve added a hook into the JSON serialisation process so that you can add in custom fields as needed. Simply create a class that implements the IVulcanIndexingModifier interface. It just has one method, ProcessContent, that receives whatever bit of content is being indexed and the outgoing stream of JSON. Simply put whatever logic you need into there and, if needed, spit out JSON properties into the stream. This method will be automatically found and used when indexing content. For an example of how this works, see the two built-in indexing modifiers for CMS and Commerce that add ancestor and pricing properties. The joys of open source! You can check that your indexing modifier has been located and is being used by checking the Vulcan UI (here you’ll see the two built-in indexing modifiers have been detected and are available):
 
image
 
Using this new technique of modifying content as it’s indexed, I’ve also added some additional properties for pricing to commerce content. For variants, I’ve added the default price for the various markets and currencies. For products, the variants could be priced differently so there you’ll find two properties for price low and price high, so showing the bracket of prices of the variants of that product. Typically, you would aggregate these for facets and this gives you the ability to do that on products – low price or high price is up to you! Again, you shouldn’t need to worry too much about the exact implementation so I’ve added a few helper methods in a VulcanFieldHelper class (part of the Vulcan commerce package) which will give you the field name you need. For example, if I wanted to get all the variants below my current node and create a price facet, I could use the following:
 
model.SearchResponse = VulcanHandler.Service.GetClient().SearchContent<EPiServer.Reference.Commerce.Site.Features.Product.Models.FashionVariant>(
q => q.Aggregations(a => a
.Filter("this_node", cm => cm
.Filter(f => f
.Bool(b => b
.Must(m => m
.Term(TcbInternetSolutions.Vulcan.Core.VulcanFieldConstants.Ancestors, currentContent.ContentLink.ToReferenceWithoutVersion().ToString()))))
.Aggregations(agg => agg
.Terms("prices", t => t
.Field(VulcanFieldHelper.GetPriceField()))))));

Note that in this case I am having to manually specify the query to narrow down the aggregate results to this node. The reason for this is because you might not want the aggregation to do this, so it’s better that you can choose yourself whether or not you want it to. In effect, it’s doing pretty much the same kind of filter as the main search does to narrow down search results to a node. You will see that the prices aggregation is being done on a field retrieved from the VulcanFieldHelper. In this case, it’s going to use the current market and the current market’s default currency. You can override that though by passing in parameters to get the price field for another market or currency. If you really do want to see what this looks like in the index, here’s a sample of a product showing the price brackets for the variants (in this case, it seems like the variants are all the same price, so the low and high values are all the same):

image

One fairly major update in this version is the ability to play nicely with other shell modules such as Episerver Google Analytics and Episerver Forms. Previously, a bug in the code meant that it didn’t… somewhat hampering it’s usefulness! So how do you get all these Vulcan goodies? Simply update to the latest package in the Episerver Nuget feed and you should be good to go! As usual, all feedback and comments are appreciated and if you’d like to contribute, simply request developer access to the Vulcan project on GitLab.

DISCLAIMER: This project is in no way connected with or endorsed by Episerver. It is being created under the auspices of a South African company and is entirely separate to what I do as an Episerver employee.

May 31, 2016

Comments

Please login to comment.
Latest blogs
How I Fixed DLL Conflicts During EPiServer CMS Upgrade to .NET Framework 4.8.1

We had a CMS solution of EPiServer 11.26.0, which was built on .NET Framework 4.7.1. We needed to update the target framework from .NET Framework...

calimat | Dec 12, 2024

Custom form element view in Optimizely CMS 12

Do you want full control over the form element markup? Create your own views!

Tomas Hensrud Gulla | Dec 11, 2024 | Syndicated blog

How to Elevate Your Experimentation - Opticon workshop experience

As a non-expert in the field of experimentation, I’d like to share my feedback on the recent Opticon San Antonio workshop session titled "How to...

David Ortiz | Dec 11, 2024

Persisting a Strawberry Shake GraphQL Client for Optimizely's Content Graph

A recent CMS project used Strawberry Shake to generate an up-to-date C# GraphQL client at each build. But what happens to the build if the GraphQL...

Nicholas Sideras | Dec 11, 2024 | Syndicated blog

Opti ID with Secure Cookies And Third Party AddOns

Opti ID has revolutionised access to the Optimizely One suite and is now the preferred authentication method on all PAAS CMS websites that I build....

Mark Stott | Dec 9, 2024

AsyncHelper can be considered harmful

.NET developers have been in the transition to move from synchronous APIs to asynchronous API. That was boosted a lot by await/async keyword of C#...

Quan Mai | Dec 4, 2024 | Syndicated blog