Skip to content

Commit 61d7fbc

Browse files
committed
Release: v6.2.0
- Added recommend-next-item-segments endpoint support - Added `searchQuery` parameter support for composite recommendations
1 parent 9934f0a commit 61d7fbc

10 files changed

+380
-138
lines changed

README.md

Lines changed: 102 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,12 @@ const client = new ApiClient(
3737

3838
const request = new requests.ListUsers({ count: 10 });
3939

40-
client
41-
.send(request)
42-
.then((result) => {
43-
console.log(result);
44-
})
45-
.catch((error) => {
46-
console.error(error);
47-
});
40+
try {
41+
const result = await client.send(request);
42+
console.log(result);
43+
} catch (error) {
44+
console.error(error);
45+
}
4846
```
4947

5048
```javascript
@@ -89,12 +87,12 @@ async function example() {
8987
const response = await client.send(
9088
new requests.RecommendItemsToUser("user-25", 5)
9189
);
92-
console.log("Recommended items for user-25: %j", response.recomms);
90+
console.log("Recommended items for user-25:", response.recomms);
9391
// User scrolled down - get next 3 recommended items
9492
const response2 = await client.send(
9593
new requests.RecommendNextItems(response.recommId, 3)
9694
);
97-
console.log("Next recommended items for user-25: %j", response2.recomms);
95+
console.log("Next recommended items for user-25:", response2.recomms);
9896
}
9997

10098
example();
@@ -121,137 +119,107 @@ const NUM = 100;
121119
// - image (url of computer's photo)
122120

123121
// Add properties of items
124-
client
125-
.send(
126-
new rqs.Batch([
127-
new rqs.AddItemProperty("price", "double"),
128-
new rqs.AddItemProperty("num-cores", "int"),
129-
new rqs.AddItemProperty("description", "string"),
130-
new rqs.AddItemProperty("time", "timestamp"),
131-
new rqs.AddItemProperty("image", "image"),
132-
])
133-
)
134-
.then((responses) => {
135-
//Prepare requests for setting a catalog of computers
136-
137-
var requests = Array.apply(0, Array(NUM)).map((_, i) => {
138-
return new rqs.SetItemValues(
139-
`computer-${i}`, //itemId
140-
//values:
141-
{
142-
price: 600 + 400 * Math.random(),
143-
"num-cores": Math.floor(Math.random() * 8) + 1,
144-
description: "Great computer",
145-
time: new Date().toISOString(),
146-
image: `http://examplesite.com/products/computer-${i}.jpg`,
147-
},
148-
//optional parameters:
149-
{
150-
cascadeCreate: true, // Use cascadeCreate for creating item
151-
// with given itemId, if it doesn't exist
152-
}
153-
);
154-
});
155-
//Send catalog to the recommender system
156-
return client.send(new rqs.Batch(requests));
157-
})
158-
.then((responses) => {
159-
// Generate some random purchases of items by users
160-
const userIds = Array.apply(0, Array(NUM)).map((_, i) => {
161-
return `user-${i}`;
162-
});
163-
const itemIds = Array.apply(0, Array(NUM)).map((_, i) => {
164-
return `computer-${i}`;
165-
});
122+
await client.send(
123+
new rqs.Batch([
124+
new rqs.AddItemProperty("price", "double"),
125+
new rqs.AddItemProperty("num-cores", "int"),
126+
new rqs.AddItemProperty("description", "string"),
127+
new rqs.AddItemProperty("time", "timestamp"),
128+
new rqs.AddItemProperty("image", "image"),
129+
])
130+
);
166131

167-
// Generate some random purchases of items by users
168-
const PROBABILITY_PURCHASED = 0.1;
169-
const purchases = [];
170-
userIds.forEach((userId) => {
171-
const purchased = itemIds.filter(
172-
() => Math.random() < PROBABILITY_PURCHASED
173-
);
174-
purchased.forEach((itemId) => {
175-
purchases.push(
176-
new rqs.AddPurchase(userId, itemId, { cascadeCreate: true })
177-
);
178-
});
179-
});
180-
// Send purchases to the recommender system
181-
return client.send(new rqs.Batch(purchases));
182-
})
183-
.then((responses) => {
184-
// Get 5 recommendations for user-42, who is currently viewing computer-6
185-
// Recommend only computers that have at least 3 cores
186-
return client.send(
187-
new rqs.RecommendItemsToItem("computer-6", "user-42", 5, {
188-
filter: "'num-cores' >= 3",
189-
})
190-
);
191-
})
192-
.then((recommended) => {
193-
console.log(
194-
"Recommended items with at least 3 processor cores: %j",
195-
recommended
196-
);
197132

198-
// Recommend only items that are more expensive then currently viewed item (up-sell)
199-
return client.send(
200-
new rqs.RecommendItemsToItem("computer-6", "user-42", 5, {
201-
filter: " 'price' > context_item[\"price\"] ",
202-
returnProperties: true,
203-
})
204-
);
205-
})
206-
.then((recommended) => {
207-
console.log("Recommended up-sell items: %j", recommended);
208-
209-
// Filters, boosters and other settings can be set also in the Admin UI (admin.recombee.com)
210-
// when scenario is specified
211-
return client.send(
212-
new rqs.RecommendItemsToItem("computer-6", "user-42", 5, {
213-
scenario: "product_detail",
214-
})
215-
);
216-
})
217-
.then((recommended) => {
218-
// Perform personalized full-text search with a user's search query (e.g. "computers")
219-
return client.send(
220-
new rqs.SearchItems("user-42", "computers", 5, {
221-
scenario: "search_top",
222-
})
223-
);
224-
})
225-
.then((matched) => {
226-
console.log("Matched items: %j", matched);
227-
})
228-
.catch((error) => {
229-
console.error(error);
230-
// Use fallback
231-
});
232-
```
133+
// Prepare requests for setting a catalog of computers
134+
var requests = Array.apply(0, Array(NUM)).map((_, i) => {
135+
return new rqs.SetItemValues(
136+
`computer-${i}`, // itemId
137+
// values:
138+
{
139+
price: 600 + 400 * Math.random(),
140+
"num-cores": Math.floor(Math.random() * 8) + 1,
141+
description: "Great computer",
142+
time: new Date().toISOString(),
143+
image: `http://examplesite.com/products/computer-${i}.jpg`,
144+
},
145+
// optional parameters:
146+
{
147+
cascadeCreate: true, // Use cascadeCreate for creating item
148+
// with given itemId, if it doesn't exist
149+
}
150+
);
151+
});
233152

