12

I've been trying to figure out, whether or not I can use Sitecore's xDB related functionalities to create a "other customers also bought" recommendation system.

The use case would be something like this: a user puts a set of products in a basket-like functionality and proceeds to the checkout. Once the user has decided to make the final purchase, I'd like to use Sitecore's xDB to show other products the user might be interested in, or perhaps something different in relation to the products, like guides or so.

My initial thought was to create personas, and tie these together with the products, such that person A is a person that buys X, Y, and Z and should be shown related products 1, 2, 3, etc. However, I am not sure if this will work in practice, and whether Sitecore is fit for such features.

So my question is, whether or not the default xDB functionalities in Sitecore can be used for this, and what the limitations are.

8

I think such functionality is absolutely an intended use case of xDB. From a high level, the approach would be:

  1. Create a custom facet for your customers which stores order history.
  2. Ensure that your customers are all imported into xDb, including order history.
  3. Ensure that when new orders are placed, that this facet is updated.
  4. Create a custom aggregation in your reporting database which effectively gives you "customers who bought X, also bought Y." Your "Fact" in this case would be:
    • Purchased Product
    • Other Product
    • Count
  5. Create a rendering which queries the reporting table and displays recommended products, based on some sort of threshold and/or ordered by Count.

The specifics of any of the above are too broad for this answer I think (since you are simply asking if it's possible). I think the big limitations at this time will be:

  • The need to duplicate your order data in xDB. In theory your AggregationProcessor could read directly from your order database however, if it's easily available. XConnect may help with the importing of this in the future.
  • You are potentially remotely querying the reporting database. Some performance testing and caching may be needed (though cache may be of limited use given the potential diversity of products / cache keys here). I assume that the forthcoming XConnect will help with this as well.

The real power of xDB would be adding additional elements to that Fact -- customer personas, geo, campaigns, etc. This allows you to essentially say "Customers LIKE YOU also bought," which you can't do with the commerce system on its own.

  • That's a very interesting suggestion! I haven't thought about using the RDB to store entity-level relationships. I don't believe xDB was necessarily built with such use cases in mind, since the RDB is normally only used in reports, not on every page load. It can even be inaccessible to content delivery servers. Anyway, I suppose your suggestion can work. A lot of performance issues should be considered and addressed, and I still believe building a custom data store will be easier and better suited for performance optimizations. – Dmytro Shevchenko Oct 6 '16 at 15:29
  • There may be architectural limitations currently, but I have to believe this is part of Sitecore's vision for its marketing platform -- real time response to customers based on historical data. Though not created directly by Sitecore, WeBlog uses the RDB to display popular posts. – techphoria414 Oct 6 '16 at 15:33
  • There are limits here: If you are using xDB cloud, you can't use custom facets due to the hosted aggregation/processing server. In addition, adding a lot of additional data to xDB is going to exponentially increase the disk space needed for Mongo, something thta was recently brought to my attention by Sitecore. – Pete Navarra Oct 6 '16 at 16:01
  • I do agree with you that xDB is intended for real time response. Use of machine learning tools I think will really drive this desire forward. – Pete Navarra Oct 6 '16 at 16:02
4

This question could lend itself to more of an opinion based response, and could be closed.

The linked article by Sean Fox does a good job at providing a way to drive to this information using xDB. However, I feel that specifically for "other customers also bought..." use case, this is handled by other systems.

IMHO, xDB is meant more for tracking what a user does during their visit, not what other users have done. It can be used for custom and exquisite personalization, however, I would recommend confining the scope of that effort to within the Contact interactions itself. That being said, yes all contact interactions are available, and with custom processing and aggregation you can get this information.

However, more appropriate is that many commerce platforms provide this type of functionality natively and is more in line with typical cart implementations. Active Commerce, Insite Commerce, and UCommerce for example provide this functionality.

With Sitecore working on a native Commerce solution too (albeit probably mostly for small scale solutions, and not trying to compete with the big commerce players), it would surprise me if Sitecore doesn't also provide this functionality, and would not surprise me at all if they DO leverage xDB for some of this.

  • 1
    I think a good solution would use a combination - perhaps storing purchases against a user in xDB (which is in the remit of customer information), and then regular processing of this data to create a network of related-products elsewhere that can be used by the site. – Kasaku Oct 6 '16 at 14:56
  • 1
    Yeah absolutely. Not saying that there isn't a plausible combination at all. But to utilize xDB solely for that is probably out of the scope that xDB was intended for. – Pete Navarra Oct 6 '16 at 14:59
  • Not the main point in your answer but I think Sitecore is absolutely trying to compete with the big commerce players (Hybris, IBM) with their solution. – techphoria414 Oct 6 '16 at 15:18
2

The first step in this journey will be to get this data into Mongo as the user visits your product detail pages.

First create a facet to hold the products your user is looking at.

using Sitecore.Analytics.Model.Framework;

namespace YourApp.Analytics.Interfaces.Entries
{
    public interface IElementProductInfo : IElement, IValidatable
    {
        string ProductId { get; set; }
        string Category { get; set; }
        string SubCategory { get; set; }
    }
}

Then you need to create a new container to hold the facets. Using IElementDictionary makes this a one to many facet in the contact record.

using Sitecore.Analytics.Model.Framework;

namespace YourApp.Analytics.Interfaces.Entries
{
    public interface IProductInfos : IFacet, IElement, IValidatable
    {
        IElementDictionary<IElementProductInfo> Entries { get; }

    }
}

Now you need to make a concrete serializable class of your ProductInfo class

namespace YourApp.Analytics.Models.Generated
{
    [Serializable]
    internal class ElementProductInfo : Element, IElementProductInfo, IElement, IValidatable
    {
        private const string productId = "productId";
        private const string category = "category";
        private const string subCategory = "subCategory";

        public ElementCustomerLookup()
        {
            base.EnsureAttribute<string>(productId);
            base.EnsureAttribute<string>(category);
            base.EnsureAttribute<string>(subCategory);
        }

        public string ProductId
        {
            get { return base.GetAttribute<string>(productId); }
            set { base.SetAttribute<string>(productId, value); }
        }

        public string Category
        {
            get { return base.GetAttribute<string>(category); }
            set { base.SetAttribute<string>(category, value); }
        }

        public string SubCategory
        {
            get { return base.GetAttribute<string>(subCategory); }
            set { base.SetAttribute<string>(subCategory, value); }
        }
    }
}

Now create a concrete class for your entities interface.

namespace YourApp.Analytics.Models.Generated
{
    [Serializable]
    internal class ProductInfos: Facet, IProductInfos, IFacet, IElement, IValidatable
    {

        private const string ENTRIES = "Entries";

        public IElementDictionary<IElementProductInfo> Entries
        {
            get
            {
                return base.GetDictionary<IElementProductInfo>("Entries");
            }
        }

        public ProductInfos()
        {
            base.EnsureDictionary<IElementProductInfo>("Entries");
        }
    }
}

Finially lets bring it all together in a config file. This will register your classes as facets and make them available for use in Mongo.

 <sitecore>
    <model>
      <elements>
        <element interface="YourApp.Analytics.Interfaces.Entries.IProductInfos, YourApp.Analytics" implementation="YourApp.Analytics.Models.Generated.ProductInfos, YourApp.Analytics" />
        <element interface="YourApp.Analytics.Interfaces.Entries.IElementProductInfo, YourApp.Analytics" implementation="YourApp.Analytics.Models.Generated.ElementProductInfo, YourApp.Analytics" />
      </elements>
      <entities>
        <contact>
          <facets>
            <facet name="ProductInformation" contract="YourApp.Analytics.Interfaces.Entries.IProductInfos, YourApp.Analytics" />
          </facets>
        </contact>
      </entities>
    </model>
  </sitecore>

The last bit it getting the data in Mongo is to add it to a users tracker.

var productInformationFacet = Tracker.Current.Contact.GetFacet<IProductInfos>("ProductInformation");
if (!productInformationFacet.Entries.Contains("YourProductId"))
{
    var customer = productInformationFacet.Entries.Create("YourProductId");

    customer.ProductId = "YourProductId";
    customer.Category = "YourCategory";
    customer.SubCategory = "YourSubCategory";
}

Your next step will be to aggregate up your data with your own BI logic. probably filtering on other products with the same category within a certain time frame. You will want to add a Processor to the analytics indexer. You can find a good example of that here. How can I create a custom report in Experience Analytics?

1

xDB centers around people (represented by contacts) and their actions (represented by interactions, page views, page events, outcomes, etc.). You can draw a lot of conclusions about each individual person by analyzing the data gathered for the corresponding contact. Though, there are no in-built means that can help you to understand relationships between contacts, or between other entities of your website. The only tool that gives some insight into page relationships is Path Analyzer, but it won't help you in your task.

The products that do provide the functionality you need are the different commerce platforms (Pete has listed a few). Using a commerce platform would be my recommendation. If you don't—well, then you are building your own commerce solution. You should then look at the ways in which other platforms work with product relationships and try to adapt them to your needs. For example, UCommerce adds several dozen SQL tables into Sitecore databases. One of them is uCommerce_ProductRelation that defines which products are related to each other and how they are related. Research how existing commerce solutions work and learn from them.

Overall, I don't see a way to do what you want without custom SQL tables, or MongoDB collections, or some graph database like Neo4j. You'll want to research how to access a custom data storage from Sitecore and store you product relationship data in the way that suits you best. Only then you'll be able to query your data store in your page code and display related products.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.