Walkthrough: Creating a rate page custom aggregation

Last updated Friday, January 20, 2017 in Sitecore Experience Platform for Developer
Keywords: Development

Aggregation is a type of processing that reduces and adapts data from the MongoDB collection database so that it can be used in Sitecore reporting applications. There are several aggregations that come with Sitecore and that work out of the box, such as for Experience Analytics reports.

If you add new functionality to your website that requires you to extract and present data from the xDB in a different way, you can write your own custom aggregation.

Note

You should follow this approach if the data that you want to extract is from a high number of interactions or if the extraction process is relatively resource intensive.

This walkthrough describes how to create a custom aggregation using an example developed for the sitecore.net website. On the sitecore.net website, visitors can rate blog posts by adding their own star ratings. Rating data can then be used to sort and search through posts.

Picture 10

This walkthrough includes sample code that you can reuse in your own solution and all the steps that you need to create a custom aggregation:

  • Create a rate page event
  • Create a fact table
  • Create fact and dimension model classes
  • Implement the aggregation processor
  • Register your custom aggregation

Create a rate page event

To create a rate page event, you need to implement the following code, so that when a visitor clicks a star to rate the blog post, the system registers a new rate page event for the current page. When a visitor rates a page, this writes the selected value (from 1 to 5) to the CustomValues collection with the key DataCode.

To do this:

  • Implement the following code to create a rate page event using the Sitecore Industry insight blog post:
    var eventData = new PageEventData("Rate")
        {
           Data = "Industry Insight",
           DataKey = "{7F84F941-A284-4DF5-9DE9-1B22A387039E}",
           Text = "Rated"
        };
    var eventRow = Tracker.Current.Interaction.PreviousPage.Register(eventData);
    eventRow.CustomValues["RateValue"] = 5;

Create a fact table

For custom aggregations, you need to create new fact tables that contain the measurements of the experience data that you want to aggregate. For this example, you need to create one new fact table.

  1. You need to run a SQL script to create a new fact table. For example:
    CREATE TABLE [dbo].[Fact_Rating](
    [ItemId]  UNIQUEIDENTIFIER NOT NULL,
    [Rating]   BIGINT NOT NULL,
    [Count]   BIGINT NOT NULL,
    CONSTRAINT [PK_Rating] PRIMARY KEY CLUSTERED ([ItemId])
    )
    GO
      
    ALTER TABLE [dbo].[Fact_Rating]  WITH NOCHECK
    ADD  CONSTRAINT [FK_Fact_Rating_Items]
    FOREIGN KEY([ItemId])
    REFERENCES [dbo].[Items] ([ItemId])
    GO
      
    ALTER TABLE [dbo].[Fact_Rating] NOCHECK
    CONSTRAINT [FK_Fact_Rating_Items]
    GO
    Where:
    ItemId – blog post ID( item ID in content tree)
    Rating – the total value given by all visitors
    Count – number of visitors who rated the post
  2. Execute the SQL script to create the new fact table.

Create fact and dimension model classes

