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.
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
.
Here's how you typically use the ranking API.
<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>
var profile = google.pers.ranking.createProfile("MyGadget");
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 }
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);
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;
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.
Although you can't directly change an item's score, you can affect how items are ranked. You can use these techniques:
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
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:
date.getTime()/1000
to convert a JavaScript Date
object
to this format.Date
objects
(see the getVarDate()
method)
and by some COM and ActiveX objects.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);
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:
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);