Facets offer a simple way to allow users to filter their search results. Faceting can be applied to any attribute set in the product feed.
Adding and Setting Facets
The following two things are important to keep in mind when working with facets:
The first is to specify which facets should be returned in the response, for example to be shown in the frontend. This is done by adding the facets in question to the request. This gives you control over which facets to show. See Adding facets for more details.
Secondly you can allow users to filter the search request based on facets. This is called applying a facet and it is done by including a list of the attribute values that the request should be filtered on. More on this under Filtering With Facets.
Note
There is no guarantee that the facets you specify will be returned in the response.
Datatype
The datatype of facets must be the same as the datatype of the attribute value in the product feed.
Dynamic Faceting
Dynamic faceting means that the Loop54 engine automatically determines which facets, out of the list of specified attributes, are most relevant to show. The relevant facets are chosen based on the context of the search result.
When can Facets be Applied
Facets can be applied to the following calls:
Search
Category listings
Related products
The examples on this page show how to add facets to a search call. The same logic can be applied to category listings by replacing the search
call with getEntitiesByAttribute
call and for Java and C# create the request
object as an instance of GetEntitiesByAttributeRequest
instead of SearchRequest
.
Adding Facets
This example shows how to specify the facets to include in the response. In this case, we specify Manufacturer
and Category
. The response will contain those facets if they are relevant and present for the products in the results along with a count of the number of results that applying the facet would yield.
// Below is an example of a request - response cycle of an autocomplete request
AutoCompleteRequest request = new AutoCompleteRequest(query);
request.QueriesOptions.Skip = 0;
request.QueriesOptions.Take = 9;
AutoCompleteResponse response = _loop54Client.AutoComplete(request);
var queries = response.Queries.Items.Select(q => q.Query).ToList();
//print out all suggested autocomplete queries
Debug.WriteLine("queries: " + string.Join(", ", queries));
C# source code on Github: AutoCompleteController.cs
// Below is an example of a request - response cycle of an autocomplete request
AutoCompleteRequest request = new AutoCompleteRequest(query);
request.queriesOptions.skip = 0;
request.queriesOptions.take = 9;
AutoCompleteResponse response = loop54Client.autoComplete(request);
List<QueryResult> queryResults = response.queries.items;
List<String> queries = queryResults.stream().map(q->q.query).collect(Collectors.toList());
// print out all suggested autocomplete queries
System.out.println("queries: " + String.join(", ", queries));
Java source code on Github: AutoCompleteController.java
// Below is an example of a request - response cycle of an autocomplete request
var response = client.autoComplete(query, {skip: 0, take:9}).then((r) => {
var queries = r.data["queries"].items.map(i => i.query);
//print out all suggested autocomplete queries
console.log("queries: " + queries.join());
}
);
JavaScript source code on Github: autocomplete.js
/* Request autocompletions for a prefix */
$request = $connector->autocomplete('a')->take(2);
/* Actually perform the request */
$response = $connector->query($request);
echo 'Items starting with prefix:' . PHP_EOL;
/* Print all (unscoped) completions for this prefix */
foreach ($response->getUnscopedResults() as $result) {
echo $result['query'] . PHP_EOL;
}
PHP source code on Github: Simple.php
// Search with multiple facets
SearchRequest request = new SearchRequest(query);
//Add facets to the search request
request.ResultsOptions.AddDistinctFacet<string>("Manufacturer");
request.ResultsOptions.AddDistinctFacet<string>("Category");
SearchResponse response = _loop54Client.Search(request);
C# source code on Github: FacetingController.cs
// Search with multiple facets
SearchRequest request = new SearchRequest(query);
// Add facets to the search request
request.resultsOptions.addDistinctFacet("Manufacturer");
request.resultsOptions.addDistinctFacet("Category");
SearchResponse response = loop54Client.search(request);
Java source code on Github: FacetingController.java
// Search with multiple facets
// Add facets to the search request
var response = client.search(
query,
{
facets: ["Manufacturer","Category"].map(function(f){return {name:f,attributeName:f,type:"distinct"}})
}
);
JavaScript source code on Github: faceting.js
$request = $connector->search('food');
$request->resultsOptions()
->addDistinctFacet('Organic', 'Organic')
->addDistinctFacet('Category', 'Category');
PHP source code on Github: Simple.php
Filtering With Facets
Similar to the previous example we ask that the response contains Manufacturer
and Category
and in addition Organic
and Price
. Notice that the Manufacturer
facet is now applied with a list containing the value specificManufacturer
. This has the effect that the returned result will be filtered on the attribute Manufacturer
matching the string contained in the variable specificManufacturer
. Note also that the facet Price
is a different kind of facet, namely a RangeFacet covered by our next example.
// Search with a distinct facet applied
// The use-case here is e.g. when the user clicks on a specific manufacturer in the search result facet list
SearchRequest request = new SearchRequest(query);
//Add facets to the search request
//And select a specific facet value to filter on
request.ResultsOptions.AddDistinctFacet<string>("Manufacturer", new List<string>() { specificManufacturer });
request.ResultsOptions.AddDistinctFacet<string>("Organic");
request.ResultsOptions.AddDistinctFacet<string>("Category");
request.ResultsOptions.AddRangeFacet<double>("Price");
SearchResponse response = _loop54Client.Search(request);
C# source code on Github: FacetingController.cs
// Search with a distinct facet applied
// The use-case here is e.g. when the user clicks on a specific manufacturer in the search result facet list
List<String> selectedManufacturers = new ArrayList<>();
selectedManufacturers.add("MeatNStuff");
SearchRequest request = new SearchRequest(query);
// Add facets to the search request
// And select a specific facet value to filter on
request.resultsOptions.addDistinctFacet("Manufacturer", selectedManufacturers);
request.resultsOptions.addDistinctFacet("Organic");
request.resultsOptions.addDistinctFacet("Category");
request.resultsOptions.addRangeFacet("Price");
SearchResponse response = loop54Client.search(request);
Java source code on Github: FacetingController.java
// Search with a distinct facet applied
// The use-case here is e.g. when the user clicks on a specific manufacturer in the search result facet list
// Add facets to the search request
// And select a specific facet value to filter on
var selectedFacets = {
"Manufacturer": [specificManufacturer],
"Category": [],
"Organic": []
};
var distinctFacets = ["Manufacturer", "Category", "Organic"].map(function(f){return {name:f,attributeName:f,type:"distinct",selected:selectedFacets[f]}});
var rangeFacets = ["Price"].map(function(f){return {name:f,attributeName:f,type:"range"}});
var response = client.search(query, {facets: distinctFacets.concat(rangeFacets)});
JavaScript source code on Github: faceting.js
$request->resultsOptions()
->addDistinctFacet('Manufacturer', 'Manufacturer', ['Early']);
PHP source code on Github: Simple.php
Range Facets
We’re now applying the RangFacet by passing a parameter consisting of a max
and min
value that defines the range within which the attributes of returned products must be.
// Search with a range facet
// The use-case here is e.g. when the user selects a specific price range in the search result facet list
SearchRequest request = new SearchRequest(query);
//Add facets to the search request
//And select a specific range for a certain facet
request.ResultsOptions.AddDistinctFacet<string>("Manufacturer");
request.ResultsOptions.AddDistinctFacet<string>("Organic");
request.ResultsOptions.AddDistinctFacet<string>("Category");
request.ResultsOptions.AddRangeFacet<double>("Price", new RangeFacetSelectedParameter<double>() { Min = 10, Max = 60 });
SearchResponse response = _loop54Client.Search(request);
C# source code on Github: FacetingController.cs
// Search with a range facet
// The use-case here is e.g. when the user selects a specific price range in the search result facet list
SearchRequest request = new SearchRequest(query);
// Add facets to the search request
// And select a specific range for a certain facet
request.resultsOptions.addDistinctFacet("Manufacturer");
request.resultsOptions.addDistinctFacet("Organic");
request.resultsOptions.addDistinctFacet("Category");
request.resultsOptions.addRangeFacet("Price", new RangeFacetParameter.RangeFacetSelectedParameter<Double>() {{ min = 10.0; max = 60.0; }}, null);
SearchResponse response = loop54Client.search(request);
Java source code on Github: FacetingController.java
// Search with a range facet
// The use-case here is e.g. when the user selects a specific price range in the search result facet list
//Add facets to the search request
//And select a specific range for a certain facet
var distinctFacets = ["Manufacturer", "Category", "Organic"].map(function(f){return {name:f,attributeName:f,type:"distinct"}});
var rangeFacets = ["Price"].map(function(f){return {name:f,attributeName:f,type:"range",selected:{min: 10, max: 60}}});
var response = client.search(query, { facets: distinctFacets.concat(rangeFacets)});
JavaScript source code on Github: faceting.js
$request->resultsOptions()
->addRangeFacet('Price', 'Price', 10, 60);
PHP source code on Github: Simple.php
Rendering Facets
Finally, this example shows how to render the facets returned in a response. Note that the code starts with a list of desired facets to show and that it then checks for the existence of those facets in the response. Importantly, it does not assume the existence of any facets in the response.
List<string> distinctFacetsToDisplay = new List<string>() { "Manufacturer", "Category", "Organic" };
foreach (string attributeName in distinctFacetsToDisplay)
{
var facet = response.Results.GetDistinctFacetByName(attributeName);
if (facet != null)
{
var facetItems = facet.Items;
if (facetItems.Any())
Debug.WriteLine(attributeName + ": ");
foreach (var facetItem in facetItems)
{
Debug.WriteLine(facetItem.GetItem<string>() + ": " + facetItem.Count); // Write the facet name and the number of products in the facet
}
}
}
C# source code on Github: CategoryListingController.cs
List<String> distinctFacetsToDisplay = new ArrayList<String>();
distinctFacetsToDisplay.add("Manufacturer");
distinctFacetsToDisplay.add("Category");
distinctFacetsToDisplay.add("Organic");
for(String attributeName : distinctFacetsToDisplay)
{
DistinctFacet facet = response.results.getDistinctFacetByName(attributeName);
if (facet != null)
{
List<DistinctFacetItem> facetItems = facet.getItems();
if (facet.hasValues())
System.out.println(attributeName + ": ");
for (DistinctFacetItem facetItem : facetItems)
{
System.out.println(facetItem.getItem(String.class) + ": " + facetItem.count); // Write the facet name and the number of products in the facet
}
}
}
Java source code on Github: CategoryListingController.java
var distinctFacetsToDisplay = ["Manufacturer", "Category", "Organic"];
if(data.results && data.results.facets.length > 0)
{
for (var i in distinctFacetsToDisplay)
{
var facet = data.results.facets.find(function(f) { return f.type == "distinct" && f.name == distinctFacetsToDisplay[i]; });
if(facet)
{
var facetItems = facet.items;
if (facetItems && facetItems.length > 0)
console.log(distinctFacetsToDisplay[i] + ": ");
for (var j in facetItems)
{
console.log(facetItems[j].item + ": " + facetItems[j].count); // Write the facet name and the number of products in the facet
}
}
}
}
JavaScript source code on Github: categorylisting.js
$distinctFacetsToDisplay = ['Manufacturer', 'Category', 'Organic'];
$facets = $response->getFacets();
foreach ($facets as $facet) {
if (in_array($facet['name'], $distinctFacetsToDisplay)) {
echo $facet['name'] . ': ' . PHP_EOL;
foreach ($facet['items'] as $option) {
echo ' [' . ($option->selected ? 'X' : ' ') . '] '
. $option->item . ' (' . $option->count . ')' . PHP_EOL;
}
}
}
PHP source code on Github: Simple.php