To implement a class model for a new dimension:

  1. Create a new class that inherits from the DictionaryKey class and expose all the key fields as public properties (get and set).
  2. RatingKey.cs
    namespace Sitecore.Components.Community.BusinessLayer
    {
      using System;
      
      using Sitecore.Analytics.Aggregation.Data.Model;
      
      public class RatingKey : DictionaryKey
      {  
        public Guid ItemId { get; set; }
      }  
    }  
  3. Create a new class that inherits from the DictionaryValue class and add the required properties. Both the key and the value class must have a public default constructor.
  4. Create a new class that inherits from the Dimension<TKey, TValue> class, again with a public default constructor.
  5. RatingValue.cs
    namespace Sitecore.Components.Community.BusinessLayer
    {
      using Sitecore.Analytics.Aggregation.Data.Model;
      
      public class RatingValue : DictionaryValue
      {  
        internal static RatingValue Reduce(RatingValue left, RatingValue right)  
        {  
          var ratingValue = new RatingValue();  
      
          ratingValue.Count = left.Count + right.Count;
          ratingValue.Rating = left.Rating + right.Rating;
      
          return ratingValue;
        }
      
        public long Rating { get; set; }
      
        public long Count { get; set; }
      }
    }
    RatingFact.cs
    namespace Sitecore.Components.Community.BusinessLayer  
    {  
      using Sitecore.Analytics.Aggregation.Data.Model;  
      
      public class Rating : Fact<RatingKey, RatingValue>  
      {  
        public Rating() : base(RatingValue.Reduce)  
        {  
        }  
     
      }  

Implement the aggregation processor

To implement the aggregation processor:

  1. Create a new class that inherits from the AggregationProcessor base class.
  2. Implement the OnProcess(AggregationPipelineArgs args) method that is defined as an abstract method in the base class.
  3. AggregationProcessor.cs
    namespace Sitecore.Components.Community.BusinessLayer
    {  
      using System;  
      using System.Linq;  
      
      using Sitecore.Analytics.Aggregation.Pipeline;  
      using Sitecore.Analytics.Model;  
      using Sitecore.Diagnostics;  
      
      public class RatingProcessor : AggregationProcessor  
    {    
      private Guid RatePageEventDefinitionId = Guid.Parse("08E50AA5-E5E7-4845-940B-2E81FB3ED56C");  
     
        protected override void OnProcess(AggregationPipelineArgs args)
        {
          Assert.ArgumentNotNull(args, "args");
            
          if (args.Context.Visit.Pages == null)
          {
            return;
          }
      
          foreach (PageData page in args.Context.Visit.Pages)
          {
            if (page.PageEvents != null)
            {  
              var fact = args.GetFact<Rating>();
              foreach (var pageEvent in page.PageEvents.Where(p => p.PageEventDefinitionId
              == RatePageEventDefinitionId))
              {
                int rating = GetRating(pageEvent);
                var postId = GetPostId(pageEvent);
      
                if (rating > 0 && postId != Guid.Empty)
                {  
                  var ratingKey = new RatingKey();
                  ratingKey.ItemId = postId;
      
                  var ratingValue = new RatingValue();
                  ratingValue.Count = 1;
                  ratingValue.Rating = rating;
      
                  fact.Emit(ratingKey, ratingValue);
                }
              }
            }
          }
        }
      
        private int GetRating(PageEventData pageEvent)
        {
          int rating = 0;
          if (pageEvent.CustomValues.ContainsKey("RateValue"))
          {
            rating = (int)pageEvent.CustomValues["RateValue"];
          }
      
          return rating;
        }
      
        private Guid GetPostId(PageEventData pageEvent)
        {
          if (!string.IsNullOrEmpty(pageEvent.DataKey))
          {  
            Guid postId;  
            if (Guid.TryParse(pageEvent.DataKey, out postId))
            {  
              return postId;
            }
          }
      
          return Guid.Empty;
        }  
       }
    }

Register your custom aggregation

Now that you have implemented the aggregation processor, the final step is to register your custom aggregation:

  1. To ensure that your processor is executed, add it to a configuration file and save it to the App_Config/Include folder.
  2. Create a new configuration file for this purpose called Rating.Aggregation.config.

    The following sample illustrates where you add your custom aggregation in the Rating.Aggregation.config file:

    <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">  
      <sitecore>  
      
        <pipelines>  
            
          <group groupName="analytics.aggregation">  
            <pipelines>  
      
              <interactions>  
                  <processor   
    type="Sitecore.Components.Community.BusinessLayer.RatingProcessor,   
    Sitecore.Components.Community" />  
             </interactions>           
      
            </pipelines>  
          </group>  
              
        </pipelines>  
        
      </sitecore>  
    </configuration> 

Note

When you try out the example, remember to update your type and assembly names if they are not using the same namespace or assembly.

After you have completed all the steps in this custom aggregation walkthrough, you can rate blog articles and have the additional option to search blogs by popularity.

Picture 12