This is a PHP library for interfacing with the Sugestio recommendation service. Data is submitted as JSON data. The library uses oauth-php to create the OAuth-signed requests. Our Drupal and Magento reference implementations are built on top of this generic library.
Sugestio is a scalable and fault tolerant service that now brings the power of web personalisation to all developers. The RESTful web service provides an easy to use interface and a set of developer libraries that enable you to enrich your content portals, e-commerce sites and other content based websites.
To access the Sugestio service, you need an account name and a secret key. To run the examples from the tutorial, you can use the following credentials:
- account name:
sandbox
- secret key:
demo
The Sandbox is a read-only account. You can use these credentials to experiment with the service. The Sandbox can give personal recommendations for users 1 through 5, and similar items for items 1 through 5.
When you are ready to work with real data, you may apply for a developer account through the Sugestio website.
The following API features are implemented:
- get personalized recommendations for a given user
- get items that are similar to a given item
- get users that are similar to a given user
- (bulk) submit user activity (consumptions): clicks, purchases, ratings, ...
- (bulk) submit item metadata: description, location, tags, categories, ...
- (bulk) submit user metadata: gender, location, birthday, ...
- delete consumptions
- delete item metadata
- delete user metadata
- get performance data (analytics): precision, recall, ...
oauth-php uses cURL for communicating with the recommendation service. As such, your system needs to have a current version of cURL installed. In addition, your PHP installation must include the php-curl extension and JSON support.
This distribution includes a slightly modified copy of oauth-php:
- OAuthRequester::doRequest does not throw an OAuthException2 on response codes >= 400
- Workaround for Issue #66
This section provides a quick demonstration of the Sugestio client object. A more detailed, step-by-step tutorial can be found further along this document.
require_once dirname(__FILE__) . '/SugestioClient.php';
require_once dirname(__FILE__) . '/SugestioUser.php';
require_once dirname(__FILE__) . '/SugestioItem.php';
require_once dirname(__FILE__) . '/SugestioConsumption.php';
$client = new SugestioClient('sandbox', 'demo');
// user X has consumed item Y
$consumption = new SugestioConsumption('X', 'Y'); // userid, itemid
$client->addConsumption($consumption);
// submit consumptions in bulk
$consumption1 = new SugestioConsumption('X', 'Y');
$consumption2 = new SugestioConsumption('X', 'Z');
$consumptions = array($consumption1, $consumption2);
$client->addConsumptions($consumptions);
// delete all consumptions made by user X
$client->deleteUserConsumptions('X');
// submit item metadata for item with ID Y
$item = new SugestioItem('Y');
$item->title = 'Item Y';
$item->category = array('A', 'B');
$client->addItem($item);
// get recommendations for user 1
$recommendations = $client->getRecommendations(1);
// two best recommendations for user 1
$recommendations = $client->getRecommendations(1, array('limit'=>2));
// only recommendations from category 'music'
$recommendations = $client->getRecommendations(1, array('category'=>'music'));
// only recommendations within 1 mile of this location
$queryParams = array(
'location_latlong'=>'40.688889,-74.045111',
'location_radius'=>'1',
'location_unit'=>'mi');
$recommendations = $client->getRecommendations(1, $queryParams);
// combined filter
$queryParams = array(
'limit'=>5, // best five
'category'=>'A,!B,C' // from category A or C, but not B
'location_latlong'=>'40.688889,-74.045111',
'location_radius'=>'1',
'location_unit'=>'mi');
$recommendations = $client->getRecommendations(1, $queryParams);
Tutorial.php
contains sample code that illustrates how you can use the library.
You can uncomment the function that you want to try out. The rest of this section shows you
how to use the SugestioClient
object's public methods and what kind of response
to expect from the service. There are also some pointers on how to integrate the library into
an existing e-commerce application.
Access credentials can be statically configured through Settings.php
:
$account = 'sandbox';
$secretkey = 'demo';
Alternatively, you can provide your account name and secret key when you
create an instance of the SugestioClient
class. Constructor
arguments override Settings.php
:
$client = new SugestioClient(); // use values from Settings.php
$client = new SugestioClient('sandbox', 'demo'); // override Settings.php
Suppose we want to generate a personalized content offer for user 1.
$recommendations = $client->getRecommendations(1);
echo '<pre>';
print_r($recommendations);
echo '</pre>';
The client responds with an indexed array of associative arrays. Each associative array represents a recommendation. Recommendations are sorted by descending score. In other words, the item that best fits this user's taste is listed first. The item element is only present if the service has metadata for the item in question.
Array
(
[0] => Array
(
[itemid] => 1
[score] => 0.9
[algorithm] => Sandbox
[certainty] => 0.1
[item] => Array
(
[id] => 1
[title] => Item 1
[permalink] => http://localhost/pages/1
[category] => Array
(
[0] => A
[1] => B
)
)
)
[1] => Array
(
[itemid] => 2
[score] => 0.8
[algorithm] => Sandbox
[certainty] => 0.1
[item] => Array
(
[id] => 2
[title] => Item 2
[permalink] => http://localhost/pages/2
[category] => Array
(
[0] => B
[1] => C
)
)
)
...
)
Let's assume our web application stores the ID of the current user in a session variable
$_SESSION['userid']
. We can use this variable to retrieve personal recommendations
for this user. The title attribute of the item element can be used to easily visualize the
recommendations.
function showRecommendations() {
echo "<h2>You may like these products:</h2>";
global $client;
$recommendations = $client->getRecommendations($_SESSION['userid']);
foreach ($recommendations as $recommendation) {
$title = $recommendation['item']['title'];
$link = "/productdetails.php?id=" . $recommendation['itemid'];
echo "<a href=\"$link\">$title</a><br/>";
}
}
Suppose we want to show similar products on our product pages. To get items that are similar to item 1:
$recommendations = $client->getSimilarItems(1);
echo '<pre>';
print_r($recommendations);
echo '</pre>';
Like with getRecommendations()
, the client responds with an indexed array
of associative arrays. Each associative array represents an item recommendation. These are again
sorted by descending score. In other words, the item that is the most similar to item 1,
is listed first.
Array
(
[0] => Array
(
[itemid] => 2
[score] => 0.8
[certainty] => 0.5
[algorithm] => Sandbox
[item] => Array
(
[id] > 2
[title] => Item 2
[permalink] => http://localhost/pages/2
[category] => Array
(
[0] => B
[1] => C
)
)
)
[1] => Array
(
[itemid] => 3
[score] => 0.7
[certainty] => 0.5
[algorithm] => Sandbox
[item] => Array
(
[id] => 3
[title] => Item 3
[permalink] => http://localhost/pages/3
[category] => Array
(
[0] => C
[1] => D
)
)
)
...
)
Suppose the user is currently viewing a product page. The URL for this product page might look
like this: productdetails.php?id=1
. Displaying a list of products which are similar
could go like this:
function showSimilar() {
echo "<h2>People who bought this product, also bought:</h2>";
global $client;
$recommendations = $client->getSimilarItems($_GET['id']);
foreach ($recommendations as $recommendation) {
$title = $recommendation['item']['title'];
$link = "/productdetails.php?id=" . $recommendation['itemid'];
echo "<a href=\"$link\">$title</a><br/>";
}
}
Collaborative filtering algorithms find clusters of users with a similar consumption behaviour. These users are called neighbours. Run the following code to get the users that are similar to user 1:
$recommendations = $client->getSimilarUsers(1);
echo '<pre>';
print_r($recommendations);
echo '</pre>';
As usual, the client responds with an indexed array of associative arrays. Each associative array represents a neighbour of user 1. These user recommendations are again sorted by descending score. In other words, the user that is the most similar to user 1, is listed first.
Array
(
[0] => Array
(
[userid] => 2
[score] => 0.9
[certainty] => 0.5
[algorithm] => Sandbox
)
[1] => Array
(
[userid] => 3
[score] => 0.8
[certainty] => 0.5
[algorithm] => Sandbox
)
...
)
Clusters of similar users can be useful input for other processes.
Consumptions are user-item interactions. You may want to submit a consumption anytime somebody places an order or rates a product. Consumption data is essential to generating good recommendations. Collaborative filtering algorithms can function on just consumption data.
Here, we introduce a new class, SugestioConsumption
. The constructor takes
two arguments; user id and item id.
In the following code fragment, we record that user 1 has consumed item A.
$consumption = new SugestioConsumption(1, 'A'); // userid, itemid
$result = $client->addConsumption($consumption);
echo "addConsumption response code: $result";
It can be beneficial to submit more information about a consumption. In the following example,
we specify that the user purchased product A. We also set the time of consumption through
the date
property. The service automatically replaces 'NOW' with the current
date.
$consumption = new SugestioConsumption(1, 'A'); // userid, itemid
$consumption->type = 'PURCHASE';
$consumption->date = 'NOW';
$result = $client->addConsumption($consumption);
echo "addConsumption response code: $result";
Item ratings can provide a good basis for quality recommendations. Suppose users can give a star rating from one to five. In the following example, user 1 gives three stars to product A:
$consumption = new SugestioConsumption(1, 'A'); // userid, itemid
$consumption->type = 'RATING';
$consumption->detail = 'STAR:5:1:3';
$consumption->date = 'NOW';
$result = $client->addConsumption($consumption);
echo "addConsumption response code: $result";
See the API documentation for information on supported date formats and consumption types.
The web service responds with standard HTTP status codes:
- 202 Accepted
- 400 Bad Request
- 401 Unauthorized
- 500 Internal Server Error
The example above will generate the following output:
addConsumption response code: 202
This indicates that the consumption submission was well-formed and that it was succesfully processed by the Sugestio service.
The following code omits the required field user id and will be rejected by the service:
$consumption = new SugestioConsumption(null, 'A'); // userid, itemid
$result = $client->addConsumption($consumption);
echo "addConsumption response code: $result";
The output will read:
addConsumption response code: 400
Suppose our e-commerce application has a method placeOrder($customer, $basket)
which is called when an order has been finalized. $basket
contains a list of all
the products that are part of this order. Each of these product purchases will represent
a new consumption:
function placeOrder($customer, $basket) {
// existing application logic
// ...
// the customer has ordered one or more products
// the order has been correctly stored in our local database
// now submit the consumption data to the recommendation service
global $client;
foreach ($basket->getProducts() as $product) {
$consumption = new Consumption($customer['id'], $product['id']);
$consumption->date = 'NOW';
$consumption->type = 'PURCHASE';
$client->addConsumption($consumption);
}
}
Content-based algorithms use item metadata to generate recommendations. The
SugestioItem
class lets you assign all kinds of metadata to items.
Some examples are:
- title
- permalink
- tags
- category information
- availability
- location data
- a short textual description
- ...
Some attributes, like location, take a scalar value. Because items can have multiple tags or categories associated with them, we have to assign an indexed array to these attributes. Title and permalink can be used to easily visualize the recommendations, so it's a good idea to always submit these attributes.
For a full list of item attributes and how to use them, see the API documentation.
The SugestioItem
constructor takes a single value, the item id. We also assign
values to various attributes, both scalar and non-scalar.
$item = new SugestioItem('A');
$item->title = "Item A";
$item->permalink = "http://localhost/products/A";
$item->tag = array('tag1', 'tag2');
$item->category = array('category1', 'category2');
$item->creator = array('artist1');
$item->location_latlong = '40.446195,-79.948862';
$result = $client->addItem($item);
echo "addItem response code: $result";
The web service responds with standard HTTP status codes:
- 202 Accepted
- 400 Bad Request
- 401 Unauthorized
- 500 Internal Server Error
The example above will generate the following output:
addItem response code: 202
This indicates that the item submission was well-formed and that it was succesfully processed by the Sugestio service.
Let's assume our e-commerce application has a control panel for adding new products to the
catalog. A method createProduct($productInfo)
gets its input from a product input form and
creates a new record in the Product table of our SQL database. Once the database has generated
a unique id for this product, we can submit metadata to the recommendation service:
function createProduct($productInfo) {
// existing application logic
// ...
$newProductId = $db->add($productInfo);
// a new row has been added to our Product table
// now we submit the product metadata to the recommendation service
global $client;
$item = new SugestioItem($newProductId);
$item->title = $productInfo['name'];
$item->tag = $productInfo['tag'];
$item->category = $productInfo['category'];
$client->addItem($item);
}
Basic demographic information about a user can be useful when generating recommendations.
The SugestioUser
class lets you assign all kinds of metadata to users.
Some examples are:
- Gender
- Birthday
- Location
- ...
For a full list of user attributes and how to use them, see the API documentation.
The SugestioUser
constructor takes a single value, the user id.
We also assign values to the gender and birthday attributes.
$user = new SugestioUser(1);
$user->gender = 'M';
$user->birthday = '1974-03-20';
$result = $client->addUser($user);
echo "addUser response code: $result";
The web service responds with standard HTTP status codes:
- 202 Accepted
- 400 Bad Request
- 401 Unauthorized
- 500 Internal Server Error
The example above will generate the following output:
addUser response code: 202
This indicates that the user submission was well-formed and that it was succesfully processed by the Sugestio service.
Let's assume our e-commerce application has a method createCustomer($customerInfo)
that gets its
input from a registration form and creates a new record in the User table of our SQL database.
Once the database has generated a unique id for this customer, we can transmit some metadata to
the recommendation service:
function createCustomer($customerInfo) {
// existing application logic
// ...
$newCustomerId = $db->add($customerInfo);
// a new row has been added to our User table
// now we submit the user data to the recommendation service
global $client;
$user = new SugestioUser($newCustomerId);
$user->gender = $customerInfo['gender'];
$user->birthday = $customerInfo['birthday'];
$client->addUser($user);
}
Periodically, the available consumption data is divided into a training set and a test set. The service then calculates a number of performance metrics. The Sugestio website visualizes this data as a chart, but you can also get the raw data through the API.
The getAnalytics
method takes an optional $limit
argument. Here, we
request the five most recent reports:
$analytics = $client->getAnalytics(5);
echo '<pre>';
print_r($analytics);
echo '</pre>';
The client responds with an indexed array of associative arrays. Each associative array represents a single analytics report. For brevity, only partial output is shown below.
Array
(
[0] => Array
(
[id] => f4fc18fa-3c7a-4daf-8807-01e4235d78ad
// ...
[evaluation_F1] => 0.0206286837
[evaluation_Precision] => 0.0257037944
[evaluation_Recall] => 0.0172272354
[evaluation_Recommendations] => 4085
[evaluation_RelevantRecommendations] => 105
[evaluation_TestSetFrom] => 2010-07-03T00:00:00
[evaluation_TestSetUntil] => 2010-08-03T00:00:00
[evaluation_TrainingSetFrom] => 2009-07-31T00:00
[evaluation_TrainingSetUntil] => 2010-07-03T00:00:00
// ...
[sparsity_AvgConsumptionsPerItemInTestSet] => 1.6850981476
[sparsity_AvgConsumptionsPerUserInTestSet] => 7.4602203182
[sparsity_ConsumptionsInTrainingSet] => 159803
[sparsity_ItemsInTestSet] => 3617
[sparsity_ItemsInTrainingSet] => 29748
[sparsity_PercTrainingUsersConsumingInTestSet] => 0.0459375879
// ...
)
[1] => Array
(
//...
)
// ...
)
The data can be imported into statistical tools for further analysis, or visualized as a graph. Google's Chart API is a great tool for charting dynamic data.