Reducing Coveo Queries/QPM

I recently encountered an issue where our Sitecore website was sending too many Coveo queries per month (QPM). This was resulting in our team exceeding the soft limit set for our Coveo organization. The primary reason that we were experiencing an overage was that the site had a set of 3-5 vertically stacked search interfaces on most pages of the site. Users wouldn’t always interact with all of them, but the queries were always issued, and always counted against the allotted QPM for the organization.

To remediate this, I contacted Coveo, who suggested that we start using a tabbed search experience. This would basically make it so that each page only loaded one search interface at a time. Additional queries wouldn’t be sent until users clicked into the alternate search interface tabs. However, our team decided that we didn’t want to change the overall UI/UX if we could find an alternate solution.

The alternate solution we found was that we could override Coveo’s default search interface initialization. Coveo Hive initializes their search interfaces in a default installation file “/Coveo/Hive/init/init.cshtml”. We found that we could write some simple JavaScript to delay the search interface initialization and query until the user actually scrolled down to the search interface. This solution wasn’t ideal in that it was a modification to a default Coveo installation file. However, getting our QPMs in order was enough of a priority that it warranted the change.

The primary change shown below is the introduction of the IntersectionObserver method call. Using this, we can prevent initializing the search interface until 50% (configurable) of the search interface is actually on the page. We found that after this change, our primary search box wasn’t working on some pages. The search box needed to be initialized prior to the search interface, and that resolved that issue as well.

@using Sitecore.Mvc
@using Coveo.UI.Components
@using Coveo.UI.Components.Extensions
@using Coveo.UI.Core.ErrorReports
@model Coveo.UI.Components.Models.SearchInterfaces.ISearchInterfaceModel

<script type="text/javascript">
    document.addEventListener("CoveoSearchEndpointInitialized", function() {
        @*
            setTimeout(function() { }, 0) defers the initialization just enough to execute other DOMContentLoaded or CoveoSearchEndpointInitialized events in the page.
            This is required by some components to allow them to register before initialization.
        *@

        setTimeout(function() {
            var searchInterface = document.getElementById("@Model.Id");
            @if (Html.Coveo().IsEditingInPageEditor()) {
                @: if (typeof(CoveoForSitecore) !== "undefined" && typeof(Sitecore) !== "undefined") {
                    @: CoveoForSitecore.initializeSearchInterfaceForExperienceEditor(searchInterface);
                @: }
            } else {
                @: if (typeof(CoveoForSitecore) !== "undefined") {
                    @* : CoveoForSitecore.initSearchInterface(searchInterface); *@
            @: var searchBoxItem = document.getElementById("{searchBoxIdHere}");

                    @: Coveo.initSearchbox(searchBoxItem, "{searchPageUrlHere}");
                    @: searchBoxItem.classList = ["CoveoSearchbox"];
					@:// define an observer instance
					@:var observer = new IntersectionObserver(function(entries, opts){
					@:  entries.forEach(entry => {
					@:		if(entry.isIntersecting){
					@:			CoveoForSitecore.initSearchInterface(entry.target);
					@:			observer.unobserve(entry.target);
					@:			observer.disconnect();
					@:		}
					@:  })},
					@:	{
					@:		root: null, 
					@:		threshold: .5 
					@:	})

					@:// Use the observer to observe an element
					@:observer.observe(searchInterface);
                @: }
            }
        }, 0);
    });
</script>

This minor change significantly lowered our queries per month and brought us back to the budgeted level.

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *