My favorites | English | Sign in

Google Desktop APIs (Labs)

Personalization API Developer Guide

The Personalization API introduced in 5.5 contains a ranking engine to help you sort items that users can click. For example, a gadget that displays items from an RSS feed can use the ranking engine to sort feed items.

Contents

  1. Overview
  2. Sample Code
  3. Attributes that Affect Ranking
  4. Changing How Items Are Ranked

Overview

You can use the ranking engine any time your gadget displays an ordered list of items. Just provide an array of rankable items or content items to the ranking engine, and the engine will return a sorted array of those items.

The ranking engine uses attributes such as clicks and the amount of time spent viewing items to determine how to sort the items. For example, if the user clicks every item except one, then by default that unclicked item will be the first item.

You can change how the ranking engine sorts items. For example, you can specify that a particular item should always be first or last. You can also group related items by specifying a data source for each group. Finally, you can not only set the values of attributes (such as clicks), but also specify how the ranking engine uses those attributes to sort items.

API support for ranking is provided by google.pers.ranking and RankableItem.

Back to top

Sample Code

Here's how you typically use the ranking API.

  1. Register to use the API by putting a <personalizationAPI> element in your gadget's gadget.gmanifest file. For example:
    <gadget minimumGoogleDesktopVersion="...">
      <about>
      <--! ... usual items such as name, description, and id go here ... -->
      <personalizationAPI />
      </about>
    </gadget>
    
  2. Create a profile for your gadget. You'll use this profile to identify your gadget whenever you call the ranking API. Here's an example of creating the profile:
    var profile = google.pers.ranking.createProfile("MyGadget");
    
  3. Unless you're ranking the items in a content area, create a RankableItem object for each item you want to be sorted.

    Note: Skip this step if you use a content area. This method is automatically called whenever the user adds a content item.

    For each rankable item, you need to specify an item identifier, a data-source identifier, and the profile. The item identifier can be anything that your gadget uses to identify the item; it might be a string or an array index. The data-source identifier is an application-specific number that you can use to group items. If you don't group items, just use the same data-source identifier for each item. Here's an example of creating RankableItem objects for items:

    var imageArray = new Array(); //one image per item
    var rankArray = new Array();  //one RankableItem per item
    ...
    //Just after an array of clickable items is created:
    for (var i = 0; i < numItems; i++) {
      var rankItem = google.pers.ranking.createRankableItem();
      rankItem.identifier = i;                   //set item ID
      rankItem.updateRankingProfile(1, profile); //set data-source ID & profile
      rankArray.push(rankItem);                  //add the rankable item to an array
    }
  4. Unless you're ranking the items in a content area, call an item's incrementClicksAndUpdateClickedTime() method whenever the user clicks the item.

    Note: Skip this step if you use a content area. This method is automatically called whenever the user clicks a content item or its details view's title.

    Usually, the value you specify to this method should be 1, but you can use a higher number to indicate that a click was more important. For example, you might use the value 2 for a double-click, or 5 for a click that was somehow as important as 5 ordinary clicks. Here's an example of calling incrementClicksAndUpdateClickedTime from an onclick handler:

    //rankIndex is the index of the selected item
    rankArray[rankIndex].incrementClicksAndUpdateClickedTime(1);
    
  5. Whenever you want to sort items — such as after a click or data refresh — call the rankAllItems() or rankItemsForDataSource() method. If you need to convert the return value to a JavaScript array, use toArray().
    //Typical code for a gadget that displays an array of items
    var selectedItemID = rankArray[rankIndex].identifier;
    rankArray = google.pers.ranking.rankAllItems(
      profile, rankArray, rankArray.length).toArray();
      
    //Keep the same selected item as before
    for (var i = 0; i < rankArray.length; i++) {
      if (rankArray[i].identifier == selectedItemID) {
        rankIndex = i;
        break;
      }
    }

    For a content area, your code should look like this:

    //Code for a content area
    var itemsToRank = contentArea.contentItems;
    var rankedItems = google.pers.ranking.rankAllItems(
      profile, itemsToRank, itemsToRank.toArray().length);
    contentArea.contentItems = rankedItems;
    

Back to top

Attributes that Affect Ranking

The ranking engine sorts items using the attributes shown in the following table. If your gadget has items from multiple data sources — from multiple RSS feeds, for example — then the data source can also affect the item order, as described in the following table.

