Relevance: Negation of characteristic

Hi all,

For an implementation of Relevance, I required the negation of a characteristic. More specific: the use-case I’m working on requires the visitor to not come from a specific country.

What I did now (which isn’t working btw) is:

  1. Create a characteristic:
targeting/characteristics/notcountry.yaml
definitions:
      config:
        /targeting:targeting/targeting:characteristics/notcountry:
          jcr:primaryType: targeting:characteristic
          targeting:collector: geo
          targeting:scorerClassName: nl.anwb.relevance.scoring.NotCountryScorer
          /gb-1557409785193:
            jcr:primaryType: targeting:targetgroup
            targeting:name: GB
            targeting:propertynames: [GB]
hcm-config/configuration/frontend.yaml
definitions:
  config:
    /hippo:configuration/hippo:frontend/cms/hippo-targeting/characteristic-notcountry:
      jcr:primaryType: frontend:plugin
      characteristic: notcountry
      collector: geo
      plugin.class: nl.anwb.relevance.characteristics.NotCountryCharacteristicPlugin
      visitor.characteristic.visible: true
    /hippo:configuration/hippo:frontend/cms/hippo-targeting/experience-optimizer-perspective:
      google.api.key: our-key
  1. Create a plugin class:
NotCountryCharacteristicPlugin.java
@ExtClass("ANWB.NotCountryCharacteristicPlugin")
    public class NotCountryCharacteristicPlugin extends BuiltinCharacteristicPlugin {

    private static final JavaScriptResourceReference DOCTYPE_JS =
            new JavaScriptResourceReference(NotCountryCharacteristicPlugin.class,
                    "NotCountryCharacteristicPlugin.js");


    public NotCountryCharacteristicPlugin(final IPluginContext context, final IPluginConfig config) {
        super(context, config);
    }

    @Override
    protected ResourceReference getIcon() {
        return new PackageResourceReference(NotCountryCharacteristicPlugin.class, "NotCountryGlobe.svg");
    }

    @Override
    public void renderHead(final Component component, IHeaderResponse response) {
        super.renderHead(component, response);
        response.render(JavaScriptHeaderItem.forReference(DOCTYPE_JS));
    }
}
  1. Add the plugin javascript:
NotCountryCharacteristicPlugin.js
Ext.namespace('ANWB');
ANWB.NotCountryCharacteristicPlugin = Ext.extend(Hippo.Targeting.CharacteristicPlugin, {

  constructor: function (config) {
    ANWB.NotCountryCharacteristicPlugin.superclass.constructor.call(this, Ext.apply(config, {
      visitorCharacteristic: {
        targetingDataProperty: 'country',
        xtype: 'Hippo.Targeting.TargetingDataPropertyCharacteristic'
      }
    }));
  }

});

Ext.reg('ANWB.NotCountryCharacteristicPlugin',
  ANWB.NotCountryCharacteristicPlugin);

ANWB.NotCountryCharacteristic =
  Ext.extend(Hippo.Targeting.VisitorCharacteristic, {

    isCollected: function (targetingData) {
      console.log(targetingData.country);
      return !this.isEmptyObject(targetingData.country);
    },

    isEmptyObject: function (object) {
      var isEmpty = true;
      if (!Ext.isEmpty(object)) {
        Ext.iterate(object, function () {
          isEmpty = false;
          return false;
        })
      }
      return isEmpty;
    },

    getTargetGroupName: function (targetingData) {
      return targetingData.country;
    },

    getTargetGroupProperties: function (targetingData) {
      var properties = [];
      properties.push({
        name: targetingData.country,
        value: ''
      });
      return properties;
    }

  });
Ext.reg('ANWB.NotCountryCharacteristic',
  ANWB.NotCountryCharacteristic);
  1. Create my negation scorer which extends the CountryScorer
NotCountryScorer.java
public class NotCountryScorer extends CountryScorer implements Scorer<GeoIPTargetingData> {

    @Override
    public void init(final Map<String, TargetGroup> targetGroups) {
        super.init(targetGroups);
    }

    @Override
    public double evaluate(final String targetGroupId, final GeoIPTargetingData targetingData) {
        double countryScore = super.evaluate(targetGroupId, targetingData);
        // Negation
        return 1.0 - countryScore;
    }
}

Now I specifically reused the GeoIpCollector, but applied a different scorer (my negation scorer).
With the above code, this characteristic has the exact same behaviour as the country characteristic. So what I thought I needed to do is change the characteristic used in the frontend plugin to my characteristic “notcountry” like so:

Change
NotCountryCharacteristicPlugin.js:7

    targetingDataProperty: 'country',

to

    targetingDataProperty: 'notcountry',

But this just results in the characteristic not showing and / or functioning at all anymore.

The problem I’m facing aswell is that debugging scorers seems to not work? Am I missing something here? When I try to add a breakpoint to CountryScorer#evaluate or my own NotCountryScorer#evaluate it never seems to hit this method. Is there an explanation for that?

I guess my real questions are:

  1. Is there a more straightforward approach to negating maybe?
  2. How can I make the above example work? Any ideas / pointers?
  3. How can I debug Relevance Scorers?

Any help is appreciated :slight_smile:

Kind regards,
Jens

I’d rather use EIRE plugin [1]. It lets me achieve the goal 5+ times faster.

[1] https://documentation.bloomreach.com/library/enterprise/services-features/inference-engine/introduction.html

1 Like

Haha, this is the first time I discover the EIRE plugin. It’s brilliant :smiley: ! It makes Relevance so much easier. I can’t believe I never came across this before.