Faceted Search
With Ucommerce comes the ability to do faceted search on any index generated. Usually Faceted search is used in products listings. This article will teach you how to:
- What facets are
- Configure facets in indexes
- Use the Facets API in Ucommerce
Facets Overview
Faceted search is the ability to narrow a search based on one or more dimensions like Color, Size, Fabric, Price etc. As shown in the image above it is usually presented by the user as a lister of filters that can take many forms. Common for all presentations are that the user decides based on a set of predefined filters. Usually they are attributes that uniquely identify a certain product.
In Ucommerce you can setup your index definition to define what properties on your products (fixed or properties defined by definitions) should be generated as facets. Once this is done, all your queries against the product index will automatically be able to generate available facets and values.
Index Definition
To configure your facets you must first create an IndexDefinition
which defines fields (and facets) available in the index. If you are interested in how to do this, or learn more, you can read about index definitions here.
Standard Facet Fields
When you want to create a facet field, your index definition needs to define the field to be part of the index in the first place.
this.Field(p => p["Colour"], typeof(string)); this.Facet("Colour");
In the example above we define a field in the index called Colour
. This is either a standard field, or a dynamic property stored on the product based on a definition like shown on the image above.
All the products with this value will now be possible to facet on, and the search APIs will automatically retrieve all values possible.
Multi Value Fields
If you have defined an enum multi select, for example available colors
or the like, you can have the API automatically split this the correct way into multiple possible values.
So if you have both Red
and Green
for your multi-value field, you'll be able to find said product by filtering on either Red
or Green
or both values in one go.
To achieve this mind the code sample below to configure a field as a multi-value field.
this.Field(p => p["multivaluefields"], typeof(IEnumerable<string>)); this.Facet("multivaluefields");
Automatic Language Translations of values
As each index are language specific, the facets will automatically adjust based on the language, so if you have defined your custom fields to be multilingual, the correct translations will automatically be there, making this very flexible without any further configuration for the indexes.
Price facets
Price facets are special and needs to be configured individual as compared to other fields. OOTB you are usually only interested in having the unit prices as facets.
this.Field(p => p.UnitPrices); this.Field(p => p.PricesInclTax); this.Field(p => p.UnitPrices["EUR 15 % VAT"]) .Facet() .AutoRanges(count: 5, precision: 10); this.Field(p => p.UnitPrices["USD 7 % VAT"]) .Facet() .AutoRanges(count: 5, precision: 100);
Facets Models
The models to display facets for the visitors similar to the image in the top of this article, can be seen below.
Ucommerce.Search.Facets.Facet
Description
Represents a field in the index along with its values and individual term counts.
Name
- Return type
string
- Description
Name of the field in the index that contains the possible values based on the current search.
DisplayName
- Return type
string
- Description
Pretty name of the field name in the index, presented to the customer.
TotalCount
- Return type
uint
- Description
Total Count of documents that has a field with any value based on the search.
FacetValues
- Return type
IList<Ucommerce.Search.Facets.FacetValue>
- Description
All possible values in the field in the index.
Ucommerce.Search.Facets.FacetValue
Description
Represents the individual terms and possible counts (entries) found in the index matching the facet name.
Value
- Return type
string
- Description
The individual term as found in the Index.
Count
- Return type
uint
- Description
Count of documents matching this value based on an existing Search.
Facets API
Once you have your index definition configured, you are ready to consume the API that allows you to search via facets in your indexes. The typical use case is faceting on product listings.
Ucommerce.Api.ICatalogLibrary.GetFacets
Additional overloads to this method exists
- Description
Gets facets for products. For multi-category product lists, use the method overload that takes in a list of category ids. - Return type
IList<Ucommerce.Search.Facets.Facet>
-
Arguments
System.Guid
categoryId : Category that contains the productsUcommerce.Search.Facets.FacetDictionary
facets : Dictionary list of facetsSystem.UInt32
skip : Skips over the first x values in the query result. Default: 0System.UInt32
take : Takes x values from the query result. Default: 64
Calling the API
var catalogLibrary = Ucommerce.Infrastructure.ObjectFactory.Instance.Resolve<Ucommerce.Api.ICatalogLibrary>(); catalogLibrary.GetFacets(categoryId, facets, skip, take);
You can also consume the raw ISearch interface in case you are doing something more custom and apply facets to that search.
var userSelectedFacetsForSearch = new FacetDictionary(); userSelectedFacetsForSearch["Color"] = new[] {"red", "blue"}; Ucommerce.Search.ISearch<Ucommerce.Search.Models.Product> search = Ucommerce.Infrastructure.ObjectFactory.Instance.Resolve<IIndex<Ucommerce.Search.Models.Product>>().Find(); //Get resultset with products ResultSet<Product> products = search.Where(userSelectedFacetsForSearch).ToList(); //Get facets FacetResultSet<Product> availableFacets = search.Where(userSelectedFacetsForSearch).ToFacets();
With the addition of Elastic search to Ucommerce, faceted range search differs in inclusivity.
Lucene takes both values from and to as inclusive (<= || >=), whereas Elastic takes from inclusive and to as exclusive.
Automatic ranges for Faceted Search
Be aware, using automatic ranges comes with a performance overhead. To determine the ranges properly, the system needs to reach out to the Index and retreive max value for the field.
This comes with 5ms - 20ms penalty depending on the setup and latency.