Gravatar for

Question by jtresidder, Jul 24, 2018 9:27 PM

Custom Filter Expression Rule for Coveo Hive


I'm trying to figure out how to get a custom rule working for my query filtering, but seem to be hitting some obstacles. I tried following this, but first ran into an issue because the rule wasn't showing up as an option on my search interface. I found that it showed up after I added my new tag to the Settings > Rules > Coveo Search Rules > Tags > Default item... but when I the new rule that shows up on my interface, it does absolutely nothing. Like, it can't even hit a breakpoint inside the custom rule, it seems to just never get called.

I'm curious if maybe I'm following an incorrect example? And there's something else I need to be doing to get this to work with the Hive framework? Or does this seem like it should be working, and I'm just doing something wrong?

Some other misc Info: Coveo 7.0, Coveo for Sitecore 4.1, we have an On-Prem installation, using Sitecore 9.01

Gravatar for

Comment by epasquini, Dec 19, 2018 12:43 AM

Do we have documentation on how to create a custom filter in Coveo Hive?. Going through this replies to get something clear seems impossible.

Thanks in advance

2 Replies
Gravatar for

Answer by François Lachance-Guillemette, Jul 25, 2018 1:39 PM

A lot of things changed in Coveo for Sitecore Hive regarding rules. As of now, this documentation is obsolete.

One of the main difference is that the expression tree is parsed on the client-side of the code instead of computing a complete query expression server-side.

This allows the Coveo for Sitecore Hive framework to put in cache the expression tree and re-render the expression depending on the current context.

Now, let's jump into actual code.


If you take a look at the current rules, for instance, the `Coveo Items` > `Specific Item` rule, you can see the following class: `Coveo.UI.Core.Rules.Conditions.Items.SpecificItemCondition,Coveo.UI.Core`.

Here is the implementation as of today: SpecificItemCondition.cs

The important parts here are the `GetQueryNode` and the `ValidateCondition` methods.

`GetQueryNode` returns the node to be output to the Coveo for Sitecore Hive framework. `IQueryNodeBuilder` allows to output a node that is understood by the Coveo for Sitecore Hive framework. You can use any method of this building and you can expect your expression to work on the client-side part of the framework.

`ValidateCondition` allows validating the property before trying to output the expression tree. `ILocalizedStringFetcher` is a simple helper that uses Sitecore dictionary to output a friendly and localized string, in case of errors.


Here are some abstract classes that you can inherit from to give you some easier time with custom rules:

`BinaryFieldOperatorCondition<TContext, TRealValue, TValue>`: Used to implement an upper bound + lower bound expression, for instance, `@field < {UPPER} AND @field > {LOWER}`. You must override `LowerBound`, `UpperBound` and `InitializeBounds`.

`StringFieldCondition<TContext>`: Used to implement a simple field + value expression, for instance, `@field == {VALUE}`. You must set the `FieldName` property and override `GetFormattedValue()`.


Let me know if this gave you enough pointers to get going. We are currently missing documentation for this topic, but I hope this answer provides the help that you needed.

Gravatar for

Answer by Charles-Hubert van Eyll, Aug 7, 2018 8:46 PM

I am going to update this question, as we have made some progress through a support case.

JTresidder took a step back to reconsider the need for a custom rule in order to implement the requirement. The goal is to prompt the user to specify 2 values that will be stored as cookies and will then be used to limit the results on the search page to only those pages which have a value in their multivalue field that matches the values from the user's input.

What we suggested to JTresidder was modifying the query by adding something like this via the queryBuilder:

`@value1==${currentSelectedValue1} @value2==${currentSelectedValue2}`

Information on how to modify the query in such a way is available here:

JTresidder then tried to put the following script block at the bottom of their page:

document.addEventListener('DOMContentLoaded', function () { 
    var root = document.body; 
    Coveo.$$(root).on('buildingQuery', function (e, args) { 
        '@fieldName', '==', '@cookieValues');*@ 

But their page is not showing any results anymore, even though the expression itself is actually commented out.

The issue seems to be that `Coveo.SearchEndpoint.configureSampleEndpointV2()`should not be there, as it overrides the endpoint. The JS UI is then unable to reach /coveo/rest.

Moreover, root should be equal to `Coveo.$$(document).find("#YourIdGoesHere");`

Finally, in MVC, you can escape the "@" character using "@@".

Gravatar for

Comment by jtresidder, Aug 16, 2018 3:52 PM

A couple follow-up questions for you: What is the element we are trying to find? Is it the search interface? How would this work for something such as the omnibox, which doesn't use an interface?

Also I'm not sure if my expression is going to work the way that I hope. As I mentioned earlier, this field is a multivalue of strings, and I want to check that the string I have is in the list of values stored on the record in coveo. Is this sufficient for coveo to accomplish this? Or do I need different syntax because the field is multivalue?

args.queryBuilder.advancedExpression.addFieldExpression('@fieldName', '==', value');
Gravatar for

Comment by jtresidder, Aug 20, 2018 4:47 PM

Alright, I feel like I'm so close! But things aren't quite clicking yet. So where I'm at right now is I have the following script block at the end of my footer:

    document.addEventListener('DOMContentLoaded', function () {
        var interfaces = $('.CoveoSearchInterface');
        $.each(interfaces, function (key, value) {
            var interfaceId = $(value).attr('id');
            var root = Coveo.$$(document).find(interfaceId);
            Coveo.$$(root).on('buildingQuery', function (e, args) {
                args.queryBuilder.advancedExpression.addFieldExpression('@Html.Raw(fieldName)', '==', '@Html.Raw(cookieValues)');

Which ends up rendered out on the page as:

As I've mentioned, the field that I'm searching on is a multivalue field, which is configured as such:

      <fieldNames hint="raw:AddFieldByFieldName">
        <fieldType fieldName="taggedLocationAndInvestor" isMultiValue="true" settingType="Coveo.Framework.Configuration.FieldConfiguration, Coveo.Framework"/>
      <fields hint="raw:AddComputedIndexField">
        <field fieldName="taggedLocationAndInvestor">Dotcom.Web.ComputedIndexFields.TaggedLocationAndInvestorField, Dotcom.Web</field>

And you can see my example page has this field populated in the index:

So, based on the script that I've added, I only want results in the taggedlocationandinvestor field that have a specific value… and in this case, my test page does not have that value in its list, but the page is still returning. So obviously something isn't wired up correctly, and my expression isn't firing like I want it to.

Is there anything that stands out that isn't wired up correctly, which would account for this behavior? Is the multivalue index field declared correctly? Is the query syntax off? Do I need to do anything to account for the appended and prepended characters in the field name? Are there maybe some special characters that I'm using in my query or field that need to be escaped?

Like I said, it feels like I'm so close to getting this wrapped up, but something isn't quite clicking yet.

Ask a question