Attribute Name Description Default Effect on Item Score Default Effect on Other Items
"NumberOfClicks" Number of times the item has been clicked.
Automatically set for content areas. To set for non-content areas, use incrementClicksAndUpdateClickedTime(), as shown in Sample Code.
More clicks = lower item score More clicks = higher scores for other items from the same data source
"LastClickedTime" How much time has passed since the item was clicked.
Automatically set for content areas. To set for non-content areas, use incrementClicksAndUpdateClickedTime(), as shown in Sample Code.
More time = higher item score More time = lower scores for other items from the same data source
"ItemTime" When the item was published (in an RSS feed).
Ignored unless you set the attribute value.
More recent = higher item score none
"ItemOpenDuration" The length of time the item's details were viewed.
Automatically set for content areas; ignored for non-content areas unless you set it. To set this attribute value, use the updateItemOpenDuration() method.
More time = lower item score More time = higher scores for other items from the same data source

In general, the higher an item's score is, the more prominent the item should be in your gadget's GUI. You don't directly use item scores. Instead, your gadget requests the ranking API to return an ordered array of items, where the first item in the array (index 0) has the highest score. For example, if the user clicks every item except one, then by default that unclicked item will be the first item in the returned array, and your gadget should display it in the most prominent position.

Back to top

Changing How Items Are Ranked

Although you can't directly change an item's score, you can affect how items are ranked. You can use these techniques:

Specifying an item's location

To specify that an item should always be at the top or bottom of the ranked list of items, use the rankType property of RankableItem.

topItem.rankType = contentRankingFlag.AlwaysTop;    //put this item at the top
botItem.rankType = contentRankingFlag.AlwaysBottom; //put this item at the bottom

Changing the value of an item's attribute

In general, you should use an attribute-specific method to set the value of an item's attribute. For example, use updateItemOpenDuration() to update the value of "ItemOpenDuration", and use incrementClicksAndUpdateClickedTime() to update the value of "NumberOfClicks" and "LastClickedTime". To reset all attribute values in an item, use resetStatistics().

To set the "ItemTime" attribute or make any other attribute of an item have a specific value, you need to use the updateAttributeValue() method. The following code shows how to set the "ItemTime" attribute value for an item.

//Parse the data to get date and time for an item.
...
//Create a Date and set the value of the ItemTime attribute.
var date = new Date(year, month, day, hours, minutes, seconds, ms);
item.updateAttributeValue("ItemTime", date.getTime()/1000);

All attributes have integer values; time-based values are in seconds. The "ItemTime" attribute supports two kinds of date formats:

  • UTC date as an integer: the number of seconds since 1/1/1970 UTC. Use the code date.getTime()/1000 to convert a JavaScript Date object to this format.
  • UTC date in VT_DATE format, as returned by JScript Date objects (see the getVarDate() method) and by some COM and ActiveX objects.

Changing an attribute's weight

Use modifyAttributeWeight() to increase or decrease the importance of a particular attribute. By default, all attributes start with the same weight (1.0), which makes them equally important. To ignore an element, set its weight to 0.0.

Here's an example of changing the weight of two items, making one more important and the other irrelevant.

//Make item time more important than attributes that have a weight of 1.0.
google.pers.ranking.modifyAttributeWeight("ItemTime", 2.0);

//Ignore the number of clicks.
google.pers.ranking.modifyAttributeWeight("NumberOfClicks", 0.0);

Changing an attribute's algorithm

Use modifyAttributeAlgorithm() to specify which algorithm to use for calculating the score of a particular attribute. You specify the algorithm using a combination of flags defined by contentRankingAlgorithm. The algorithm has two parts:

Proportionality — DirectlyProportional or InverselyProportional
A directly proportional algorithm increases the score as the attribute value increases. An inversely proportional algorithm reduces the score as the attribute value increases.
Steepness — LeastSteep or MostSteep
If you graph the attribute value on the x-axis and the score on the y-axis, the curve is flatter for LeastSteep than it is for MostSteep. In other words, "most steep" means that the score increases or decreases more as the attribute value increases. Because a click is usually much more significant than one second of time, by default "NumberOfClicks" uses MostSteep and time-based attributes use LeastSteep.

The following table shows the default algorithm used by each attribute.

Attribute Name Default Algorithm
"NumberOfClicks" InverselyProportional, MostSteep
"LastClickedTime" custom
"ItemTime" InverselyProportional, LeastSteep
"ItemOpenDuration" InverselyProportional, LeastSteep

Note: Don't set the algorithm for "LastClickedTime". It always uses a custom algorithm.

The following code changes the algorithm for the "NumberOfClicks" attribute. The default algorithm for "NumberOfClicks" (InverselyProportional and MostSteep) decreases the score significantly each time the item has been clicked. If you want the score to increase instead, you must change InverselyProportional to DirectlyProportional.

google.pers.ranking.modifyAttributeAlgorithm(
    "NumberOfClicks",
    contentRankingAlgorithm.DirectlyProportional | contentRankingAlgorithm.MostSteep);

Back to top