Improving custom macro performance in scoring and contact groups

This topic describes two ways in which you can improve macro performance in scoring and contact groups:

  1. Create a custom macro rule translator - by default, custom macro rules that you use in scoring and contact group conditions evaluate individually for each contact. You can improve the recalculation performance by implementing and registering translators for these macro rules. Once a macro rule has a translator registered, a database query is constructed that then selects only the contacts that fit the given macro condition.
  2. (Contact groups) Limit unnecessary recalculations - you can further improve your site performance by making sure your custom contact group macro rules are recalculated only when users perform activity types that are relevant to the macro rule.
Default macro rules

Macro rules available in Kentico by default have both these optimizations implemented out of the box.

Creating a custom macro rule translator

  1. Create a class that implements the IMacroRuleInstanceTranslator interface.
  2. Implement the logic of the macro rule in a method that returns a query of the ObjectQuery<ContactInfo> type. The returned object needs to contain the contacts that fulfill the condition. Note that you do not have to handle contextual information, such as site context, in the query.

    Example of an implemented ContactIsFemaleMacro rule translator
    using CMS.Base;
    using CMS.DataEngine;
    using CMS.MacroEngine;
    using CMS.Membership;
    using CMS.OnlineMarketing;
    
    class ContactIsFemaleInstanceTranslator: IMacroRuleInstanceTranslator
    {
        /// <summary>
        /// Translates ContactIsFemaleMacro rule.
        /// </summary>
        public ObjectQuery<ContactInfo> Translate(MacroRuleInstance macroRuleInstance)
        {
            if (macroRuleInstance == null)
            {
                throw new ArgumentNullException("macroRuleInstance");
            }
            if (macroRuleInstance.MacroRuleName != "ContactIsFemaleMacro")
            {
                throw new ArgumentException("[ContactIsFemaleTranslator.Translate]: Only macro rule instances of type ContactIsFemaleMacro can be translated");
            }
    		// ruleParameters["_is"] accesses the data contacts enter in macro fields
            string paramIs = ruleParameters["_is"].Value;
            QueryOperator queryOperator = paramIs == "!" ? QueryOperator.NotEquals : QueryOperator.Equals;
    
            return ContactInfoProvider.GetContacts().Where("ContactGender", queryOperator, (int)UserGenderEnum.Female);
        }
    }
  3. Register an instance of the MacroRuleMetadata class through the MacroRuleMetadataContainer.RegisterMetadata method. There are two ways in which you can register the class at the beginning of the application's lifecycle:

    • During the initialization process of the application itself — use the CMSModuleLoader partial class in the App_Code folder.
    • When initializing custom modules — override the OnInit method of the module class.

    protected override void OnInit()
    {
    	...
    	MacroRuleMetadata metadata = new MacroRuleMetadata( "ContactIsFemaleMacro" , new ContactIsFemaleInstanceTranslator());
    	MacroRuleMetadataContainer.RegisterMetadata(metadata);
        ...
    }
  4. Save the files.

Now, when you use the translated macro rule in a scoring or contact group condition, the query is only performed once when you run recalculation.
 

Compound conditions

Note that all macro rules used in a contact group or scoring macro conditions need to be translated. Otherwise, the evaluation will be performed in the non-optimized way.

Recalculating contact group rules only for specific activities

Another way of improving your site performance is making sure that your custom contact group macro rules aren't recalculated when contacts perform activities unrelated to the macro rule.

Examples:

  • The "ContactIsFemale" macro doesn't need to be rebuilt by any contact activity that the visitor performs on the site.
  • A rule that checks whether contact is registered for an event ("CMSContactIsRegisteredForSpecifiedEvent" macro by default) only needs to be rebuilt when a visitor performs an event booking activity on the site ("EVENT_BOOKING" activity by default).
  • A rule that checks whether contact has visited a page ("CMSContactHasVisitedSpecifiedPageInLastXDays" macro by default) only needs to be rebuilt when a visitor performs an event booking activity on the site ("PAGE_VISIT" activity by default).

 

To specify the activities that rebuild your custom macro rule

  1. Create a custom macro rule translator

  2. Extend the instantiation of metadata by a parameter. The parameter specifies the activity or a set of activities for which you want the macro to rebuild.

    Rebuild custom macro rule for a single activity  Expand source
    protected override void OnInit()
    {
    	...
    	MacroRuleMetadata metadata = new MacroRuleMetadata("ContactHasVisitedSpecifiedPageInLastXDays", new ContactHasVisitedSpecifiedPageInLastXDaysTranslator(), PredefinedActivityType.PAGE_VISIT);
    	MacroRuleMetadataContainer.RegisterMetadata(metadata);
    	...
    }
    Rebuild custom macro rule for a custom activity  Expand source
    protected override void OnInit()
    {
    	...
    	MacroRuleMetadata metadata = new MacroRuleMetadata("ContactHasVisitedSpecifiedPageInLastXDays", new ContactHasVisitedSpecifiedPageInLastXDaysTranslator(), "custom_activity_codename");
    	MacroRuleMetadataContainer.RegisterMetadata(metadata);
    	...
    }
    Rebuild custom macro rule for a set of activities  Expand source
    protected override void OnInit()
    {
    	...
    	MacroRuleMetadata metadata = new MacroRuleMetadata("ContactIsSubscribedToSpecifiedNewsletter", new ContactIsSubscribedToSpecifiedNewsletterTranslator(), new List<string>() {
            PredefinedActivityType.NEWSLETTER_SUBSCRIBING, 
            PredefinedActivityType.NEWSLETTER_UNSUBSCRIBING,
        });
    	MacroRuleMetadataContainer.RegisterMetadata(metadata);
    	...
    }
    Do not rebuild custom macro rule for any activity  Expand source
    protected override void OnInit()
    {
    	...
    	MacroRuleMetadata registration = new MacroRuleMetadata("ContactIsFemaleMacro", new ContactIsFemaleInstanceTranslator(), new List<string>(0));
    	MacroRuleMetadataContainer.RegisterMetadata(metadata);	 
    	...
    }
  3. Save the files.

Now, only the specified contact activities will trigger a recalculation of the custom macro rule.