Improving performance for Nuxeo page provider aggregates

Page providers in Nuxeo often use aggregates as user-friendly filters. For example, if aggregates are used, then when filtering a query, users will be able to see before clicking how many documents match that filter. However, having a lot of aggregates takes a toll on page load performance since all this data has to be retrieved from Elasticsearch during page load. In order to reduce this upfront load while still providing this user-friendly functionality, we can replace the default aggregate functionality with custom functionality that only loads the data once the user has clicked to see the options for a specific filter.

From analysis, we know that the default behavior is for the aggregates’ buckets to be transferred along with page providers’ data and then be assigned to the Nuxeo aggregate elements’ data property (nuxeo-checkbox-aggregation, nuxeo-dropdown-aggregation). This occurs when page is first loaded, but we know users will not immediately select all filters. That means that, from a performance and user experience perspective, all these aggregations do not need to load when the page first loads.

So, our solution is to remove these aggregation buckets from the response data in order to reduce the amount of data requested upon page load, and only load the data when a user clicks a filter (fetching that filter’s aggregation at that point in time).

There are some steps we need to complete before we’ll be able to achieve these performance improvements.

 

Many areas to optimize

Nuxeo has a lot of moving parts-the front-end, the database, Elastic Search, caching, and so on-and the exact setup can be unique to each company that uses it. And, because developers typically introduce custom functionality that is specific to the company’s needs, such as custom views, we need to make sure that we are aware of the impact of these customizations on page-load speed and that we optimize the page load process where necessary.

In short, there are many places where we can optimize performance. This blog entry won’t try to cover all of them but will instead look at one specific example scenario where we discovered some issues using the Network Monitor tool in Chrome and investigated to find the issue and the solution.

 

Part 1: Customize the aggregation elements

We need to define a customized element that fetches aggregates when a user clicks a filter but which otherwise looks and operates the same as a standard Nuxeo aggregate.

Below is the template content of our customized dropdown aggregation element based on the nuxeo-dropdown-aggregation element:

Figure 1: Template content of our customized dropdown aggregation element

 

We use a nuxeo-page-provider element to fetch aggregation; the page-size should be 1, and schemas should contain “dublincore” to get the items’ label.

In the element, we use a customized element, iss-selectivity, to execute the query. The iss-selectivity element is derived from the nuxeo-selectivity element. We changed its default query in its callback function; if we set its page provider, then it will query aggregation. A code snippet is below:

// debounce requests
this._debouncer = Polymer.Debouncer.debounce(
this._debouncer,
Polymer.Async.timeOut.after(this.frequency), () => {
// if set PageProvider, then use it to query aggregations
if (this.pageProvider) {
// if first time set quickFilters, need to fetch once
if (this.quickFilters && !this.pageProvider.quickFilters) {
this.pageProvider.fetch().then(resp => {
this._fetchAggregations(query);
});
} else {
this._fetchAggregations(query);
}
} else { // the default query
this._query(query);
}
},
);

Figure 2: Code snippet showing the customized iss-selectivity element

 

The nuxeo-dropdown-aggregation and nuxeo-selectivity elements can be found in the Nuxeo WebUI official repository on GitHub.

 

Part 2: Modify page providers and search form and result files

Once we have customized aggregation elements, we can apply them to multi-doc view pages and search forms. We will explain here, in three steps, how to use it in a search form or results page.

 

Step 1: Modify main page provider

We need to modify the original main page provider. First, we need to change aggregates to predicates. All predicate operations should use the Operator “IN”. If the field is a single value type, check the list checkbox; this is necessary to ensure aggregate’s multi-value search function:

Figure 3: Screen capture of the Predicate Editor

 

In the example of modified page provider below, we can see that all aggregates are changed to predicates:

Figure 4: Screen capture showing the change of predicates to aggregates

 

Step 2: Define separate aggregation page provider

In order to achieve lazy loading, we use the main page provider to fetch the entries’ data when we are in the search tab/section. Then we need to define a separate aggregation page provider to fetch the aggregates when users click the specific filter.

In the aggregation page provider, we set predicates like above, except for the fields that we need to aggregate. For example, if we need to fetch desc:assetTypes aggregation, the page provider is set as shown below:

Figure 5: Screen capture showing the assetType aggregate

 

If the main page provider contains some necessary aggregates, quick filters, or other settings, the aggregation page provider should also keep the same settings with the main page provider. This ensures that the aggregate filter will request the same parameters as the main page provider. An example definition of all page providers for an example area called Chapter Reference is below (including the main page provider, “chapterReference_pp”):

  • chapterReference_Description_assetTypes_agg
  • chapterReference_Description_character_agg
  • chapterReference_Description_chapterRef_chapterRefVolumeBook_agg
  • chapterReference_Relations_series_agg
  • chapterReference_Relations_storyline_agg
  • chapterReference_pp
  • chapterReference_technical_mediaTyes_agg
  • chapterReference_video_production_season_agg

In the above page providers, the chapterReference_pp is the main page provider and the others are aggregation page providers.

 

Step 3: Modify the search form/results file

We need to modify the search form file to replace the Nuxeo aggregate element with our customized element.

A simple example is below (the element name is iss-dropdown-aggregation):

Figure 5: Code showing the iss-dropdown-aggregation

 

The parameters “value”, “page-params”, “provider”, and “multiple” are necessary. When “value” changes, the “params” will also change and will invoke the “params-changed” event to fetch data. The “provider” is the page provider id that we defined to fetch aggregations; when users click the filter, it will execute the query and pop up the dropdown list with results.

If page provider contains other aggregates, then we also need to set “aggregation” parameter to identify the aggregates that we need:

Figure 6: Screen capture showing aggregation parameters

 

Figure 7: Code showing the iss-dropdown-aggregation with parameters filled in

 

If the page provider contains any quick filters, then we need to set the “quick-filters” parameter:

Figure 8: Screen capture showing the Quick Filters UI

 

Figure 9: Code showing the iss-dropdown-aggregation with parameters filled in

 

The variable quickFilters is defined in the search form file:

Figure 10: Code snippet showing configuration of quickFilters

 

When users click quick filter buttons, the variable quickFilters must know its changes, so we need to listen for the quick-filters-changed event on the search result file:

Figure 11: Code snippet showing configuration of quickFilters element

 

The application in multi-doc view file also needs to be changed slightly. We should listen for the “params-changed” event:

listeners: {
‘params-changed’: ‘_paramsChanged’
},
_paramsChanged: function () {
if (this.document && this.$.results.view) {
this.$.results.view.fetch();
}
}

Figure 12: Code snippet showing configuration

 

Conclusion

This solution can significantly improve page performance on pages with a lot of aggregates. However, we need customized aggregation elements and to define separate aggregation page providers to work with the main page provider to support this feature; this makes code modification more complex.

 

Want more information?

If you would like to learn more information, please contact us today.

Man and woman meeting in a bright and modern office. Whiteboard with writing and sticky notes is behind them.

Engage your digital transformation.

The right technology partner gets you where your customers expect you to be.

Contact us