234-
## Promises / callbacks
153+
// Send catalog to the recommender system
154+
await client.send(new rqs.Batch(requests));
235155

236-
The SDK supports both Promises and callbacks, so you can choose the way which suits your coding style and conventions of your project:
237156

238-
```javascript
239-
// Using Promises
240-
await client.send(new ListUsers());
241-
// or
242-
client
243-
.send(new ListUsers())
244-
.then((response) => {
245-
// handle response
246-
})
247-
.catch((error) => {
248-
// handle error
249-
});
157+
// Generate some random purchases of items by users
158+
const userIds = Array.apply(0, Array(NUM)).map((_, i) => {
159+
return `user-${i}`;
160+
});
161+
const itemIds = Array.apply(0, Array(NUM)).map((_, i) => {
162+
return `computer-${i}`;
163+
});
250164

251-
// Using callbacks
252-
client.send(new ListUsers(), (error, response) => {
253-
// handle result
165+
// Generate some random purchases of items by users
166+
const PROBABILITY_PURCHASED = 0.1;
167+
const purchases = [];
168+
userIds.forEach((userId) => {
169+
const purchased = itemIds.filter(
170+
() => Math.random() < PROBABILITY_PURCHASED
171+
);
172+
purchased.forEach((itemId) => {
173+
purchases.push(
174+
new rqs.AddPurchase(userId, itemId, { cascadeCreate: true })
175+
);
176+
});
254177
});
178+
// Send purchases to the recommender system
179+
await client.send(new rqs.Batch(purchases));
180+
181+
// Get 5 recommendations for user-42, who is currently viewing computer-6
182+
// Recommend only computers that have at least 3 cores
183+
const recommended = await client.send(
184+
new rqs.RecommendItemsToItem("computer-6", "user-42", 5, {
185+
filter: "'num-cores' >= 3",
186+
})
187+
);
188+
console.log(
189+
"Recommended items with at least 3 processor cores:",
190+
recommended
191+
);
192+
193+
// Recommend only items that are more expensive then currently viewed item (up-sell)
194+
const upsell = await client.send(
195+
new rqs.RecommendItemsToItem("computer-6", "user-42", 5, {
196+
filter: " 'price' > context_item[\"price\"] ",
197+
returnProperties: true,
198+
})
199+
);
200+
console.log("Recommended up-sell items:", upsell);
201+
202+
// Filters, boosters and other settings can be set also in the Admin UI (admin.recombee.com)
203+
// when scenario is specified
204+
const productDetail = await client.send(
205+
new rqs.RecommendItemsToItem("computer-6", "user-42", 5, {
206+
scenario: "product_detail",
207+
})
208+
);
209+
console.log("Recommended items for product detail scenario:", productDetail);
210+
211+
// Perform personalized full-text search with a user's search query (e.g. "computers")
212+
try {
213+
const searchResults = await client.send(
214+
new rqs.SearchItems("user-42", "computers", 5, {
215+
scenario: "search_top",
216+
})
217+
);
218+
console.log("Matched items:", searchResults);
219+
} catch (error) {
220+
console.error(error);
221+
// use fallback...
222+
}
255223
```
256224

