Skip to content

Commit

Permalink
Added support for user properties. Automatically split Batch with mor…
Browse files Browse the repository at this point in the history
…e than 10k requests to multiple Batch requests. Added cascadeCreate parameter to Set item/user values.
  • Loading branch information
OndraFiedler committed Dec 29, 2016
1 parent e451ae7 commit 07d36cb
Show file tree
Hide file tree
Showing 31 changed files with 1,177 additions and 85 deletions.
39 changes: 15 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Recombee API Client

A Java client for easy use of the [Recombee](https://www.recombee.com/) recommendation API.
A Java client (SDK) for easy use of the [Recombee](https://www.recombee.com/) recommendation API.

If you don't have an account at Recombee yet, you can create a free account [here](https://www.recombee.com/).

Expand All @@ -13,7 +13,7 @@ The client is available in the [Maven Central Repository](https://mvnrepository.
<dependency>
<groupId>com.recombee</groupId>
<artifactId>api-client</artifactId>
<version>1.2.5</version>
<version>1.3</version>
</dependency>
```

Expand All @@ -39,32 +39,24 @@ public class BasicExample {

RecombeeClient client = new RecombeeClient("client-test", "jGGQ6ZKa8rQ1zTAyxTc0EMn55YPF7FJLUtaMLhbsGxmvwxgTwXYqmUk5xVZFw98L");
try {
client.send(new ResetDatabase());
final int NUM = 100;
//Create some users and send them to Recombee, use Batch for faster processing
ArrayList<Request> addUserRequests = new ArrayList<Request>();
for (int i = 0; i < NUM; i++) addUserRequests.add(new AddUser(String.format("user-%s", i)));

System.out.println("Send users");
client.send(new Batch(addUserRequests));

//Now create some items
ArrayList<Request> addItemRequests = new ArrayList<Request>();
for (int i = 0; i < NUM; i++) addItemRequests.add(new AddItem(String.format("item-%s", i)));

System.out.println("Send items");
client.send(new Batch(addItemRequests));

// Generate some random purchases of items by users
final double PROBABILITY_PURCHASED = 0.01;
final double PROBABILITY_PURCHASED = 0.1;
Random r = new Random();
ArrayList<Request> addPurchaseRequests = new ArrayList<Request>();
for (int i = 0; i < NUM; i++)
for (int j = 0; j < NUM; j++)
if (r.nextDouble() < PROBABILITY_PURCHASED)
addPurchaseRequests.add(new AddPurchase(String.format("user-%s", i),String.format("item-%s", j)));
if (r.nextDouble() < PROBABILITY_PURCHASED) {

AddPurchase request = new AddPurchase(String.format("user-%s", i),String.format("item-%s", j))
.setCascadeCreate(true); // Use cascadeCreate parameter to create
// the yet non-existing users and items
addPurchaseRequests.add(request);
}

System.out.println("Send purchases");
client.send(new Batch(addPurchaseRequests));
client.send(new Batch(addPurchaseRequests)); //Use Batch for faster processing of larger data

// Get 5 recommendations for user 'user-25'
Recommendation[] recommended = client.send(new UserBasedRecommendation("user-25", 5));
Expand All @@ -81,6 +73,7 @@ public class BasicExample {
```

### Using property values

```java
package com.recombee.api_client.examples;

Expand Down Expand Up @@ -127,10 +120,9 @@ public class ItemPropertiesExample {
put("price", 600.0 + 400*rand.nextDouble());
put("num-cores", 1 + rand.nextInt(7));
put("description", "Great computer");
put("!cascadeCreate", true); // Use !cascadeCreate for creating item
// with given itemId, if it doesn't exist
}}
);
).setCascadeCreate(true); // Use cascadeCreate for creating item
// with given itemId, if it doesn't exist;
requests.add(req);
}
client.send(new Batch(requests)); // Send catalog to the recommender system
Expand Down Expand Up @@ -174,7 +166,6 @@ public class ItemPropertiesExample {
}
}
}

```

## Exception handling
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.recombee</groupId>
<artifactId>api-client</artifactId>
<version>1.2.5</version>
<version>1.3</version>
<name>Recombee API Client</name>
<description>A client library for easy use of the Recombee recommendation API</description>
<url>http://recombee.com</url>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,24 @@ public static void main(String[] args) {

RecombeeClient client = new RecombeeClient("client-test", "jGGQ6ZKa8rQ1zTAyxTc0EMn55YPF7FJLUtaMLhbsGxmvwxgTwXYqmUk5xVZFw98L");
try {
client.send(new ResetDatabase());
final int NUM = 100;
//Create some users and send them to Recombee, use Batch for faster processing
ArrayList<Request> addUserRequests = new ArrayList<Request>();
for (int i = 0; i < NUM; i++) addUserRequests.add(new AddUser(String.format("user-%s", i)));

System.out.println("Send users");
client.send(new Batch(addUserRequests));

//Now create some items
ArrayList<Request> addItemRequests = new ArrayList<Request>();
for (int i = 0; i < NUM; i++) addItemRequests.add(new AddItem(String.format("item-%s", i)));

System.out.println("Send items");
client.send(new Batch(addItemRequests));

// Generate some random purchases of items by users
final double PROBABILITY_PURCHASED = 0.01;
final double PROBABILITY_PURCHASED = 0.1;
Random r = new Random();
ArrayList<Request> addPurchaseRequests = new ArrayList<Request>();
for (int i = 0; i < NUM; i++)
for (int j = 0; j < NUM; j++)
if (r.nextDouble() < PROBABILITY_PURCHASED)
addPurchaseRequests.add(new AddPurchase(String.format("user-%s", i),String.format("item-%s", j)));
if (r.nextDouble() < PROBABILITY_PURCHASED) {

AddPurchase request = new AddPurchase(String.format("user-%s", i),String.format("item-%s", j))
.setCascadeCreate(true); // Use cascadeCreate parameter to create
// the yet non-existing users and items
addPurchaseRequests.add(request);
}

System.out.println("Send purchases");
client.send(new Batch(addPurchaseRequests));
client.send(new Batch(addPurchaseRequests)); //Use Batch for faster processing of larger data

// Get 5 recommendations for user 'user-25'
Recommendation[] recommended = client.send(new UserBasedRecommendation("user-25", 5));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,9 @@ public static void main(String[] args) {
put("price", 600.0 + 400*rand.nextDouble());
put("num-cores", 1 + rand.nextInt(7));
put("description", "Great computer");
put("!cascadeCreate", true); // Use !cascadeCreate for creating item
// with given itemId, if it doesn't exist
}}
);
).setCascadeCreate(true); // Use cascadeCreate for creating item
// with given itemId, if it doesn't exist;
requests.add(req);
}
client.send(new Batch(requests)); // Send catalog to the recommender system
Expand Down
106 changes: 105 additions & 1 deletion src/main/java/com/recombee/api_client/RecombeeClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
Expand All @@ -44,7 +45,10 @@
import com.recombee.api_client.api_requests.ListSeriesItems;
import com.recombee.api_client.api_requests.ListGroups;
import com.recombee.api_client.api_requests.ListGroupItems;
import com.recombee.api_client.api_requests.GetUserValues;
import com.recombee.api_client.api_requests.ListUsers;
import com.recombee.api_client.api_requests.GetUserPropertyInfo;
import com.recombee.api_client.api_requests.ListUserProperties;
import com.recombee.api_client.api_requests.ListItemDetailViews;
import com.recombee.api_client.api_requests.ListUserDetailViews;
import com.recombee.api_client.api_requests.ListItemPurchases;
Expand All @@ -71,6 +75,8 @@ public class RecombeeClient {
String baseUri = "rapi.recombee.com";
ObjectMapper mapper;

final int BATCH_MAX_SIZE = 10000; //Maximal number of requests within one batch request

public RecombeeClient(String databaseId, String token) {
this.databaseId = databaseId;
this.token = token;
Expand Down Expand Up @@ -170,6 +176,26 @@ public User[] send(ListUsers request) throws ApiException {
return null;
}

public PropertyInfo send(GetUserPropertyInfo request) throws ApiException {
String responseStr = sendRequest(request);
try {
return this.mapper.readValue(responseStr, PropertyInfo.class);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}

public PropertyInfo[] send(ListUserProperties request) throws ApiException {
String responseStr = sendRequest(request);
try {
return this.mapper.readValue(responseStr, PropertyInfo[].class);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}

public DetailView[] send(ListItemDetailViews request) throws ApiException {
String responseStr = sendRequest(request);
try {
Expand Down Expand Up @@ -273,6 +299,11 @@ public Bookmark[] send(ListUserBookmarks request) throws ApiException {
/* End of the generated code */

public BatchResponse[] send(Batch batchRequest) throws ApiException {

if(batchRequest.getRequests().size() > this.BATCH_MAX_SIZE) {
return sendMultipartBatchRequest(batchRequest);
}

String responseStr = sendRequest(batchRequest);

try {
Expand Down Expand Up @@ -376,6 +407,20 @@ else if (request instanceof ListUsers)
parsedResponse = ar;
}

else if (request instanceof GetUserPropertyInfo)
{
Map<String, Object> obj = (Map<String, Object>) parsedResponse;
parsedResponse = new PropertyInfo(obj);
}

else if (request instanceof ListUserProperties)
{
ArrayList<Map<String, Object>> array = (ArrayList<Map<String, Object>>) parsedResponse;
PropertyInfo[] ar = new PropertyInfo[array.size()];
for(int j=0;j<ar.length;j++) ar[j] = new PropertyInfo(array.get(j));
parsedResponse = ar;
}

else if (request instanceof ListItemDetailViews)
{
ArrayList<Map<String, Object>> array = (ArrayList<Map<String, Object>>) parsedResponse;
Expand Down Expand Up @@ -467,7 +512,51 @@ else if (request instanceof ListUserBookmarks)
}
return null;
}
/* End of the generated code */



private BatchResponse[] sendMultipartBatchRequest(Batch batchRequest) throws ApiException {

List<List<Request>> requestChunks = getRequestsChunks(batchRequest);
ArrayList<BatchResponse[]> responses = new ArrayList<BatchResponse[]>();

for(List<Request> rqs: requestChunks)
responses.add(send(new Batch(rqs)));

return concatenateResponses(responses);
}

private List<List<Request>> getRequestsChunks(Batch batchRequest) {

ArrayList<List<Request>> result = new ArrayList<List<Request>>();
List<Request> requests = batchRequest.getRequests();
int fullparts = requests.size() / this.BATCH_MAX_SIZE;

for(int i=0;i<fullparts;i++)
result.add(requests.subList(i * this.BATCH_MAX_SIZE, (i+1) * this.BATCH_MAX_SIZE));

if(fullparts * this.BATCH_MAX_SIZE < requests.size())
result.add(requests.subList(fullparts * this.BATCH_MAX_SIZE, requests.size()));

return result;
}

private BatchResponse[] concatenateResponses(ArrayList<BatchResponse[]> responses)
{
int size = 0, i = 0;

for(BatchResponse[] rsps: responses) {
size += rsps.length;
}

BatchResponse[] result = new BatchResponse[size];

for(BatchResponse[] rsps: responses) {
for(BatchResponse rsp: rsps)
result[i++] = rsp;
}
return result;
} /* End of the generated code */

public Map<String, Object> send(GetItemValues request) throws ApiException {
String responseStr = sendRequest(request);
Expand All @@ -482,6 +571,21 @@ public Map<String, Object> send(GetItemValues request) throws ApiException {
return null;
}


public Map<String, Object> send(GetUserValues request) throws ApiException {
String responseStr = sendRequest(request);

TypeReference<HashMap<String,Object>> typeRef
= new TypeReference<HashMap<String,Object>>() {};
try {
return this.mapper.readValue(responseStr, typeRef);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}


public Recommendation[] send(UserBasedRecommendation request) throws ApiException {
return sendRecomm(request);
}
Expand Down
Loading

0 comments on commit 07d36cb

Please sign in to comment.