# Tutorial

> Source: https://docs.recombee.com/tutorial

> For the complete documentation index, see [llms.txt](/llms.txt).

**Table of contents**

* [Server Side - Interactions & Recommendations](#tutorial-interactions-recommendations)  
   * [Video Tutorial](#video-tutorial)  
   * [Source Codes](#source-codes)  
   * [Text Tutorial](#text-tutorial)  
         * [Sending Interactions](#sending-interactions)  
         * [Recommending Items to User](#recommending-items-to-user)  
         * [Recommending Items to Item](#recommending-items-to-item)  
         * [Recommending Users to Item](#recommending-users-to-item)
* [Server Side - Uploading Items Catalog](#tutorial-catalog)  
   * [Source Codes](#id2)  
   * [Text Tutorial](#id3)  
         * [Defining Item Properties](#defining-item-properties)  
         * [Setting Item Values](#setting-item-values)
* [ReQL Filtering](#tutorial-reql)  
   * [Source Codes](#id4)  
   * [Text Tutorial](#id5)
* [JavaScript Integration](#javascript-integration)

# Tutorial

[Interactions & recommendationsServer side](#tutorial-interactions-recommendations)[Uploading items catalogServer side](#tutorial-catalog)[ReQL filteringRestrictions on the recommended items](#tutorial-reql)

## Server Side - Interactions & Recommendations

The first part of the tutorial covers sending interactions to the system and getting recommendations based on them.

### Video Tutorial

### Source Codes

[Python](/files/tutorial/1/tutorial1.py)[Java](/files/tutorial/1/tutorial1.java)[Ruby](/files/tutorial/1/tutorial1.rb)[PHP](/files/tutorial/1/tutorial1.php)[C#](/files/tutorial/1/tutorial1.cs)[Node.js](/files/tutorial/1/tutorial1.js)

### Text Tutorial

#### Sending Interactions

Suppose that I run a website which offers tickets to cultural events and I already have some collected data from the past - namely views of the events and purchases of the tickets by the users. For simplicity, I have the interactions in two .json files with the same structure.

JSON

```
purchases.json:

[
	{"user_id": "user-50", "item_id": "event-276", "timestamp": "2016-04-20T12:50:42+02:00"},
	{"user_id": "user-389", "item_id": "event-73", "timestamp": "2014-07-20T02:49:45+02:00"},
	{"user_id": "user-204", "item_id": "event-116", "timestamp": "2015-04-22T13:32:32+02:00"},
	...
]

detail_views.json:

[
	{"user_id": "user-7", "item_id": "event-12 ", "timestamp": "2016-04-20T13:25:55+02:00"},
	{"user_id": "user-384", "item_id": "event-73", "timestamp": "2016-04-20T13:07:10+02:00"},
	{"user_id": "user-12", "item_id": "event-113", "timestamp": "2016-04-20T12:50:42+02:00"},
	...
]
...
```

We will use [SDK](/api_clients) for communication with Recombee, as it greatly simplifies the process of the integration. I need the Recombee client, so we will import it from the already installed package. We will also import all the classes for the requests in order to spare some typing. Then, I create the instance of the client. It is initialized with the ID of my database and the secret token, which I both gained when I [created the instant account](https://admin.recombee.com/sign-up), so we will just copy and paste them from the UI at[admin.recombee.com](https://admin.recombee.com).

```python
from recombee_api_client.api_client import RecombeeClient
from recombee_api_client.api_requests import *

client = RecombeeClient('events-example', 'PbBaEVxx8ZOj0x3BhGtqfHyi8qQ8rm8rE1JBnSPoCnHwetzO3gjHer96YVAIa14G')
```

```java
RecombeeClient client = new RecombeeClient("events-example", "PbBaEVxx8ZOj0x3BhGtqfHyi8qQ8rm8rE1JBnSPoCnHwetzO3gjHer96YVAIa14G");
```

```ruby
require 'recombee_api_client'
include RecombeeApiClient

client = RecombeeClient.new('events-example', 'PbBaEVxx8ZOj0x3BhGtqfHyi8qQ8rm8rE1JBnSPoCnHwetzO3gjHer96YVAIa14G')
```

```php
use Recombee\RecommApi\Client;
use Recombee\RecommApi\Requests as Reqs;
use Recombee\RecommApi\Exceptions as Ex;

$client = new Client('events-example', 'PbBaEVxx8ZOj0x3BhGtqfHyi8qQ8rm8rE1JBnSPoCnHwetzO3gjHer96YVAIa14G');
```

```csharp
using Recombee.ApiClient;
using Recombee.ApiClient.ApiRequests;
using Recombee.ApiClient.Bindings;

var client = new RecombeeClient("events-example", "PbBaEVxx8ZOj0x3BhGtqfHyi8qQ8rm8rE1JBnSPoCnHwetzO3gjHer96YVAIa14G");
```

```js
var recombee = require('recombee-api-client');
var rqs = recombee.requests;

var client = new recombee.ApiClient('events-example', 'PbBaEVxx8ZOj0x3BhGtqfHyi8qQ8rm8rE1JBnSPoCnHwetzO3gjHer96YVAIa14G');
```

Now, I want to upload some interactions to the recommender system. We will start by reading and the purchases from the json file and creating an [AddPurchase](/api#request-add-purchase)request object for each purchase in the file. It takes two mandatory parameters - the `userId` and the `itemId`. We will set the optional parameter `timestamp` to `time`, because the default value is the current time, but I want a particular time from past. And we will also set `cascadeCreate` to `true` in order to create in the system the yet non existing items and users.

```python
from recombee_api_client.api_client import RecombeeClient
from recombee_api_client.api_requests import *
import json

client = RecombeeClient('events-example', 'PbBaEVxx8ZOj0x3BhGtqfHyi8qQ8rm8rE1JBnSPoCnHwetzO3gjHer96YVAIa14G')

requests = []

with open('purchases.json') as f:
	interactions = json.loads(f.read())
	for interaction in interactions:
		r = AddPurchase(interaction['user_id'],
						interaction['item_id'],
						timestamp=interaction['timestamp'],
						cascade_create=True)
```

```java
RecombeeClient client = new RecombeeClient("events-example", "PbBaEVxx8ZOj0x3BhGtqfHyi8qQ8rm8rE1JBnSPoCnHwetzO3gjHer96YVAIa14G");

JSONParser parser = new JSONParser();
try {
	JSONArray a = (JSONArray) parser.parse(new FileReader("purchases.json"));
	for (Object o : a) {
		JSONObject interaction = (JSONObject) o;
		Date time =  new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX").parse((String)interaction.get("timestamp"));
		Request r = new AddPurchase((String) interaction.get("userId"),
									(String) interaction.get("itemId"))
						.setTimestamp(time).setCascadeCreate(true);
	}
} catch (org.json.simple.parser.ParseException e) {
	e.printStackTrace();
} catch (IOException e) {
	e.printStackTrace();
} catch (ParseException e) {
	e.printStackTrace();
}
```

```ruby
require 'json'

client = RecombeeClient.new('events-example', 'PbBaEVxx8ZOj0x3BhGtqfHyi8qQ8rm8rE1JBnSPoCnHwetzO3gjHer96YVAIa14G')

file = File.read('purchases.json')
JSON.parse(file).each do |interaction|
	user_id = interaction['user_id']
	item_id = interaction['item_id']
	time = interaction['timestamp']
	r = AddPurchase.new(user_id, item_id, 'timestamp' => time, 'cascadeCreate' => true)
end
```

```php
$client = new Client('events-example', 'PbBaEVxx8ZOj0x3BhGtqfHyi8qQ8rm8rE1JBnSPoCnHwetzO3gjHer96YVAIa14G');

$str = file_get_contents('purchases.json');

foreach(json_decode($str, true) as $interacion) {
	$user_id = $interacion['user_id'];
	$item_id = $interacion['item_id'];
	$time = $interacion['timestamp'];

	$r = new Reqs\AddPurchase($user_id, $item_id,
					['timestamp' => $time, 'cascadeCreate' => true]);
}
```

```csharp
var client = new RecombeeClient("events-example", "PbBaEVxx8ZOj0x3BhGtqfHyi8qQ8rm8rE1JBnSPoCnHwetzO3gjHer96YVAIa14G");

string[] allLines = File.ReadAllLines(@"purchases.csv");

var parsed = from line in allLines
	let row = line.Split(',')
	select new
	{
		UserId = row[0],
		ItemId = row[1],
		Timestamp = DateTime.Parse(row[2], null, System.Globalization.DateTimeStyles.RoundtripKind)
	};
var purchases = parsed.Select(x => new AddPurchase(x.UserId, x.ItemId, timestamp: x.Timestamp, cascadeCreate: true));
```

```js
var interactions = require('./purchases.json');

var requests = interactions.map((interaction) => {
	var userId = interaction['user_id'];
	var itemId = interaction['item_id'];
	var time = interaction['timestamp'];

	return new rqs.AddPurchase(userId, itemId, {timestamp: time, cascadeCreate: true});
});
```

I could send the purchases one by one, using the send method of the client.

```python
client.send(r)
```

```java
client.send(r);
```

```ruby
client.send(r)
```

```php
$client->send($r);
```

```csharp
foreach(AddPurchase purchase in purchases) client.Send(purchase);
```

```js
purchases.forEach((purchase) => client.send(purchase));
```

Sending individual requests is very beneficial when you have the recommender already deployed in production as the system can immediately modify its recommendations using the just received interaction.

But uploading larger data from the past with individual requests would be quite slow, so for sending the list of purchases we will use the [Batch](/api#request-batch) request, which can encapsulate many requests into a single request.

```python
requests = []

with open('purchases.json') as f:
	interactions = json.loads(f.read())
	for interaction in interactions:
		r = AddPurchase(interaction['user_id'],
						interaction['item_id'],
						timestamp=interaction['timestamp'],
						cascade_create=True)
		requests.append(r)

br = Batch(requests)
client.send(br)
```

```java
ArrayList<Request> interactions = new ArrayList<>();

try {

		...

		Request r = new AddPurchase((String) interaction.get("userId"),
					(String) interaction.get("itemId"))
						.setTimestamp(time).setCascadeCreate(true);
		interactions.add(r);
		...
}
...

client.send(new Batch(interactions));
```

```ruby
interactions = []

file = File.read('purchases.json')
JSON.parse(file).each do |interaction|
	user_id = interaction['user_id']
	item_id = interaction['item_id']
	time = interaction['timestamp']
	r = AddPurchase.new(user_id, item_id, 'timestamp' => time, 'cascadeCreate' => true)
	interactions.push(r)
end

br = Batch.new(interactions)
client.send(br)
```

```php
$requests = array();
$str = file_get_contents('purchases.json');

foreach(json_decode($str, true) as $interacion) {
	$user_id = $interacion['user_id'];
	$item_id = $interacion['item_id'];
	$time = $interacion['timestamp'];

	$r = new Reqs\AddPurchase($user_id, $item_id,
					['timestamp' => $time, 'cascadeCreate' => true]);
	array_push($requests, $r);
}

$br = new Reqs\Batch($requests);
$client->send($br);
```

```csharp
client.Send(new Batch(purchases));
```

```js
client.send(new rqs.Batch(requests), (err, responses) => {
	console.log(responses);
});
```

Now let's run the script and see the result in the Admin UI.

You should see the uploaded items in the _Catalog listing_. You can also check interactions of an item by clicking its id.

[![Items in the catalog listing](/img/tutorial/1/catalog1.png)](/img/tutorial/1/catalog1.png)

Now I'll change the code to send the detail views by changing the name of file with interactions (_purchases.csv_ to _detail\_views.csv_ ) and the name of the class from _AddPurchase_ to[AddDetailView](/api#request-add-detail-view).

```python
r = AddDetailView(interaction['user_id'],
				interaction['item_id'],
				timestamp=interaction['timestamp'],
				cascade_create=True)
```

```java
Request r = new AddDetailView((String) interaction.get("userId"),
				(String) interaction.get("itemId"))
		.setTimestamp(time).setCascadeCreate(true);
```

```ruby
r = AddDetailView.new(user_id, item_id, 'timestamp' => time, 'cascadeCreate' => true)
```

```php
$r = new Reqs\AddDetailView($user_id, $item_id,
	['timestamp' => $time, 'cascadeCreate' => true]);
```

```csharp
var detailViews = parsed.Select(x => new AddDetailView(x.UserId, x.ItemId, timestamp: x.Timestamp, cascadeCreate: true));
```

```js
return new rqs.AddDetailView(userId, itemId, {timestamp: time, cascadeCreate: true});
```

After running the changed code, detail views should appear in the interface.

[![Interactions in the catalog listing](/img/tutorial/1/catalog2.png)](/img/tutorial/1/catalog2.png)

You can also see the visualization in the _KPI console_, which is updated up to every few minutes.

[![Interactions in the KPI](/img/tutorial/1/kpi1.png)](/img/tutorial/1/kpi1.png)

#### Recommending Items to User

Now it's time to get some recommendations based on the uploaded interactions.

Suppose that _user-27_ just came to my website. I want to immediately show him 5 events that he will most likely favor. I'll use the[RecommendItemsToUser](/api#request-recommend-items-to-user) for this task.

```python
recommended = client.send(RecommendItemsToUser('user-27', 5))
print(recommended)
```

```java
RecommendationResponse recommended = client.send(new RecommendItemsToUser("user-27", 5));
for(Recommendation rec: recommended) System.out.println(rec.getId());
```

```ruby
recommended = client.send(RecommendItemsToUser.new('user-27', 5))
puts(recommended)
```

```php
$recommended = $client->send(new Reqs\RecommendItemsToUser('user-27', 5));
echo 'User based recommendation for "user-27": ' . print_r($recommended, true) . "\n";
```

```csharp
Console.WriteLine("Recommendations for \"user-27\":");
RecommendationResponse recommended = client.Send(new RecommendItemsToUser("user-27", 5));
foreach(Recommendation rec in recommended.Recomms) Console.WriteLine(rec.Id);
```

```js
client.send(new rqs.RecommendItemsToUser('user-27', 5), (err, recommendations) => {
	console.log(recommendations);
});
```

An object with recommended items in field `recomms` is returned. For example:

JSON

```
{
"recommId": "c386301b-8f9d-4841-9b83-9e7f1f6bb463",
"recomms": [
		{
			"id": "event-5"
		},
		{
			"id": "event-17"
		},
		{
			"id": "event-32"
		},
		{
			"id": "event-19"
		},
		{
			"id": "event-92"
		}
	]
}
```

Now I can show these recommended events to _user-27_ at my homepage.

#### Recommending Items to Item

Let's say that the user likes the recommended events, and clicked one of them, namely _event-32_, to see the details. The page of the event contains box with related events, which are obtained by requesting the[RecommendItemsToItem](/api#request-recommend-items-to-item). The id of the user is passed in the request as well, to make the related items personalized for _user-27_.

```python
recommended = client.send(RecommendItemsToItem('event-32', 'user-27', 5))
print(recommended)
```

```java
recommended = client.send(new RecommendItemsToItem("event-32", "user-27", 5));
for(Recommendation rec: recommended) System.out.println(rec.getId());
```

```ruby
recommended = client.send(RecommendItemsToItem.new('event-32', 'user-27', 5))
puts(recommended)
```

```php
$recommended = $client->send(new Reqs\RecommendItemsToItem('event-32', 'user-27', 5));
echo 'Related items to "event-32" for "user-27": ' . print_r($recommended, true) . "\n";
```

```csharp
Console.WriteLine("Items related to \"event-32\" for \"user-27\":");
recommended = client.Send(new RecommendItemsToItem("event-32", "user-27", 5));
foreach(Recommendation rec in recommended.Recomms) Console.WriteLine(rec.Id);
```

```js
client.send(new rqs.RecommendItemsToItem('event-32', 'user-27', 5),
	(err, recommendations) => {
		console.log(recommendations);
});
```

Returning:

JSON

```
{
	"recommId": "a7add465-d29d-4a1b-9e38-4923378ec0b5",
	"recomms": [
		{
		"id": "event-59"
		},
		{
		"id": "event-19"
		},
		{
		"id": "event-17"
		},
		{
		"id": "event-38"
		},
		{
		"id": "event-3"
		}
	]
}

```

#### Recommending Users to Item

Other two supported recommendation endpoints,[RecommendUsersToItem](/api#request-recommend-users-to-item) and[RecommendUsersToUser](/api#request-recommend-users-to-user) return users instead of items. For example if I want to know which users would be most likely interested in attending_event-42_, I'll call the[RecommendUsersToItem](/api#request-recommend-users-to-item).

```python
recommended = client.send(RecommendUsersToItem('event-42', 5))
print(recommended)
```

```java
recommended = client.send(new RecommendUsersToItem("event-42",  5));
for(Recommendation rec: recommended) System.out.println(rec.getId());
```

```ruby
recommended = client.send(RecommendUsersToItem.new('event-42', 5))
puts(recommended)
```

```php
$recommended = $client->send(new Reqs\RecommendUsersToItem('event-42', 5));
echo 'Users who should be interested in "event-42": ' . print_r($recommended, true) . "\n";
```

```csharp
Console.WriteLine("Users who should be interested in to \"event-42\":");
recommended = client.Send(new RecommendUsersToItem("event-42", 5));
foreach(Recommendation rec in recommended.Recomms) Console.WriteLine(rec.Id);
```

```js
client.send(new rqs.RecommendUsersToItem('event-42', 5), (err, recommendations) => {
	console.log(recommendations);
});
```

Returning:

JSON

```
{
	"recommId": "a7add465-d29d-4a1b-9e38-4923378ec0b5",
	"recomms": [
		{
		"id": "user-47"
		},
		{
		"id": "user-95"
		},
		{
		"id": "user-10"
		},
		{
		"id": "user-50"
		},
		{
		"id": "user-54"
		}
	]
}
```

As you can see sending interactions and getting recommendations is very easy, and took just few lines of code. In the next tutorial I'll show you how to send properties of the items to Recombee and how to use these properties in filtering and boosting according to your business rules.

## Server Side - Uploading Items Catalog

### Source Codes

[Python](/files/tutorial/2-catalog/catalog.py)[Java](/files/tutorial/2-catalog/catalog.java)[Ruby](/files/tutorial/2-catalog/catalog.rb)[PHP](/files/tutorial/2-catalog/catalog.php)[C#](/files/tutorial/2-catalog/catalog.cs)[Node.js](/files/tutorial/2-catalog/catalog.js)

### Text Tutorial

Items in the Recombee system can have many properties such as title, description, categories, price and many other. There are two possibilities how to get your items catalog into Recombee - one is setting a [catalog feed](/catalog_feeds)and the other is uploading the data from your server. This tutorial covers the second option.

Let's continue with the sample company that sell tickets to cultural events from previous part of the tutorial.

The events have following properties:

| id                   | name String                         | city String | venue String   | genres Set                            | date Timestamp   | price Double |
| -------------------- | ----------------------------------- | ----------- | -------------- | ------------------------------------- | ---------------- | ------------ |
| nyphilharmonic181210 | New York Philharmonic: Rachmaninoff | New York    | Lincoln Center | \["classical music"\]                 | 2018-12-10 19:00 | 94.0         |
| beachboys190321      | Beach Boys                          | New Jersey  | Arts Center    | \["rock music", "rock’n’roll music"\] | 2019-03-21 20:00 | 69.0         |
| snoopdogg191102      | Snoop Dogg                          | New York    | Terminal 5     | \["hip-hop", "rap"\]                  | 2019-02-11 19:00 | 42.0         |

I have these data in a json object, where the keys are IDs of the items and values contain an object with item properties.

JSON

```
{
	"nyphilharmonic181210": {
		"title": "New York Philharmonic: Rachmaninoff",
		"city": "New York",
		"venue": "Lincoln Center",
		"date":  "2017-12-10",
		"genres": ["classical music"],
		"price": 94.0
	}
	"beachboys190321": { ... },
	....
}
```

#### Defining Item Properties

Now, let's see how we can send these data to Recombee, and how they are used in recommendations. First, I need to define the properties. They can be thought as columns in relational database. In my case the properties are _title_, _city_, _venue_, _date_, _genres_ and _price_.

I add them using the [Admin UI](/admin_ui):

[![Add item property in Admin UI](/img/gui/add_property2.png)](/img/gui/add_property2.png)

Alternatively, I can add them by calling the API:

```python
client.send(AddItemProperty('title', 'string'))
client.send(AddItemProperty('city', 'string'))
client.send(AddItemProperty('venue', 'string'))
client.send(AddItemProperty('date', 'timestamp'))
client.send(AddItemProperty('genres', 'set'))
client.send(AddItemProperty('price', 'double'))
```

```java
client.send(new AddItemProperty("title", "string"));
client.send(new AddItemProperty("city", "string"));
client.send(new AddItemProperty("venue", "string"));
client.send(new AddItemProperty("date", "timestamp"));
client.send(new AddItemProperty("genres", "set"));
client.send(new AddItemProperty("price", "double"));
```

```ruby
client.send(AddItemProperty.new('title', 'string'))
client.send(AddItemProperty.new('city', 'string'))
client.send(AddItemProperty.new('venue', 'string'))
client.send(AddItemProperty.new('date', 'timestamp'))
client.send(AddItemProperty.new('genres', 'set'))
client.send(AddItemProperty.new('price', 'double'))
```

```php
$client->send(new Reqs\AddItemProperty('title', 'string'));
$client->send(new Reqs\AddItemProperty('city', 'string'));
$client->send(new Reqs\AddItemProperty('venue', 'string'));
$client->send(new Reqs\AddItemProperty('date', 'timestamp'));
$client->send(new Reqs\AddItemProperty('genres', 'set'));
$client->send(new Reqs\AddItemProperty('price', 'double'));
```

```csharp
client.Send(new AddItemProperty("title", "string"));
client.Send(new AddItemProperty("city", "string"));
client.Send(new AddItemProperty("venue", "string"));
client.Send(new AddItemProperty("date", "timestamp"));
client.Send(new AddItemProperty("genres", "set"));
client.Send(new AddItemProperty("price", "double"));
```

```js
client.send(
new rqs.Batch([
	new rqs.AddItemProperty('title', 'string'),
	new rqs.AddItemProperty('city', 'string'),
	new rqs.AddItemProperty('venue', 'string'),
	new rqs.AddItemProperty('date', 'timestamp'),
	new rqs.AddItemProperty('genres', 'set'),
	new rqs.AddItemProperty('price', 'double')
	])
);
```

The properties are now in the place. If there were already some items in the database, they would have all the values set to `NULL`.

#### Setting Item Values

I start by reading the file, parsing the json and iterating over the item IDs and corresponding property values. I will send them to Recombee with [SetItemValues](/api#request-set-item-values) requests.[SetItemValues](/api#request-set-item-values) takes the `itemId`, the property values of the items, and the optional parameter `cascadeCreate` which I set to `true` in order to create items in the system if they don't exist yet. I use the [Batch](/api#request-batch) to speed up the uploading.

```python
requests = []
with open('items.json') as f:
	data = json.loads(f.read())
	for item_id,values in data.items():
		r = SetItemValues(item_id,
						values,
						cascade_create=True)
		requests.append(r)

res = client.send(Batch(requests))
```

```java
ArrayList<Request> requests = new ArrayList<>();

try {
	// HashMap<itemId, HashMap<name of property, value of property>>
	HashMap<String, HashMap<String, Object>> items =
			new ObjectMapper().readValue(new FileReader("items.json"), HashMap.class);
	for (Map.Entry<String, HashMap<String, Object>> entry : items.entrySet()) {
		String itemId = entry.getKey();
		HashMap<String, Object> values = entry.getValue();
		requests.add(new SetItemValues(itemId, values).setCascadeCreate(true));
	}
} catch (IOException e) {
	e.printStackTrace();
}
BatchResponse[] res = client.send(new Batch(requests));
```

```ruby
file = File.read('items.json')
requests = JSON.parse(file).map do |item_id, values|
SetItemValues.new(item_id, values, :cascade_create => true)
end

br = Batch.new(requests)
puts client.send(br)
```

```php
$requests = array();
$str = file_get_contents('items.json');

foreach(json_decode($str, true) as $item_id => $values) {
	$r = new Reqs\SetItemValues($item_id, $values, ['cascadeCreate' => true]);
	array_push($requests, $r);
}

$br = new Reqs\Batch($requests);
$res = $client->send($br);
```

```csharp
using (StreamReader r = new StreamReader("items.json"))
{
	string json = r.ReadToEnd();
	Dictionary<string, Dictionary<string, Object>> items =
			JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, Object>>>(json);

	var requests = new List<SetItemValues>();

	foreach(KeyValuePair<string, Dictionary<string, Object>> entry in items)
	{
		var itemId = entry.Key;
		var values = entry.Value; // Dictionary with names of properties as keys
								// and values of the properties as values
		requests.Add(new SetItemValues(itemId, values, cascadeCreate: true));
	}
	client.Send(new Batch(requests));
}
```

```js
var catalog = require('./items.json');
var requests = [];

for (var itemId in catalog) {
	var values = catalog[itemId];
	requests.push(new rqs.SetItemValues(itemId, values, {cascadeCreate: true}));
}
client.send(new rqs.Batch(requests));
```

I can check the uploaded items in the Admin UI.

Other properties that are usually very useful, but were not included in this example are **text descriptions**, which are processed by text mining algorithms, and **links to images** (property types **Image** and**Image List**) that can be used for finding visually similar items using artificial neural networks and other images processing models.

## ReQL Filtering

### Source Codes

[Python](/files/tutorial/3-reql/reql.py)[Java](/files/tutorial/3-reql/reql.java)[Ruby](/files/tutorial/3-reql/reql.rb)[PHP](/files/tutorial/3-reql/reql.php)[C#](/files/tutorial/3-reql/reql.cs)[Node.js](/files/tutorial/3-reql/reql.js)

### Text Tutorial

[ReQL](/reql) filtering allows you to put some restrictions on the recommended items.

Tip

You can use ReQL also for specifying the [Business Rules](/reql#business-rules) in the Admin UI

Let's assume I have the catalog of cultural events from previous part of the tutorial uploaded in my database. It contains following item properties: _title_, _city_, _venue_, _genres_, _date_ and _price_.

I want to get some related items to item_nyphilharmonic181210_, which is concert by the New York Philharmonic. These recommendations will be shown to_user-27_. I use [RecommendItemsToItem](/api#request-recommend-items-to-item) for this purpose:

```python
recommended = client.send(RecommendItemsToItem('nyphilharmonic181210', 'user-27', 3, cascade_create=True))
print(recommended)
```

```js
var callback  = function (err, res) {
	if(err) {
		console.log(err);
		return;
	}
	console.log(res.recomms);
}

client.send(
	new recombee.RecommendItemsToItem('nyphilharmonic181210', 'user-27', 3, {cascadeCreate: true}),
	callback);
```

```java
RecommendationResponse recommended = client.send(new RecommendItemsToItem("nyphilharmonic181210", "user-27", 3)
						.setCascadeCreate(true));
for(Recommendation rec: recommended) System.out.println(rec.getId());
```

```ruby
require 'pp'
recommended = client.send(RecommendItemsToItem.new('nyphilharmonic181210', 'user-27', 3, :cascade_create => true))
pp recommended
```

```php
$recommended = $client->send(new Reqs\RecommendItemsToItem('nyphilharmonic181210', 'user-27', 3,
							['cascadeCreate' => true]));
echo print_r($recommended, true) . "\n";
```

```csharp
RecommendationResponse recommended = client.Send(new RecommendItemsToItem("nyphilharmonic181210", "user-27", 3,
												cascadeCreate: true));
foreach(Recommendation rec in recommended.Recomms) Console.WriteLine(rec.Id);
```

```js
var callback  = function (err, res) {
	if(err) {
		console.log(err);
		return;
	}
	console.log(res.recomms);
}

client.send(
	new rqs.RecommendItemsToItem('nyphilharmonic181210', 'user-27', 3, {cascadeCreate: true}),
	callback);
```

I got some IDs, but in order to evaluate the quality of the recommendations, I need to set optional parameter `returnProperties` to`true`.

```python
recommended = client.send(RecommendItemsToItem('nyphilharmonic181210', 'user-27', 3, return_properties=True))
print(json.dumps(recommended, indent=4))
```

```js
client.send(
	new recombee.RecommendItemsToItem('nyphilharmonic181210', 'user-27', 3, {returnProperties: true})),
	callback);
```

```java
recommended = client.send(new RecommendItemsToItem("nyphilharmonic181210", "user-27", 3)
							.setReturnProperties(true));
printRecommendedItems(recommended);

// ...

private static void printRecommendedItems(RecommendationResponse recommended)
{
	for(Recommendation rec: recommended)
	{
		System.out.format("%s:\n", rec.getId());
		for (Map.Entry<String, Object> entry : rec.getValues().entrySet())
		{
			String propertyName = entry.getKey();
			Object propertyValue = entry.getValue();
			System.out.format("  %s: %s\n", propertyName, propertyValue);
		}
	}
	System.out.println("\n");
}
```

```ruby
recommended = client.send(RecommendItemsToItem.new('nyphilharmonic181210', 'user-27', 3, :return_properties => true))
```

```php
$recommended = $client->send(new Reqs\RecommendItemsToItem('nyphilharmonic181210', 'user-27', 3,
							['returnProperties' => true]));
```

```csharp
recommended = client.Send(new RecommendItemsToItem("nyphilharmonic181210", "user-27", 3,
								returnProperties: true));
WriteRecommendedItemsToConsole(recommended);

// ..

private static void WriteRecommendedItemsToConsole(RecommendationResponse recommended)
{
	foreach(Recommendation rec in recommended.Recomms)
	{
		Console.WriteLine("{0}:", rec.Id);
		foreach (KeyValuePair<string, Object> entry in rec.Values)
		{
			var propertyName = entry.Key;
			var propertyValue = entry.Value;
			Console.WriteLine("  {0}: {1}", propertyName, propertyValue);
		}
	}
	Console.WriteLine("\n\n");
}
```

```js
client.send(
	new rqs.RecommendItemsToItem('nyphilharmonic181210', 'user-27', 3, {returnProperties: true})),
	callback);
```

Now I get also the property values of recommended items. As you can see, the recommended items look pretty related to the concert of the philharmonic.

JSON

```
{
	"recomms": [
		{
			"values": {
				"city": "New York",
				"price": 56.0,
				"venue": "Lincoln Center",
				"title": "Ravel's Daphnis et Chloe and Dvorak",
				"genres": [
					"classical music"
				],
				"date": 1523318400.0
			},
			"id": "ravelsdaphnis180410"
		},
		{
			"values": {
				"city": "Los Angeles",
				"price": 62.0,
				"venue": "Walt Disney Concert Hall",
				"title": "Los Angeles Philharmonic: Rachmaninoff",
				"genres": [
					"classical music"
				],
				"date": 1558742400.0
			},
			"id": "laphilharmonic190525"
		},
		{
			"values": {
				"city": "San Francisco",
				"price": 58.0,
				"venue": "Davies Symphony Hall",
				"title": "Czech Philharmonic: Dvorak",
				"genres": [
					"classical music"
				],
				"date": 1573430400.0
			},
			"id": "czechphilharmonic191111"
		}
	],
	"recommId": "295b2aa5-8375-48bc-82dd-e1555ee0b5ec"
}
```

But if the user is interested in the _New York Philharmonic_ concert which takes place in _New York City_, there is only slight chance that the user will attend concert of _Los Angeles Philharmonic_ in LA.

So I want to put restriction on the recommendations to return only events that take place in _New York_. This can be easily done by setting filter `'city' == "New York"`.

```python
recommended = client.send(RecommendItemsToItem('nyphilharmonic181210', 'user-27', 3,
			return_properties=True,
			filter="'city' == \"New York\" "))
```

```js
client.send(
	new recombee.RecommendItemsToItem('nyphilharmonic181210', 'user-27', 3, {
			returnProperties: true,
			filter: "'city' == \"New York\""
		}),
	callback);
```

```java
recommended = client.send(new RecommendItemsToItem("nyphilharmonic181210", "user-27", 3)
			.setReturnProperties(true)
			.setFilter("'city' == \"New York\""));
```

```ruby
recommended = client.send(RecommendItemsToItem.new('nyphilharmonic181210', 'user-27', 3,
			:return_properties => true,
			:filter => "'city' == \"New York\""))
```

```php
$recommended = $client->send(new Reqs\RecommendItemsToItem('nyphilharmonic181210', 'user-27', 3,
			['returnProperties' => true,
			'filter' => "'city' == \"New York\""]));
```

```csharp
recommended = client.Send(new RecommendItemsToItem("nyphilharmonic181210", "user-27", 3,
			returnProperties: true,
			filter: "'city' == \"New York\""));
```

```js
client.send(
	new rqs.RecommendItemsToItem('nyphilharmonic181210', 'user-27', 3, {
			returnProperties: true,
			filter: "'city' == \"New York\""
		}),
	callback);
```

As you can see I use single quotes for accessing values of the properties and double quotes, which I had to escape, for creating the_New York_ string.

Now all the events I received take place in New York:

JSON

```
{
    "recomms": [
        {
            "values": {
                "city": "New York",
                "genres": [
                    "classical music"
                ],
                "venue": "Lincoln Center",
                "price": 56.0,
                "date": 1523318400.0,
                "title": "Ravel's Daphnis et Chloe and Dvorak"
            },
            "id": "ravelsdaphnis180410"
        },
        {
            "values": {
                "city": "New York",
                "genres": [
                    "classical music"
                ],
                "venue": "Carnegie Hall",
                "price": 72.0,
                "date": 1558656000.0,
                "title": "Staatskapelle Dresden in NY: Schubert"
            },
            "id": "staatskapelle190524"
        },
        {
            "values": {
                "city": "New York",
                "genres": [
                    "classical music"
                ],
                "venue": "Brooklyn Museum",
                "price": 63.0,
                "date": 1552780800.0,
                "title": "Brooklyn Symphony Orchestra: Borodin, Shostakovich"
            },
            "id": "brooklynsymphony190317"
        }
    ],
    "recommId": "8ef292ca-7f4c-4be0-8f63-fdb9f4a9fee0"
}
```

The problem is that some events may have already passed, and therefore should not be recommended. To filter these events out I compare the date property with current time, which obtain by calling ReQL function[now()](/reql_functions#reql-func-now).

The filter therefore becomes `'city' == "New York" and 'date' >= now()`:

```python
recommended = client.send(RecommendItemsToItem('nyphilharmonic181210', 'user-27', 3,
						return_properties=True,
						filter="'city' == \"New York\" AND 'date' >= now()"))
```

```js
client.send(
	new recombee.RecommendItemsToItem('nyphilharmonic181210', 'user-27', 3, {
			returnProperties: true,
			filter: "'city' == \"New York\" AND 'date' >= now()"
		}),
	callback);
```

```java
recommended = client.send(new RecommendItemsToItem("nyphilharmonic181210", "user-27", 3)
			.setReturnProperties(true)
			.setFilter("'city' == \"New York\" AND 'date' >= now()"));
```

```ruby
recommended = client.send(RecommendItemsToItem.new('nyphilharmonic181210', 'user-27', 3,
			:return_properties => true,
			:filter => "'city' == \"New York\" AND 'date' >= now()"))
```

```php
$recommended = $client->send(new Reqs\RecommendItemsToItem('nyphilharmonic181210', 'user-27', 3,
			['returnProperties' => true,
			'filter' => "'city' == \"New York\" AND 'date' >= now()"]));
```

```csharp
recommended = client.Send(new RecommendItemsToItem("nyphilharmonic181210", "user-27", 3,
			returnProperties: true,
			filter: "'city' == \"New York\" AND 'date' >= now()"));
```

```js
client.send(
	rqs.RecommendItemsToItem('nyphilharmonic181210', 'user-27', 3, {
			returnProperties: true,
			filter: "'city' == \"New York\" AND 'date' >= now()"
		}),
	callback);
```

Now all the events are upcoming. Another restriction can be restriction on genres - let's suppose the user chose to view only items that have_ballet_ as one of their _genres_. It is done by appending`"ballet" in 'genres'` to the filter:

```python
recommended = client.send(RecommendItemsToItem('nyphilharmonic181210', 'user-27', 3,
						return_properties=True,
						filter="'city' == \"New York\" AND 'date' >= now() AND \"ballet\" in 'genres'"))
```

```js
client.send(
	new recombee.RecommendItemsToItem('nyphilharmonic181210', 'user-27', 3, {
		returnProperties: true,
		filter: "'city' == \"New York\" AND 'date' >= now() AND \"ballet\" in 'genres'"
	}),
	callback);
```

```java
recommended = client.send(new RecommendItemsToItem("nyphilharmonic181210", "user-27", 3)
				.setReturnProperties(true)
				.setFilter("'city' == \"New York\" AND 'date' >= now() AND \"ballet\" in 'genres'"));
```

```ruby
recommended = client.send(RecommendItemsToItem.new('nyphilharmonic181210', 'user-27', 3,
					:return_properties => true,
					:filter => "'city' == \"New York\" AND 'date' >= now() AND \"ballet\" in 'genres'"))
```

```php
$recommended = $client->send(new Reqs\RecommendItemsToItem('nyphilharmonic181210', 'user-27', 3,
					['returnProperties' => true,
					'filter' => "'city' == \"New York\" AND 'date' >= now() AND \"ballet\" in 'genres'"]));
```

```csharp
recommended = client.Send(new RecommendItemsToItem("nyphilharmonic181210", "user-27", 3,
					returnProperties: true,
					filter: "'city' == \"New York\" AND 'date' >= now() AND \"ballet\" in 'genres'"));
```

```js
client.send(
	new rqs.RecommendItemsToItem('nyphilharmonic181210', 'user-27', 3, {
		returnProperties: true,
		filter: "'city' == \"New York\" AND 'date' >= now() AND \"ballet\" in 'genres'"
	}),
	callback);
```

JSON

```
{
    "recomms": [
        {
            "values": {
                "city": "New York",
                "price": 82.0,
                "venue": "Metropolitan Opera House",
                "title": "American Ballet Theatre: Harlequinade",
                "date": 1564185600.0,
                "genres": [
                    "ballet"
                ]
            },
            "id": "americanballet190727"
        },
        {
            "values": {
                "city": "New York",
                "price": 77.0,
                "venue": "Joyce Theater",
                "title": "BalletX & Raphael Xavier",
                "date": 1555027200.0,
                "genres": [
                    "contemporary dance",
                    "ballet"
                ]
            },
            "id": "balletx190412"
        },
        {
            "values": {
                "city": "New York",
                "price": 92.0,
                "venue": "David H. Koch Theater",
                "title": "NYCB: Orpheus",
                "date": 1561334400.0,
                "genres": [
                    "ballet"
                ]
            },
            "id": "nycb190624"
        }
    ],
    "recommId": "f05b4d84-fec0-4ef8-8875-eac9bd378c6c"
}

```

Sometimes the filter may depend on the currently viewed item. For example, we may want to change our filter not to permit only items from_New York_, but recommend events from the same city where the event that is currently viewed by the user takes place.

The [context\_item function](/reql_functions#reql-func-context-item), which retrieves properties of current item, makes achieving this behavior easy. We will permit only items that have the same _city_as context item: `'city' == context_item["city"]`. Therefore if we get recommendations related to an event that takes place in _Los Angeles_, we get only events taking place in LA.

```python
recommended = client.send(RecommendItemsToItem('laphilharmonic190525', 'user-27', 3,
	return_properties=True,
	filter="'city' == context_item[\"city\"] AND 'date' >= now() AND \"ballet\" in 'genres'"))
```

```js
client.send(
	new recombee.RecommendItemsToItem('laphilharmonic190525', 'user-27', 3, {
		returnProperties: true,
		filter: "'city' == context_item[\"city\"] AND 'date' >= now() AND \"ballet\" in 'genres'"
	}),
	callback);
```

```java
recommended = client.send(new RecommendItemsToItem("laphilharmonic190525", "user-27", 3)
				.setReturnProperties(true)
				.setFilter("'city' == context_item[\"city\"] AND 'date' >= now() AND \"ballet\" in 'genres'"));
```

```ruby
recommended = client.send(RecommendItemsToItem.new('laphilharmonic190525', 'user-27', 3,
				:return_properties => true,
				:filter => "'city' == context_item[\"city\"] AND 'date' >= now() AND \"ballet\" in 'genres'"))
```

```php
$recommended = $client->send(new Reqs\RecommendItemsToItem('laphilharmonic190525', 'user-27', 3,
				['returnProperties' => true,
				'filter' => "'city' == context_item[\"city\"] AND 'date' >= now() AND \"ballet\" in 'genres'"]));
```

```csharp
recommended = client.Send(new RecommendItemsToItem("laphilharmonic190525", "user-27", 3,
				returnProperties: true,
				filter: "'city' == context_item[\"city\"] AND 'date' >= now() AND \"ballet\" in 'genres'"));
```

```js
client.send(
	new rqs.RecommendItemsToItem('laphilharmonic190525', 'user-27', 3, {
		returnProperties: true,
		filter: "'city' == context_item[\"city\"] AND 'date' >= now() AND \"ballet\" in 'genres'"
	}),
	callback);
```

As you can see, the possibilities of filtering are very broad. Besides filtering, there is also the possibility to[boost some items](/reql_filtering_and_boosting#reql-boosting) or[use properties of users](/api#request-add-user-property).

## JavaScript Integration

To see the steps required to integrate Recombee with your website or JavaScript application, please refer to the [example in our JavaScript SDK Documentation](/js_client#integration-example).