Personalize Find with Social, POC

If you are using Episerver Social on your site, it’s possible to “personalize” search results for a logged in user. Or more accurately, boost e.g. contenttypes or categories of content the user has rated.

It’s possible to get a list of content the user has rated on your site. With this list you can retrieve e.g. the categories or contenttype id’s for that content and add boostmatching for those categories or types to your Find query.

Of course this is not a full personalization, but it certainly makes a difference in the search results.

The samples are based on the SocialAlloy demo, with an Episerver Find implementation based on the regular Alloy site added to it.

In my tests I added some methods to the SocialRatingRepository from the SocialAlloy demo.

First you will need to get the e.g. 25 best rated content for the user. Social gives you the content GUID’s back, so you’ll need to get the actual content from the content repository. I added the following to the SocialRatingRepository.

public IEnumerable GetTopRatedPagesForUser(string userId)
{
    if (string.IsNullOrWhiteSpace(userId))
    {
        return new List();
    }

    Reference rater = Reference.Create(userId);

    ResultPage ratingPage = this.ratingService.Get(
        new Criteria()
            {
                Filter = new RatingFilter { Rater = rater },
                PageInfo = new PageInfo
                        {
                            PageSize = 25
                        },
                OrderBy = new List
                        {
                            new SortInfo(RatingSortFields.Value, false),
                            new SortInfo(RatingSortFields.Created,false),
                        }
            });

    return ratingPage.Results.Select(result => this.contentRepository.Get(Guid.Parse(result.Target.Id)));
}

Next add a method to get the categories for that content, and a counter how many times it occurred on the rated content.

public Dictionary GetFavoriteCategoriesForUser(string userId)
{
    Dictionary favoriteCategories = new Dictionary();

    if (string.IsNullOrWhiteSpace(userId))
    {
       return favoriteCategories;
    }

    List topRated = this.GetTopRatedPagesForUser(userId).ToList();

    foreach (ICategorizable page in topRated.OfType())
    {
        foreach (int categoryId in page.Category)
        {
            if (favoriteCategories.ContainsKey(categoryId))
            {
                favoriteCategories[categoryId] += 1;
            }
            else
            {
                favoriteCategories.Add(categoryId, 1);
            }
        }
    }

    return favoriteCategories.OrderByDescending(c => c.Value).Take(5).ToDictionary(pair => pair.Key, pair => pair.Value);
}

For Find you’ll need an extension method to create the BoostMatching for the categories and add it to the query.

public static IQueriedSearch AddCategoryBoosts(
            this IQueriedSearch query,
            Dictionary favoriteCategories)
            where T : ICategorizable
{
    return favoriteCategories.Aggregate(
        query,
        (current, favoriteCategory) => current.BoostMatching(x => x.Category.In(new[] { favoriteCategory.Key }), favoriteCategory.Value));
}

When building you Find query you’ll need to do the following

string userId = this.userRepository.GetUserId(this.User);
Dictionary cats = this.socialRatingRepository.GetFavoriteCategoriesForUser(userId);

ITypeSearch query =
    this.searchClient.Search(
            this.searchClient.Settings.Languages.GetSupportedLanguage(ContentLanguage.PreferredCulture)
            ?? Language.None).For(model.Query)

            .AddCategoryBoosts(cats)

Now you have a way to personalize the search results for a user based on their ratings.

Full code sample can be found in a gist

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s