Skip to content

Commit 07d36cb

Browse files
committed
Added support for user properties. Automatically split Batch with more than 10k requests to multiple Batch requests. Added cascadeCreate parameter to Set item/user values.
1 parent e451ae7 commit 07d36cb

31 files changed

+1177
-85
lines changed

README.md

Lines changed: 15 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Recombee API Client
22

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

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

@@ -13,7 +13,7 @@ The client is available in the [Maven Central Repository](https://mvnrepository.
1313
<dependency>
1414
<groupId>com.recombee</groupId>
1515
<artifactId>api-client</artifactId>
16-
<version>1.2.5</version>
16+
<version>1.3</version>
1717
</dependency>
1818
```
1919

@@ -39,32 +39,24 @@ public class BasicExample {
3939

4040
RecombeeClient client = new RecombeeClient("client-test", "jGGQ6ZKa8rQ1zTAyxTc0EMn55YPF7FJLUtaMLhbsGxmvwxgTwXYqmUk5xVZFw98L");
4141
try {
42+
client.send(new ResetDatabase());
4243
final int NUM = 100;
43-
//Create some users and send them to Recombee, use Batch for faster processing
44-
ArrayList<Request> addUserRequests = new ArrayList<Request>();
45-
for (int i = 0; i < NUM; i++) addUserRequests.add(new AddUser(String.format("user-%s", i)));
46-
47-
System.out.println("Send users");
48-
client.send(new Batch(addUserRequests));
49-
50-
//Now create some items
51-
ArrayList<Request> addItemRequests = new ArrayList<Request>();
52-
for (int i = 0; i < NUM; i++) addItemRequests.add(new AddItem(String.format("item-%s", i)));
53-
54-
System.out.println("Send items");
55-
client.send(new Batch(addItemRequests));
56-
5744
// Generate some random purchases of items by users
58-
final double PROBABILITY_PURCHASED = 0.01;
45+
final double PROBABILITY_PURCHASED = 0.1;
5946
Random r = new Random();
6047
ArrayList<Request> addPurchaseRequests = new ArrayList<Request>();
6148
for (int i = 0; i < NUM; i++)
6249
for (int j = 0; j < NUM; j++)
63-
if (r.nextDouble() < PROBABILITY_PURCHASED)
64-
addPurchaseRequests.add(new AddPurchase(String.format("user-%s", i),String.format("item-%s", j)));
50+
if (r.nextDouble() < PROBABILITY_PURCHASED) {
51+
52+
AddPurchase request = new AddPurchase(String.format("user-%s", i),String.format("item-%s", j))
53+
.setCascadeCreate(true); // Use cascadeCreate parameter to create
54+
// the yet non-existing users and items
55+
addPurchaseRequests.add(request);
56+
}
6557

6658
System.out.println("Send purchases");
67-
client.send(new Batch(addPurchaseRequests));
59+
client.send(new Batch(addPurchaseRequests)); //Use Batch for faster processing of larger data
6860

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

8375
### Using property values
76+
8477
```java
8578
package com.recombee.api_client.examples;
8679

@@ -127,10 +120,9 @@ public class ItemPropertiesExample {
127120
put("price", 600.0 + 400*rand.nextDouble());
128121
put("num-cores", 1 + rand.nextInt(7));
129122
put("description", "Great computer");
130-
put("!cascadeCreate", true); // Use !cascadeCreate for creating item
131-
// with given itemId, if it doesn't exist
132123
}}
133-
);
124+
).setCascadeCreate(true); // Use cascadeCreate for creating item
125+
// with given itemId, if it doesn't exist;
134126
requests.add(req);
135127
}
136128
client.send(new Batch(requests)); // Send catalog to the recommender system
@@ -174,7 +166,6 @@ public class ItemPropertiesExample {
174166
}
175167
}
176168
}
177-
178169
```
179170

180171
## Exception handling

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>com.recombee</groupId>
88
<artifactId>api-client</artifactId>
9-
<version>1.2.5</version>
9+
<version>1.3</version>
1010
<name>Recombee API Client</name>
1111
<description>A client library for easy use of the Recombee recommendation API</description>
1212
<url>http://recombee.com</url>

src/examples/java/com/recombee/api_client/examples/BasicExample.java

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,32 +13,24 @@ public static void main(String[] args) {
1313

1414
RecombeeClient client = new RecombeeClient("client-test", "jGGQ6ZKa8rQ1zTAyxTc0EMn55YPF7FJLUtaMLhbsGxmvwxgTwXYqmUk5xVZFw98L");
1515
try {
16+
client.send(new ResetDatabase());
1617
final int NUM = 100;
17-
//Create some users and send them to Recombee, use Batch for faster processing
18-
ArrayList<Request> addUserRequests = new ArrayList<Request>();
19-
for (int i = 0; i < NUM; i++) addUserRequests.add(new AddUser(String.format("user-%s", i)));
20-
21-
System.out.println("Send users");
22-
client.send(new Batch(addUserRequests));
23-
24-
//Now create some items
25-
ArrayList<Request> addItemRequests = new ArrayList<Request>();
26-
for (int i = 0; i < NUM; i++) addItemRequests.add(new AddItem(String.format("item-%s", i)));
27-
28-
System.out.println("Send items");
29-
client.send(new Batch(addItemRequests));
30-
3118
// Generate some random purchases of items by users
32-
final double PROBABILITY_PURCHASED = 0.01;
19+
final double PROBABILITY_PURCHASED = 0.1;
3320
Random r = new Random();
3421
ArrayList<Request> addPurchaseRequests = new ArrayList<Request>();
3522
for (int i = 0; i < NUM; i++)
3623
for (int j = 0; j < NUM; j++)
37-
if (r.nextDouble() < PROBABILITY_PURCHASED)
38-
addPurchaseRequests.add(new AddPurchase(String.format("user-%s", i),String.format("item-%s", j)));
24+
if (r.nextDouble() < PROBABILITY_PURCHASED) {
25+
26+
AddPurchase request = new AddPurchase(String.format("user-%s", i),String.format("item-%s", j))
27+
.setCascadeCreate(true); // Use cascadeCreate parameter to create
28+
// the yet non-existing users and items
29+
addPurchaseRequests.add(request);
30+
}
3931

4032
System.out.println("Send purchases");
41-
client.send(new Batch(addPurchaseRequests));
33+
client.send(new Batch(addPurchaseRequests)); //Use Batch for faster processing of larger data
4234

4335
// Get 5 recommendations for user 'user-25'
4436
Recommendation[] recommended = client.send(new UserBasedRecommendation("user-25", 5));

src/examples/java/com/recombee/api_client/examples/ItemPropertiesExample.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,9 @@ public static void main(String[] args) {
4343
put("price", 600.0 + 400*rand.nextDouble());
4444
put("num-cores", 1 + rand.nextInt(7));
4545
put("description", "Great computer");
46-
put("!cascadeCreate", true); // Use !cascadeCreate for creating item
47-
// with given itemId, if it doesn't exist
4846
}}
49-
);
47+
).setCascadeCreate(true); // Use cascadeCreate for creating item
48+
// with given itemId, if it doesn't exist;
5049
requests.add(req);
5150
}
5251
client.send(new Batch(requests)); // Send catalog to the recommender system

src/main/java/com/recombee/api_client/RecombeeClient.java

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.io.UnsupportedEncodingException;
2222
import java.net.URLEncoder;
2323

24+
import java.util.List;
2425
import java.util.ArrayList;
2526
import java.util.Map;
2627
import java.util.HashMap;
@@ -44,7 +45,10 @@
4445
import com.recombee.api_client.api_requests.ListSeriesItems;
4546
import com.recombee.api_client.api_requests.ListGroups;
4647
import com.recombee.api_client.api_requests.ListGroupItems;
48+
import com.recombee.api_client.api_requests.GetUserValues;
4749
import com.recombee.api_client.api_requests.ListUsers;
50+
import com.recombee.api_client.api_requests.GetUserPropertyInfo;
51+
import com.recombee.api_client.api_requests.ListUserProperties;
4852
import com.recombee.api_client.api_requests.ListItemDetailViews;
4953
import com.recombee.api_client.api_requests.ListUserDetailViews;
5054
import com.recombee.api_client.api_requests.ListItemPurchases;
@@ -71,6 +75,8 @@ public class RecombeeClient {
7175
String baseUri = "rapi.recombee.com";
7276
ObjectMapper mapper;
7377

78+
final int BATCH_MAX_SIZE = 10000; //Maximal number of requests within one batch request
79+
7480
public RecombeeClient(String databaseId, String token) {
7581
this.databaseId = databaseId;
7682
this.token = token;
@@ -170,6 +176,26 @@ public User[] send(ListUsers request) throws ApiException {
170176
return null;
171177
}
172178

179+
public PropertyInfo send(GetUserPropertyInfo request) throws ApiException {
180+
String responseStr = sendRequest(request);
181+
try {
182+
return this.mapper.readValue(responseStr, PropertyInfo.class);
183+
} catch (IOException e) {
184+
e.printStackTrace();
185+
}
186+
return null;
187+
}
188+
189+
public PropertyInfo[] send(ListUserProperties request) throws ApiException {
190+
String responseStr = sendRequest(request);
191+
try {
192+
return this.mapper.readValue(responseStr, PropertyInfo[].class);
193+
} catch (IOException e) {
194+
e.printStackTrace();
195+
}
196+
return null;
197+
}
198+
173199
public DetailView[] send(ListItemDetailViews request) throws ApiException {
174200
String responseStr = sendRequest(request);
175201
try {
@@ -273,6 +299,11 @@ public Bookmark[] send(ListUserBookmarks request) throws ApiException {
273299
/* End of the generated code */
274300

275301
public BatchResponse[] send(Batch batchRequest) throws ApiException {
302+
303+
if(batchRequest.getRequests().size() > this.BATCH_MAX_SIZE) {
304+
return sendMultipartBatchRequest(batchRequest);
305+
}
306+
276307
String responseStr = sendRequest(batchRequest);
277308

278309
try {
@@ -376,6 +407,20 @@ else if (request instanceof ListUsers)
376407
parsedResponse = ar;
377408
}
378409

410+
else if (request instanceof GetUserPropertyInfo)
411+
{
412+
Map<String, Object> obj = (Map<String, Object>) parsedResponse;
413+
parsedResponse = new PropertyInfo(obj);
414+
}
415+
416+
else if (request instanceof ListUserProperties)
417+
{
418+
ArrayList<Map<String, Object>> array = (ArrayList<Map<String, Object>>) parsedResponse;
419+
PropertyInfo[] ar = new PropertyInfo[array.size()];
420+
for(int j=0;j<ar.length;j++) ar[j] = new PropertyInfo(array.get(j));
421+
parsedResponse = ar;
422+
}
423+
379424
else if (request instanceof ListItemDetailViews)
380425
{
381426
ArrayList<Map<String, Object>> array = (ArrayList<Map<String, Object>>) parsedResponse;
@@ -467,7 +512,51 @@ else if (request instanceof ListUserBookmarks)
467512
}
468513
return null;
469514
}
470-
/* End of the generated code */
515+
516+
517+
518+
private BatchResponse[] sendMultipartBatchRequest(Batch batchRequest) throws ApiException {
519+
520+
List<List<Request>> requestChunks = getRequestsChunks(batchRequest);
521+
ArrayList<BatchResponse[]> responses = new ArrayList<BatchResponse[]>();
522+
523+
for(List<Request> rqs: requestChunks)
524+
responses.add(send(new Batch(rqs)));
525+
526+
return concatenateResponses(responses);
527+
}
528+
529+
private List<List<Request>> getRequestsChunks(Batch batchRequest) {
530+
531+
ArrayList<List<Request>> result = new ArrayList<List<Request>>();
532+
List<Request> requests = batchRequest.getRequests();
533+
int fullparts = requests.size() / this.BATCH_MAX_SIZE;
534+
535+
for(int i=0;i<fullparts;i++)
536+
result.add(requests.subList(i * this.BATCH_MAX_SIZE, (i+1) * this.BATCH_MAX_SIZE));
537+
538+
if(fullparts * this.BATCH_MAX_SIZE < requests.size())
539+
result.add(requests.subList(fullparts * this.BATCH_MAX_SIZE, requests.size()));
540+
541+
return result;
542+
}
543+
544+
private BatchResponse[] concatenateResponses(ArrayList<BatchResponse[]> responses)
545+
{
546+
int size = 0, i = 0;
547+
548+
for(BatchResponse[] rsps: responses) {
549+
size += rsps.length;
550+
}
551+
552+
BatchResponse[] result = new BatchResponse[size];
553+
554+
for(BatchResponse[] rsps: responses) {
555+
for(BatchResponse rsp: rsps)
556+
result[i++] = rsp;
557+
}
558+
return result;
559+
} /* End of the generated code */
471560

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

574+
575+
public Map<String, Object> send(GetUserValues request) throws ApiException {
576+
String responseStr = sendRequest(request);
577+
578+
TypeReference<HashMap<String,Object>> typeRef
579+
= new TypeReference<HashMap<String,Object>>() {};
580+
try {
581+
return this.mapper.readValue(responseStr, typeRef);
582+
} catch (IOException e) {
583+
e.printStackTrace();
584+
}
585+
return null;
586+
}
587+
588+
485589
public Recommendation[] send(UserBasedRecommendation request) throws ApiException {
486590
return sendRecomm(request);
487591
}

0 commit comments

Comments
 (0)