Product Grouping

In a commerce interface, you will often want to group similar products together. For example, if a certain type of bicycle helmet comes in various colors, you could display those variations as smaller images below the main product image.

Product Grouping Sample Image

The mechanism required for product grouping to apply is filtering (i.e., the filterField and filterFieldRange query parameters). In addition, ranking within the group of products is controlled by query ranking expressions (QREs) and can dramatically improve the user experience, but product grouping will work without it.

Grouping Field Configuration

Grouping is done between products that share the same value for a specific field.

We recommend that you use ec_item_group_id as a grouping field.

Suppose that in your catalog, whenever a product comes in different colors, all color variations of that product share the same unique "root" substring in their product ID. In such a scenario, you could index those root IDs into your grouping field for each product in your catalog:

Product description Productid value Desired ec_item_group_id value

Bicycle helmet model 001 (gray)

bhelmet001-gray

bhelmet001

Bicycle helmet model 001 (red)

bhelmet001-red

bhelmet001

Bicycle helmet model 001 (blue)

bhelmet001-blue

bhelmet001

Bicycle helmet model 002 (gray)

bhelmet002-gray

bhelmet002

Bicycle helmet model 002 (red)

bhelmet002-red

bhelmet002

Bicycle helmet model 002 (blue)

bhelmet002-blue

bhelmet002

You could then use that field to request grouped products (as explained in the Set Up the Pipelines section below).

Your grouping field must be configured as follows:

  1. Must be set as Facet.

  2. Must be of type String.

Set Up the Pipelines

To request grouped products, you must apply the following filters in your Query Pipelines, under the Advanced tab.

Filter Field Grouping

The filterField query parameter is used to set the field to execute the grouping and is entered in the Query Parameters, directly in the pipeline.

Product Grouping Sample Image

Filter Field Range

The filterFieldRange parameter controls the number of items returned in the group. This is used to define how many results are returned to the group.

In the following example, we want to return 10 results. If you want to show all of the items in your group, ensure the number entered is equal to the number of items you have in your biggest product group.

Product Grouping Sample Image

Products From the Same Group

Products from the same group are retrieved with a disjunction query expression (dq) that fetches all the products using the same ec_item_group_id as the one returned by the query. To create this expression, in the Filters section, click Add rule. In the Query Parameter drop-down, always select dq, then enter the expression.

EXAMPLES

To be used with Dynamic facets

(@source=="exampleCatalog")([[@ec_item_group_id]($query) ($originalQuery)($facetsFilter)])
Where:
  • @source is the name of your Catalog source.

  • [@ec_item_group_id] is another item with the same ec_item_group_id.

  • $originalQuery is the manual query (q parameter) that initially gets sent before modifications.

  • $facetsFilter query expression that represents the filters introduced by the selection of dynamic facets.

To be used with Legacy facets

(@source=="exampleCatalog")([[@ec_item_group_id]($query) ($originalAdvancedQuery)])
Where:
  • @source is the name of your Catalog source.

  • [@ec_item_group_id] is another item with the same ec_item_group_id.

  • $originalAdvancedQuery is the advanced query that initially gets sent to the platform before any modifications are made by filters or query parameters.

Only Dynamic facets are used within a Headless library.

Product Grouping Main Item

Grouped items aren’t displayed in any particular order. However, you can improve the experience with ranking expressions. You can boost a color field if that value is present in the query. This will move the appropriate product to the top as the main item.

To apply these expressions, select a pipeline from the Query Pipelines page. Under the Result Ranking tab, click Add Rule, and then select Ranking expression.

For example, performing a search for “shoes” will return shoes as a result with their grouped items in no particular order. Performing a search for “red shoes” will return any red shoes as the main item, and place all other colors as grouped items underneath.

Using the @color field would result in:

@color=$splitValues(text: $query, separator: '\s')

Then, use the slider to increase the boost by 100

Product Grouping Query Sample Image

In case of a facet selection, this expression can extract the right value from the advanced query and add it to the expression:

@color=$valuesOfField(field: '@color', resultSet: $advancedQuery)
Product Grouping Facet Sample Image

When using Dynamic facets you would need to replace $advancedQuery in the above expression to $facetsFilter

Refer to the product grouping template based on your use case, With JSUI or With Headless.

Product Grouping Within a Recommendation Component

Recommended product grouping uses the same principles as product grouping, but with an additional modification to the ML model configuration. The group shown is based on the product recommendation (PR) strategies set by the user.

This method should be applied when you’re already returning recommendations, but instead of showing individual products, you want to show the product within a group defined by the ec_item_group_id field.

Recommended Product Grouping Sample Image

The base configurations are the same as product grouping, set the Grouping Field Configuration and the Filter Field Grouping query parameter.

In addition, you then need to create a PR model and associate the PR model to your pipeline.

Once completed, edit the PR model association via a JSON configuration to modify the ML model’s configuration by adding the following parameter:

"maxRecommendations”:__

EXAMPLE

Your ec_item_group_id group contains 7 products and you want there to be enough products to populate a full carousel of items frequently viewed together.

You need to request more items to return less results, as the recommendations are folded under those groups. The value greatly depends on the number of products per group.