257225
## Errors handling

lib/api-client.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class ApiClient {
4343
method: request.method,
4444
headers: {'Accept': 'application/json',
4545
'Content-Type': 'application/json',
46-
'User-Agent': 'recombee-node-api-client/6.1.0'},
46+
'User-Agent': 'recombee-node-api-client/6.2.0'},
4747
timeout: request.timeout,
4848
agent: this.options.agent
4949
};

lib/index.d.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,8 @@ declare module "recombee-api-client" {
168168
statusCode: number,
169169
message: string
170170
);
171+
172+
public readonly statusCode: number;
171173
}
172174

173175
/**
@@ -2606,7 +2608,43 @@ declare module "recombee-api-client" {
26062608
}
26072609

26082610
/**
2609-
* Composite Recommendation returns both a *source entity* (e.g., an Item or [Item Segment](https://docs.recombee.com/segmentations.html)) and a list of related recommendations in a single response.
2611+
* Returns Item segments that shall be shown to a user as next recommendations when the user e.g. scrolls the page down (*infinite scroll*) or goes to the next page.
2612+
* It accepts `recommId` of a base recommendation request (e.g., request from the first page) and the number of segments that shall be returned (`count`).
2613+
* The base request can be one of:
2614+
* - [Recommend Item Segments to Item](https://docs.recombee.com/api#recommend-item-segments-to-item)
2615+
* - [Recommend Item Segments to User](https://docs.recombee.com/api#recommend-item-segments-to-user)
2616+
* - [Recommend Item Segments to Item Segment](https://docs.recombee.com/api#recommend-item-segments-to-item-segment)
2617+
* - [Search Item Segments](https://docs.recombee.com/api#search-item-segments)
2618+
* All the other parameters are inherited from the base request.
2619+
* *Recommend next Item segments* can be called many times for a single `recommId` and each call returns different (previously not recommended) segments.
2620+
* The number of *Recommend next Item segments* calls performed so far is returned in the `numberNextRecommsCalls` field.
2621+
* *Recommend next Item segments* can be requested up to 30 minutes after the base request or a previous *Recommend next Item segments* call.
2622+
* For billing purposes, each call to *Recommend next Item segments* is counted as a separate recommendation request.
2623+
*/
2624+
export class RecommendNextItemSegments extends requests.Request {
2625+
/**
2626+
* @param recommId - ID of the base recommendation request for which next recommendations should be returned
2627+
* @param count - Number of item segments to be recommended
2628+
*/
2629+
constructor(
2630+
recommId: string,
2631+
count: number,
2632+
);
2633+
2634+
recommId: string;
2635+
count: number;
2636+
protected __response_type: RecommendationResponse;
2637+
2638+
bodyParameters(): {
2639+
count: number;
2640+
};
2641+
2642+
queryParameters(): {
2643+
};
2644+
}
2645+
2646+
/**
2647+
* Composite Recommendation returns both a *source entity* (e.g., an Item or [Item Segment](https://docs.recombee.com/segmentations)) and a list of related recommendations in a single response.
26102648
* It is ideal for use cases such as personalized homepage sections (*Articles from <category>*), *Because You Watched <movie>*, or *Artists Related to Your Favorite Artist <artist>*.
26112649
* See detailed **examples and configuration guidance** in the [Composite Scenarios documentation](https://docs.recombee.com/scenarios#composite-recommendations).
26122650
* **Structure**
@@ -2645,6 +2683,8 @@ declare module "recombee-api-client" {
26452683
logic?: string | object;
26462684
/** ID of the segment from `contextSegmentationId` for which the recommendations are to be generated. */
26472685
segmentId?: string;
2686+
/** Search query provided by the user. It is used for the full-text search. Only applicable if the *scenario* corresponds to a search scenario. */
2687+
searchQuery?: string;
26482688
/** If the entity for the source recommendation does not exist in the database, returns a list of non-personalized recommendations and creates the user in the database. This allows, for example, rotations in the following recommendations for that entity, as the entity will be already known to the system. */
26492689
cascadeCreate?: boolean;
26502690
/** Parameters applied for recommending the *Source* stage. The accepted parameters correspond with the recommendation sub-endpoint used to recommend the *Source*. */
@@ -2662,6 +2702,7 @@ declare module "recombee-api-client" {
26622702
userId?: string;
26632703
logic?: string | object;
26642704
segmentId?: string;
2705+
searchQuery?: string;
26652706
cascadeCreate?: boolean;
26662707
sourceSettings?: Record<string, unknown>;
26672708
resultSettings?: Record<string, unknown>;
@@ -2675,6 +2716,7 @@ declare module "recombee-api-client" {
26752716
userId?: string;
26762717
logic?: string | object;
26772718
segmentId?: string;
2719+
searchQuery?: string;
26782720
cascadeCreate?: boolean;
26792721
sourceSettings?: Record<string, unknown>;
26802722
resultSettings?: Record<string, unknown>;

lib/requests/composite-recommendation.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
const rqs = require("./request");
77

88
/**
9-
* Composite Recommendation returns both a *source entity* (e.g., an Item or [Item Segment](https://docs.recombee.com/segmentations.html)) and a list of related recommendations in a single response.
9+
* Composite Recommendation returns both a *source entity* (e.g., an Item or [Item Segment](https://docs.recombee.com/segmentations)) and a list of related recommendations in a single response.
1010
* It is ideal for use cases such as personalized homepage sections (*Articles from <category>*), *Because You Watched <movie>*, or *Artists Related to Your Favorite Artist <artist>*.
1111
* See detailed **examples and configuration guidance** in the [Composite Scenarios documentation](https://docs.recombee.com/scenarios#composite-recommendations).
1212
* **Structure**
@@ -50,6 +50,9 @@ class CompositeRecommendation extends rqs.Request {
5050
* - *segmentId*
5151
* - Type: string
5252
* - Description: ID of the segment from `contextSegmentationId` for which the recommendations are to be generated.
53+
* - *searchQuery*
54+
* - Type: string
55+
* - Description: Search query provided by the user. It is used for the full-text search. Only applicable if the *scenario* corresponds to a search scenario.
5356
* - *cascadeCreate*
5457
* - Type: boolean
5558
* - Description: If the entity for the source recommendation does not exist in the database, returns a list of non-personalized recommendations and creates the user in the database. This allows, for example, rotations in the following recommendations for that entity, as the entity will be already known to the system.
@@ -72,6 +75,7 @@ class CompositeRecommendation extends rqs.Request {
7275
this.userId = optional.userId;
7376
this.logic = optional.logic;
7477
this.segmentId = optional.segmentId;
78+
this.searchQuery = optional.searchQuery;
7579
this.cascadeCreate = optional.cascadeCreate;
7680
this.sourceSettings = optional.sourceSettings;
7781
this.resultSettings = optional.resultSettings;
@@ -99,6 +103,9 @@ class CompositeRecommendation extends rqs.Request {
99103
if(this.segmentId !== undefined)
100104
params.segmentId = this.segmentId;
101105

106+
if(this.searchQuery !== undefined)
107+
params.searchQuery = this.searchQuery;
108+
102109
if(this.cascadeCreate !== undefined)
103110
params.cascadeCreate = this.cascadeCreate;
104111

0 commit comments

Comments
 (0)