{
  "id": "<ORG_ID>",
  "position": "1",
  "modelId": "<MODEL_ID>",
  "modelDisplayName": "<MODEL_DISPLAY_NAME>",
  "modelEngine": "ecommerce",
  "modelStatus": "Updating",
  "rankingModifier": 1000,
  "maxRecommendations": 50,
  "exclusive": true,
  "customQueryParameters": {
     "submodel": "frequentlyViewed"
  },
  "useAdvancedConfiguration": true,
}

By grouping products, you filter down the output of the model at the group level, therefore you must request more recommendations to ensure that your component is populated accordingly.

You can request up to a maximum of 50 recommendations. Attempting to use a higher value will have no effect.

Product Grouping Template

In the result templates, use a loop to access the child results. This will show the related items in the same group. When using the filterField parameter, the items with the same value for that field appear under childResults in the search response.

Whether you use a full search interface with a result list or you implement a product recommendation component, you get a results list in both cases. The template usage is identical but the behaviors are slightly different.

The following example iterates over the child to show the related products.

Product Grouping Template Example

With JSUI

Here’s the code to produce the previous image:

import {
 Component,
 ComponentOptions,
 IComponentBindings,
 Initialization,
} from 'coveo-search-ui';
export interface IRelatedProductsOptions { }
export class RelatedProducts extends Component {
 static ID = 'RelatedProducts';
 static options: IRelatedProductsOptions = {};
 constructor(public element: HTMLElement, public options: IRelatedProductsOptions, public bindings: IComponentBindings, public result: any) {
   super(element, RelatedProducts.ID, bindings);
   this.options = ComponentOptions.initComponentOptions(element, RelatedProducts, options);
   const relatedProducts = result.childResults || [];
   if (relatedProducts.length) {
     // for each related product, create an array of Html <div> to display it.
     const imagesHtml = relatedProducts.map(product => `
       <div style="background-image: url(${product.raw.image})" title="${product.raw.color}">
         <a href="show.html#p=${product.raw.permanentid}" title="${product.raw.color}">&nbsp;</a>
       </div>
     `);
     // Show the related products in the HTML for this result.
     element.innerHTML = `
       <b>Also available in:</b>
       <div>
         ${imagesHtml.join('\n')}
       </div>
     `;
   }
 }
}
Initialization.registerAutoCreateComponent(RelatedProducts);

This is a custom component, meant to be used as a <div class="CoveoRelatedProducts"></div> element in the result template for Products.

With Headless

When using the the Coveo Headless library, you’ll need to create a special-purpose result template.

The following example code shows a basic use case of the ResultTemplatesManager and will produce the previous image. You can access products from the same group by using the childResults property on the result object.

import { buildResultTemplatesManager,
         ResultTemplatesManager,
         Result,
         ResultTemplatesHelpers } from "@coveo/headless";
import { headlessEngine } from "../Engine";
// ...
 
export default class ResultList {
  // ...
  private headlessResultTemplatesManager: ResultTemplatesManager;
  // ...
  constructor(props: any) {
    // ...
    this.headlessResultTemplatesManager =
      buildResultTemplatesManager(headlessEngine);
    this.headlessResultTemplatesManager.registerTemplates(
      {
        conditions: [],
        content: (result: Result) => (
          <li>
            <h4>{result.title}</h4>
            <p>{result.excerpt}</p>
            <b>Also available in:</b>
            <div>
              {
                // Use the `childResults` property to get the related products, which we map to their HTML representation in order to display them.
                result.childResults.map(product => (
                    <div style="background-image: url(${product.raw.image})" title="${product.raw.color}">
                      <a href="show.html#p=${product.raw.permanentid}" title="${product.raw.color}">&nbsp;</a>
                    </div>
                  )
                )
              }
            </div>
          </li>
        )
      },
    );
    // ...
  }
  // ...
  render() {
    return (
      <ul>
        {this.state.results.map((result: Result) => {
          const template =
            this.headlessResultTemplatesManager.selectTemplate(result);
          return template(result);
        })}
      </ul>
    );
  }
}

Debugging Product Grouping

You may want to ensure that the product grouping you’ve set up is working as intended. Before proceeding with the steps below, you’ll first need to complete the Grouping Field Configuration and Set Up the Pipelines sections from above.

  1. In your Coveo organization, open the Content Browser.

  2. Access your browser developer tools.

  3. In the Source facet, select the source you are attempting to validate.

    dev tools product grouping results
  4. Back in the Content Browser, from the Pipeline drop-down, select the pipeline where you set up your filter fields for grouping.

  5. In your browser developer tools, in the Network tab, under the Name column, select the latest request to the Search API. The request path should contain v2.

  6. Select the Preview tab. You should now see the query response body.

  7. In the query response body, you should see an expandable results property. You can expand it to see information about the search results for this query.

  8. Expand one of the results. (e.g., the 0 index).

  9. Expand its child properties, also known as childResults. This should hold a list of results that belong to the same group as the main result.

    dev tools product grouping results

You can also test whether the keywords give priority to the right item. These adjustments to the ranking expressions can be done to the Product Grouping Main Item.

EXAMPLE

If you search for “red” in the Content Browser, and the “white” product is returned as the main result, you might want to boost the color field so that it matches the search box keyword, since it should be given a higher priority compared to its siblings.

Recommended Articles