Restaurant Dataset
This tutorial will guide you through using the demo dataset to show you some of the abilities that Pipeless provides.
Data summary
Our restaurant demo dataset is a small slice of a public Yelp dataset which includes 1) restaurants 2) restaurant cuisine categories 3) user likes/dislikes of restaurants 4) users following users.
Objects
This dataset contains these objects:
- 10,000 users (type is "user")
- id for each of these is the numeral 0 through 9999, e.g. "33"
- 468 restaurants (type is "company")
- id for each of these is the string name of the restaurant, e.g. "The Vig Uptown"
- 161 restaurant cuisine categories (type is "category")
- id for each of these is the string name of the category, e.g. "Sushi"
Relationships
This dataset contains these relationships:
- 4,100 users "followed" another user ("user")
- 15,929 users "liked" a restaurant ("company")
- 3,206 users "disliked" a restaurant ("company")
- 2,158 restaurants ("company") "categorizedIn" in a cuisine category ("category")
Total stored objects: 10,629
Total stored relationships: 25,393
Total stored items (objects + relationships): 36,022
Schema
The data structure with objects and relationships looks like this connected together in the graph database:
Cloning dataset
To create your own editable version of the restaurant dataset first go to the Account / Apps page and clicking on the link "Or add demo app" that is on the empty Apps list or from the Add App modal. Clicking "Or add demo app" will open the "Add Demo App" modal. There you will see the "Restaurant Dataset" selected. You can then click "Add App" to start the app cloning process, which should only take a few seconds to complete.
If you do not already have a paid app, adding a demo app will utilize your single free plan app, so if you already have a free app created, you may need to delete that app before adding the demo app.
View app details in Apps list
Once the data finishes cloning, you will see the "Restaurant Dataset" app listed on your Apps page. It should look something like this but with your unique App ID and API Key:
Making requests to the API
Now that you have your App ID and your API Key for this demo app, you can now make requests to our API endpoints using your App ID in the endpoint URL, and for authentication, your API Key (do not use the example App ID and API Key shown in the screenshot).
To experiment with your demo app, you're welcome to use your language of choice, but for ease of testing, we recommend the free Postman product for for quick testing of our API. You can get Postman here.
Using Postman
First you'll need to go to the "Authorization" Tab to enter the API Key for your demo app. This unique string goes in place of the "XXXX....XXXX" you see in this screenshot. Do keep the "Bearer " text before your API Key as that is needed.
Next, you can go to the "Body" tab and enter in the JSON body data for each request.
You'll also need to input the endpoint URL and set the request type to "GET" for all of these algo endpoints. Remember to use your own App ID for the demo app, and not the "123" you see in this screenshot.
Once you have those three items set up in Postman: 1) your app API Key 2) your body data JSON 3) your GET request endpoint URL with your unique App ID, you can click the button "Send" to submit the request to Pipeless. You should see a response underneath the Body section that is either data back or an error message of some kind.
This will count as your first call to your free demo app, which you can see counted a few seconds later by going to your Dashboard. Make sure the top right dropdown that it says "Restaurant Dataset", and if "Used Monthly Calls" still reads "0", you may have to refresh to see the updated count.
For the requests below, you can copy/paste the code examples or you can also try out our Postman Collection:
https://api.pipeless.io/pipeless_postman_collection.json
Client libraries
The examples below can also be executed by utilizing our client libraries:
Node Client Library
PHP Client Library
Try out our algorithms
Recent Activity
Let's start with taking a look at a user and seeing recent activity associated with that user.
GET request endpoint URL (replace "app_id" with your App ID for your cloned demo app)
https://api.pipeless.io/v1/apps/app_id/algos/activity/object
Body request data in JSON format
{
"object":{
"id":"33",
"type":"user"
}
}
The body of the response for user 33 should look like this:
{
"events": [
{
"object": {
"id": "5967",
"type": "user",
"created_on": "2020-09-29T01:17:18",
"modified_on": "2020-09-29T01:17:18"
},
"relationship": {
"type": "followed",
"created_on": "2020-09-29T01:49:56"
},
"direction": "incoming"
},
{
"object": {
"id": "5967",
"type": "user",
"created_on": "2020-09-29T01:17:18",
"modified_on": "2020-09-29T01:17:18"
},
"relationship": {
"type": "followed",
"created_on": "2020-09-29T01:49:11"
},
"direction": "outgoing"
},
{
"object": {
"id": "Tryst Cafe - Phoenix",
"type": "company",
"created_on": "2020-09-29T01:15:53",
"modified_on": "2020-09-29T01:15:53"
},
"relationship": {
"type": "liked",
"created_on": "2011-07-13T21:45:13"
},
"direction": "outgoing"
},
{
"object": {
"id": "Over Easy - Arcadia",
"type": "company",
"created_on": "2020-09-29T01:19:26",
"modified_on": "2020-09-29T01:19:26"
},
"relationship": {
"type": "liked",
"created_on": "2011-01-14T18:31:13"
},
"direction": "outgoing"
}
],
"page_info": {
"end_cursor": "MTI5NTAyOTg3M18yMjQ4OTc0MjY=",
"has_next_page": false
}
}
The first activity you see is another user (user 5967) following user 33. The next activity shows the reciprocation of that following relationship so that user 33 is following user 5967. Relationships in Pipeless are directional, so for a "friends" or "connection" style following system, "followed" relationships need to be established in both directions.
The next two activity involving user 33 are liked actions on a couple different restaurants.
You can get an Activity Feed on any object, like in this example, one of the restaurants user 33 liked:
{
"object": {
"id": "Over Easy - Arcadia",
"type": "company"
},
"relationship_types": [
"liked"
],
"limit": 3
}
This changes the object type to "company" and adds in the extra parameter "relationship_types" which allows you to filter the relationships "Over Easy - Arcadia" has to just "liked" activity. If you try it without that param, the response would include the "categorizedIn" relationships as well. And since we don't want all of the likes, we're limiting the number of activity events to a max of 3 events.
Here's the response body for the above example request, showing different users who most recently liked this restaurant:
{
"events": [
{
"object": {
"id": "1035",
"type": "user",
"created_on": "2020-09-29T01:17:21",
"modified_on": "2020-09-29T01:17:21"
},
"relationship": {
"type": "liked",
"created_on": "2019-06-26T00:57:24"
},
"direction": "incoming"
},
{
"object": {
"id": "9993",
"type": "user",
"created_on": "2020-09-29T01:17:14",
"modified_on": "2020-09-29T01:17:14"
},
"relationship": {
"type": "liked",
"created_on": "2019-03-20T03:17:34"
},
"direction": "incoming"
},
{
"object": {
"id": "3740",
"type": "user",
"created_on": "2020-09-29T01:17:15",
"modified_on": "2020-09-29T01:17:15"
},
"relationship": {
"type": "liked",
"created_on": "2019-03-06T19:31:24"
},
"direction": "incoming"
}
],
"page_info": {
"end_cursor": "MTU1MTkwMDY4NF8yMjQ5MzI4NzU=",
"has_next_page": true
}
}
You can also do this with topics, interests, tags, or in this case cuisine categories, to see the most recent activity associated with these objects, which in this case will be restaurants that were categorized with the category "Burgers":
{
"object": {
"id": "Burgers",
"type": "category"
},
"limit": 3
}
Here we see the response body for that request, limited to 3 most recent restaurants which have the "categorizedIn" relationship to the "Burgers" category object.
{
"events": [
{
"object": {
"id": "Rocket Burger & Subs",
"type": "company",
"created_on": "2020-09-29T01:20:48",
"modified_on": "2020-09-29T01:20:48"
},
"relationship": {
"type": "categorizedIn",
"created_on": "2020-09-29T03:10:11"
},
"direction": "incoming"
},
{
"object": {
"id": "Caveman Burgers",
"type": "company",
"created_on": "2020-09-29T01:20:49",
"modified_on": "2020-09-29T01:20:49"
},
"relationship": {
"type": "categorizedIn",
"created_on": "2020-09-29T03:10:09"
},
"direction": "incoming"
},
{
"object": {
"id": "Modern Grove",
"type": "company",
"created_on": "2020-09-29T01:20:50",
"modified_on": "2020-09-29T01:20:50"
},
"relationship": {
"type": "categorizedIn",
"created_on": "2020-09-29T03:10:09"
},
"direction": "incoming"
}
],
"page_info": {
"end_cursor": "MTYwMTM0OTAwOV8yMjQ5ODgwNTY=",
"has_next_page": true
}
}
You can read the reference docs for this endpoint here:
Get Activity on Object
Following Feed
GET request endpoint URL (replace "app_id" with your App ID for your cloned demo app)
https://api.pipeless.io/v1/apps/app_id/algos/activity/feed
Body data in JSON format
{
"object": {
"id": "95",
"type": "user"
},
"event_relationship_types": [
"liked",
"disliked"
]
}
Here's the response for this user's following feed, limited to event relationship types either as "liked" or "disliked." (Without that param, it will also include the "followed" action.)
{
"events": [
{
"actor_object": {
"id": "437",
"type": "user",
"created_on": "2020-09-29T01:21:14",
"modified_on": "2020-09-29T01:21:14"
},
"action_relationship": {
"type": "liked",
"created_on": "2019-05-21T17:25:43"
},
"action_object": {
"id": "32 Shea",
"type": "company",
"created_on": "2020-09-29T01:20:49",
"modified_on": "2020-09-29T01:20:49"
}
},
{
"actor_object": {
"id": "9877",
"type": "user",
"created_on": "2020-09-29T01:16:01",
"modified_on": "2020-09-29T01:16:01"
},
"action_relationship": {
"type": "liked",
"created_on": "2018-05-05T23:42:34"
},
"action_object": {
"id": "The Original Carolina's Mexican Food",
"type": "company",
"created_on": "2020-09-29T01:18:33",
"modified_on": "2020-09-29T01:18:33"
}
},
{
"actor_object": {
"id": "9877",
"type": "user",
"created_on": "2020-09-29T01:16:01",
"modified_on": "2020-09-29T01:16:01"
},
"action_relationship": {
"type": "liked",
"created_on": "2018-05-02T02:03:42"
},
"action_object": {
"id": "Rosita's Place",
"type": "company",
"created_on": "2020-09-29T01:17:01",
"modified_on": "2020-09-29T01:17:01"
}
},
{
"actor_object": {
"id": "9877",
"type": "user",
"created_on": "2020-09-29T01:16:01",
"modified_on": "2020-09-29T01:16:01"
},
"action_relationship": {
"type": "disliked",
"created_on": "2017-07-12T04:50:25"
},
"action_object": {
"id": "Popo's Mexican Food",
"type": "company",
"created_on": "2020-09-29T01:18:33",
"modified_on": "2020-09-29T01:18:33"
}
},
{
"actor_object": {
"id": "9877",
"type": "user",
"created_on": "2020-09-29T01:16:01",
"modified_on": "2020-09-29T01:16:01"
},
"action_relationship": {
"type": "liked",
"created_on": "2016-12-07T21:33:44"
},
"action_object": {
"id": "Ticoz Latin Kitchen",
"type": "company",
"created_on": "2020-09-29T01:15:53",
"modified_on": "2020-09-29T01:15:53"
}
},
{
"actor_object": {
"id": "6911",
"type": "user",
"created_on": "2020-09-29T01:17:06",
"modified_on": "2020-09-29T01:17:06"
},
"action_relationship": {
"type": "liked",
"created_on": "2014-03-19T05:52:06"
},
"action_object": {
"id": "Switch",
"type": "company",
"created_on": "2020-09-29T01:20:03",
"modified_on": "2020-09-29T01:20:03"
}
},
{
"actor_object": {
"id": "6911",
"type": "user",
"created_on": "2020-09-29T01:17:06",
"modified_on": "2020-09-29T01:17:06"
},
"action_relationship": {
"type": "liked",
"created_on": "2014-03-19T05:46:30"
},
"action_object": {
"id": "La Grande Orange Pizzeria",
"type": "company",
"created_on": "2020-09-29T01:17:00",
"modified_on": "2020-09-29T01:17:00"
}
}
],
"page_info": {
"end_cursor": "MTM5NTIwNzk5MF8yMjQ5NTU1NjA=",
"has_next_page": false
}
}
It looks like user 95 is following three users (users 437, 9877, 6911) who have recently liked or disliked any restaurants, and you can see which restaurants they engaged with.
Some shortcomings of this dataset: The Following Feed algo is a lot more interesting when you have users following other users/accounts that post content (posts, articles, photos, videos, etc.) rather than users following other users who only can like/dislike fixed content. That limitation makes the Following Feed results look very similar to the Following Action Feed. Also be aware that for this demo dataset, there are a lot of users who are 1) not following anyone and 2) not following many people, so if you try out different user id's, don't be surprised if you run into some limited responses.
You can read the reference docs for this endpoint here:
Get Activity Feed
Following Action Feed
GET request endpoint URL (replace "app_id" with your App ID for your cloned demo app)
https://api.pipeless.io/v1/apps/app_id/algos/activity/actions-feed
Body data in JSON format
{
"object": {
"id": "7908",
"type": "user"
},
"event_relationship_types": [
"liked"
]
}
This will return a feed of actions of other users that user 7908 follows, filtered to just "liked" actions:
{
"events": [
{
"action_object": {
"id": "The Sicilian Butcher",
"type": "company",
"created_on": "2020-09-29T01:20:48",
"modified_on": "2020-09-29T01:20:48"
},
"actions": [
{
"actor_object": {
"id": "5540",
"type": "user",
"created_on": "2020-09-29T01:17:53",
"modified_on": "2020-09-29T01:17:53"
},
"action_relationship": {
"type": "liked",
"created_on": "2019-12-07T17:04:06"
}
},
{
"actor_object": {
"id": "3312",
"type": "user",
"created_on": "2020-09-29T01:15:53",
"modified_on": "2020-09-29T01:15:53"
},
"action_relationship": {
"type": "liked",
"created_on": "2018-01-25T20:50:47"
}
}
]
},
{
"action_object": {
"id": "The Tamale Store",
"type": "company",
"created_on": "2020-09-29T01:15:58",
"modified_on": "2020-09-29T01:15:58"
},
"actions": [
{
"actor_object": {
"id": "4644",
"type": "user",
"created_on": "2020-09-29T01:15:54",
"modified_on": "2020-09-29T01:15:54"
},
"action_relationship": {
"type": "liked",
"created_on": "2019-12-05T15:55:26"
}
}
]
},
{
"action_object": {
"id": "The Arrogant Butcher",
"type": "company",
"created_on": "2020-09-29T01:15:53",
"modified_on": "2020-09-29T01:15:53"
},
"actions": [
{
"actor_object": {
"id": "1693",
"type": "user",
"created_on": "2020-09-29T01:16:00",
"modified_on": "2020-09-29T01:16:00"
},
"action_relationship": {
"type": "liked",
"created_on": "2019-11-17T05:04:14"
}
}
]
},
{
"action_object": {
"id": "The Duce",
"type": "company",
"created_on": "2020-09-29T01:16:27",
"modified_on": "2020-09-29T01:16:27"
},
"actions": [
{
"actor_object": {
"id": "5588",
"type": "user",
"created_on": "2020-09-29T01:15:57",
"modified_on": "2020-09-29T01:15:57"
},
"action_relationship": {
"type": "liked",
"created_on": "2019-11-07T22:23:41"
}
},
{
"actor_object": {
"id": "2230",
"type": "user",
"created_on": "2020-09-29T01:15:59",
"modified_on": "2020-09-29T01:15:59"
},
"action_relationship": {
"type": "liked",
"created_on": "2018-11-09T04:26:37"
}
},
{
"actor_object": {
"id": "4859",
"type": "user",
"created_on": "2020-09-29T01:16:11",
"modified_on": "2020-09-29T01:16:11"
},
"action_relationship": {
"type": "liked",
"created_on": "2015-12-28T22:38:51"
}
}
]
},
{
"action_object": {
"id": "The Coronado PHX",
"type": "company",
"created_on": "2020-09-29T01:20:03",
"modified_on": "2020-09-29T01:20:03"
},
"actions": [
{
"actor_object": {
"id": "5588",
"type": "user",
"created_on": "2020-09-29T01:15:57",
"modified_on": "2020-09-29T01:15:57"
},
"action_relationship": {
"type": "liked",
"created_on": "2019-11-07T22:17:37"
}
}
]
},
{
"action_object": {
"id": "Ajo Al's Mexican Cafe",
"type": "company",
"created_on": "2020-09-29T01:20:04",
"modified_on": "2020-09-29T01:20:04"
},
"actions": [
{
"actor_object": {
"id": "1693",
"type": "user",
"created_on": "2020-09-29T01:16:00",
"modified_on": "2020-09-29T01:16:00"
},
"action_relationship": {
"type": "liked",
"created_on": "2019-10-16T17:35:39"
}
}
]
},
{
"action_object": {
"id": "The Henry",
"type": "company",
"created_on": "2020-09-29T01:20:04",
"modified_on": "2020-09-29T01:20:04"
},
"actions": [
{
"actor_object": {
"id": "5540",
"type": "user",
"created_on": "2020-09-29T01:17:53",
"modified_on": "2020-09-29T01:17:53"
},
"action_relationship": {
"type": "liked",
"created_on": "2019-10-13T16:56:28"
}
},
{
"actor_object": {
"id": "5754",
"type": "user",
"created_on": "2020-09-29T01:15:57",
"modified_on": "2020-09-29T01:15:57"
},
"action_relationship": {
"type": "liked",
"created_on": "2019-08-12T19:01:27"
}
},
{
"actor_object": {
"id": "8094",
"type": "user",
"created_on": "2020-09-29T01:16:01",
"modified_on": "2020-09-29T01:16:01"
},
"action_relationship": {
"type": "liked",
"created_on": "2018-05-25T07:13:29"
}
},
{
"actor_object": {
"id": "8713",
"type": "user",
"created_on": "2020-09-29T01:16:43",
"modified_on": "2020-09-29T01:16:43"
},
"action_relationship": {
"type": "liked",
"created_on": "2017-06-12T19:58:11"
}
},
{
"actor_object": {
"id": "5646",
"type": "user",
"created_on": "2020-09-29T01:15:58",
"modified_on": "2020-09-29T01:15:58"
},
"action_relationship": {
"type": "liked",
"created_on": "2014-09-10T18:47:56"
}
},
{
"actor_object": {
"id": "5664",
"type": "user",
"created_on": "2020-09-29T01:15:54",
"modified_on": "2020-09-29T01:15:54"
},
"action_relationship": {
"type": "liked",
"created_on": "2014-07-04T03:29:56"
}
}
]
},
{
"action_object": {
"id": "Sushi On Tatum",
"type": "company",
"created_on": "2020-09-29T01:17:29",
"modified_on": "2020-09-29T01:17:29"
},
"actions": [
{
"actor_object": {
"id": "5540",
"type": "user",
"created_on": "2020-09-29T01:17:53",
"modified_on": "2020-09-29T01:17:53"
},
"action_relationship": {
"type": "liked",
"created_on": "2019-10-13T16:48:27"
}
}
]
},
{
"action_object": {
"id": "Sushiholic",
"type": "company",
"created_on": "2020-09-29T01:20:49",
"modified_on": "2020-09-29T01:20:49"
},
"actions": [
{
"actor_object": {
"id": "646",
"type": "user",
"created_on": "2020-09-29T01:16:26",
"modified_on": "2020-09-29T01:16:26"
},
"action_relationship": {
"type": "liked",
"created_on": "2019-09-23T01:00:24"
}
},
{
"actor_object": {
"id": "4859",
"type": "user",
"created_on": "2020-09-29T01:16:11",
"modified_on": "2020-09-29T01:16:11"
},
"action_relationship": {
"type": "liked",
"created_on": "2019-06-04T00:36:02"
}
},
{
"actor_object": {
"id": "1693",
"type": "user",
"created_on": "2020-09-29T01:16:00",
"modified_on": "2020-09-29T01:16:00"
},
"action_relationship": {
"type": "liked",
"created_on": "2016-08-17T19:51:20"
}
}
]
},
{
"action_object": {
"id": "The Capital Grille",
"type": "company",
"created_on": "2020-09-29T01:20:04",
"modified_on": "2020-09-29T01:20:04"
},
"actions": [
{
"actor_object": {
"id": "646",
"type": "user",
"created_on": "2020-09-29T01:16:26",
"modified_on": "2020-09-29T01:16:26"
},
"action_relationship": {
"type": "liked",
"created_on": "2019-09-10T03:47:35"
}
},
{
"actor_object": {
"id": "4644",
"type": "user",
"created_on": "2020-09-29T01:15:54",
"modified_on": "2020-09-29T01:15:54"
},
"action_relationship": {
"type": "liked",
"created_on": "2014-05-14T18:20:36"
}
}
]
}
],
"page_info": {
"end_cursor": "MTU2ODA4NzI1NV8yMjQ5NjYzNDI=",
"has_next_page": true
}
}
Above we see restaurants that are actions of others users that user 7908 follows, and for the Action Feed, results are aggregated. For the first "action_object" listed above in the response, you can see that there are two users ("actor_object" users 5540 and 3312) that user 7908 follows who have recently liked the restaurant "The Sicilian Butcher".
One characteristic of the Following Feed and the Following Action Feed is that they include all actions from users/accounts that that user follows, which you may find isn't always desirable, for instance in this case below where an action of a user that user 545 follows is the action of them reciprocating the follow to user 545. So you can set a param to skip actions that other users take on the target user (user 545) by adding "exclude_self_object" as "true":
{
"object": {
"id": "545",
"type": "user"
},
"exclude_self_object": true
}
The response with "exclude_self_object" set to "true":
{
"events": [
{
"action_object": {
"id": "313",
"type": "user",
"created_on": "2020-09-29T01:18:23",
"modified_on": "2020-09-29T01:18:23"
},
"actions": [
{
"actor_object": {
"id": "8406",
"type": "user",
"created_on": "2020-09-29T01:17:02",
"modified_on": "2020-09-29T01:17:02"
},
"action_relationship": {
"type": "followed",
"created_on": "2020-09-29T01:49:52"
}
}
]
},
{
"action_object": {
"id": "Original Breakfast House",
"type": "company",
"created_on": "2020-09-29T01:16:59",
"modified_on": "2020-09-29T01:16:59"
},
"actions": [
{
"actor_object": {
"id": "8406",
"type": "user",
"created_on": "2020-09-29T01:17:02",
"modified_on": "2020-09-29T01:17:02"
},
"action_relationship": {
"type": "liked",
"created_on": "2017-11-09T16:14:48"
}
}
]
},
{
"action_object": {
"id": "Duza's Kitchen",
"type": "company",
"created_on": "2020-09-29T01:17:58",
"modified_on": "2020-09-29T01:17:58"
},
"actions": [
{
"actor_object": {
"id": "2576",
"type": "user",
"created_on": "2020-09-29T01:18:08",
"modified_on": "2020-09-29T01:18:08"
},
"action_relationship": {
"type": "liked",
"created_on": "2016-07-17T16:13:50"
}
}
]
},
{
"action_object": {
"id": "Pizza People Pub",
"type": "company",
"created_on": "2020-09-29T01:20:03",
"modified_on": "2020-09-29T01:20:03"
},
"actions": [
{
"actor_object": {
"id": "2576",
"type": "user",
"created_on": "2020-09-29T01:18:08",
"modified_on": "2020-09-29T01:18:08"
},
"action_relationship": {
"type": "liked",
"created_on": "2016-02-02T03:16:58"
}
}
]
}
],
"page_info": {
"end_cursor": "MTQ1NDM4MzAxOF8yMjQ5MDUxNDI=",
"has_next_page": false
}
}
Compare below without the self exclusion and see how user 545 is shown as the first "action_object" because other users that 545 is following have taken the action to follow back (setting "exclude_self_object" to "false" would produce the same response since the default value is "false") :
{
"object":{
"id":"545",
"type":"user"
}
}
Response to the above request (no self exclusion) where you get results that include user 545 as an action object since a couple of the users that are followed by user 545 followed back (user 2576 and user 8406 both followed user 545) :
{
"events": [
{
"action_object": {
"id": "545",
"type": "user",
"created_on": "2020-09-29T01:18:04",
"modified_on": "2020-09-29T01:18:04"
},
"actions": [
{
"actor_object": {
"id": "2576",
"type": "user",
"created_on": "2020-09-29T01:18:08",
"modified_on": "2020-09-29T01:18:08"
},
"action_relationship": {
"type": "followed",
"created_on": "2020-09-29T01:50:00"
}
},
{
"actor_object": {
"id": "8406",
"type": "user",
"created_on": "2020-09-29T01:17:02",
"modified_on": "2020-09-29T01:17:02"
},
"action_relationship": {
"type": "followed",
"created_on": "2020-09-29T01:49:52"
}
}
]
},
{
"action_object": {
"id": "313",
"type": "user",
"created_on": "2020-09-29T01:18:23",
"modified_on": "2020-09-29T01:18:23"
},
"actions": [
{
"actor_object": {
"id": "8406",
"type": "user",
"created_on": "2020-09-29T01:17:02",
"modified_on": "2020-09-29T01:17:02"
},
"action_relationship": {
"type": "followed",
"created_on": "2020-09-29T01:49:52"
}
}
]
},
{
"action_object": {
"id": "Original Breakfast House",
"type": "company",
"created_on": "2020-09-29T01:16:59",
"modified_on": "2020-09-29T01:16:59"
},
"actions": [
{
"actor_object": {
"id": "8406",
"type": "user",
"created_on": "2020-09-29T01:17:02",
"modified_on": "2020-09-29T01:17:02"
},
"action_relationship": {
"type": "liked",
"created_on": "2017-11-09T16:14:48"
}
}
]
},
{
"action_object": {
"id": "Duza's Kitchen",
"type": "company",
"created_on": "2020-09-29T01:17:58",
"modified_on": "2020-09-29T01:17:58"
},
"actions": [
{
"actor_object": {
"id": "2576",
"type": "user",
"created_on": "2020-09-29T01:18:08",
"modified_on": "2020-09-29T01:18:08"
},
"action_relationship": {
"type": "liked",
"created_on": "2016-07-17T16:13:50"
}
}
]
},
{
"action_object": {
"id": "Pizza People Pub",
"type": "company",
"created_on": "2020-09-29T01:20:03",
"modified_on": "2020-09-29T01:20:03"
},
"actions": [
{
"actor_object": {
"id": "2576",
"type": "user",
"created_on": "2020-09-29T01:18:08",
"modified_on": "2020-09-29T01:18:08"
},
"action_relationship": {
"type": "liked",
"created_on": "2016-02-02T03:16:58"
}
}
]
}
],
"page_info": {
"end_cursor": "MTQ1NDM4MzAxOF8yMjQ5MDUxNDI=",
"has_next_page": false
}
}
The exclusion is an optional parameter, so it's up to you if you want to include actions that connect back to the target user or not.
You can read the reference docs for this endpoint here:
Get Activity Actions Feed
Content Recommendations
GET request endpoint URL (replace "app_id" with your App ID for your cloned demo app)
https://api.pipeless.io/v1/apps/app_id/algos/recommendations/content
Body data in JSON format
{
"object": {
"id": "33",
"type": "user"
},
"content_object_type": "company",
"primary_positive_relationship_type": "liked",
"primary_negative_relationship_type": "disliked",
"content_tagged_relationship_type": "categorizedIn",
"content_tag_object_type": "category",
"limit": 4
}
The request above is going to return four personalized recommendations for user 33 that will be restaurants ("company"), which will be based on user 33's past likes ("liked" set as "primary_positive_relationship_type") and will avoid showing any negative signals user 33 has given for restaurants ("disliked" set as "primary_negative_relationship_type"). That by itself will run through collaborative filtering to find other users who liked the restaurants user 33 has liked, and find restaurants that those other users have liked. Next we add in restaurant cuisine categories to help filter more similar types of restaurants (using "content_tagged_relationship_type" as "categorizedIn" and "content_tag_object_type" as "category"). These category tags get weighted with the liked collaborative filtering to produce the restaurant recommendations for user 33 shown in the response below:
{
"items": [
{
"object": {
"id": "Carly's Bistro",
"type": "company",
"created_on": "2020-09-29T01:17:59",
"modified_on": "2020-09-29T01:17:59"
}
},
{
"object": {
"id": "32 Shea",
"type": "company",
"created_on": "2020-09-29T01:20:49",
"modified_on": "2020-09-29T01:20:49"
}
},
{
"object": {
"id": "Hob Nobs",
"type": "company",
"created_on": "2020-09-29T01:15:54",
"modified_on": "2020-09-29T01:15:54"
}
},
{
"object": {
"id": "Ollie Vaughn's",
"type": "company",
"created_on": "2020-09-29T01:18:33",
"modified_on": "2020-09-29T01:18:33"
}
}
]
}
Filtered Content Recommendations
You can also filter personalized recommendations by specific tags/categories, like if you wanted to take the results above but only return recommended restaurants that are categorized as "Jazz & Blues" and "Vegan", which is shown below. Note that "filter_tag_ids" is an AND operator, so results must have all tags to be returned.
{
"object": {
"id": "33",
"type": "user"
},
"content_object_type": "company",
"primary_positive_relationship_type": "liked",
"primary_negative_relationship_type": "disliked",
"content_tagged_relationship_type": "categorizedIn",
"content_tag_object_type": "category",
"limit": 4,
"filter_tag_ids": ["Jazz & Blues","Vegan"]
}
That will return just one recommended restaurant (Vegan Jazz is a niche audience!):
{
"items": [
{
"object": {
"id": "Carly's Bistro",
"type": "company",
"created_on": "2020-09-29T01:17:59",
"modified_on": "2020-09-29T01:17:59"
}
}
]
}
If you want to double check the category tags, you can do that easily with the Activity Feed endpoint. Just take that object and find all the "categorizedIn" relationships, which will give you a list of the category tags:
https://api.pipeless.io/v1/apps/app_id/algos/activity/object
{
"object": {
"id": "Carly's Bistro",
"type": "company"
},
"relationship_types": [
"categorizedIn"
]
}
{
"events": [
{
"object": {
"id": "Sandwiches",
"type": "category",
"created_on": "2020-09-29T03:09:35",
"modified_on": "2020-09-29T03:09:35"
},
"relationship": {
"type": "categorizedIn",
"created_on": "2020-09-29T03:09:50"
},
"direction": "outgoing"
},
{
"object": {
"id": "Bars",
"type": "category",
"created_on": "2020-09-29T03:09:35",
"modified_on": "2020-09-29T03:09:35"
},
"relationship": {
"type": "categorizedIn",
"created_on": "2020-09-29T03:09:50"
},
"direction": "outgoing"
},
{
"object": {
"id": "Vegan",
"type": "category",
"created_on": "2020-09-29T03:09:35",
"modified_on": "2020-09-29T03:09:35"
},
"relationship": {
"type": "categorizedIn",
"created_on": "2020-09-29T03:09:50"
},
"direction": "outgoing"
},
{
"object": {
"id": "Vegetarian",
"type": "category",
"created_on": "2020-09-29T03:09:35",
"modified_on": "2020-09-29T03:09:35"
},
"relationship": {
"type": "categorizedIn",
"created_on": "2020-09-29T03:09:50"
},
"direction": "outgoing"
},
{
"object": {
"id": "Arts & Entertainment",
"type": "category",
"created_on": "2020-09-29T03:09:35",
"modified_on": "2020-09-29T03:09:35"
},
"relationship": {
"type": "categorizedIn",
"created_on": "2020-09-29T03:09:50"
},
"direction": "outgoing"
},
{
"object": {
"id": "Desserts",
"type": "category",
"created_on": "2020-09-29T03:09:37",
"modified_on": "2020-09-29T03:09:37"
},
"relationship": {
"type": "categorizedIn",
"created_on": "2020-09-29T03:09:50"
},
"direction": "outgoing"
},
{
"object": {
"id": "Jazz & Blues",
"type": "category",
"created_on": "2020-09-29T03:09:36",
"modified_on": "2020-09-29T03:09:36"
},
"relationship": {
"type": "categorizedIn",
"created_on": "2020-09-29T03:09:50"
},
"direction": "outgoing"
},
{
"object": {
"id": "Beer",
"type": "category",
"created_on": "2020-09-29T03:09:35",
"modified_on": "2020-09-29T03:09:35"
},
"relationship": {
"type": "categorizedIn",
"created_on": "2020-09-29T03:09:50"
},
"direction": "outgoing"
},
{
"object": {
"id": "American (New)",
"type": "category",
"created_on": "2020-09-29T03:09:34",
"modified_on": "2020-09-29T03:09:34"
},
"relationship": {
"type": "categorizedIn",
"created_on": "2020-09-29T03:09:50"
},
"direction": "outgoing"
},
{
"object": {
"id": "Local Flavor",
"type": "category",
"created_on": "2020-09-29T03:09:36",
"modified_on": "2020-09-29T03:09:36"
},
"relationship": {
"type": "categorizedIn",
"created_on": "2020-09-29T03:09:50"
},
"direction": "outgoing"
}
],
"page_info": {
"end_cursor": "MTYwMTM0ODk5MF8yMjQ5OTAyNTU=",
"has_next_page": true
}
}
These results can let you confirm that things are looking right, where that restaurant does in fact have both "Vegan" and "Jazz & Blues" as category tags.
You can read the reference docs for this endpoint here:
Get Recommended Content (for user)
Recommended Accounts
GET request endpoint URL (replace "app_id" with your App ID for your cloned demo app)
https://api.pipeless.io/v1/apps/app_id/algos/recommendations/users-to-follow
Body data in JSON format
{
"object": {
"id": "543",
"type": "user"
},
"followed_relationship_type": "followed",
"content_created_relationship_type": "liked",
"positive_relationship_type": "liked",
"content_tagged_relationship_type": "categorizedIn",
"content_object_type": "company",
"content_tag_object_type": "category",
"limit": 3
}
The above request has a few options set: 1) it starts by personalizing the results for user 543 and then 2) it looks at the users that user 543 is following 3) it looks at objects (restaurants) that are connected by a "liked" relationship 4) basing recommendations on those "liked" relationships for others who are have liked content (restaurants as object type "company") while factoring in 5) cuisine categories of the restaurants that have been liked by others compared to the past likes of user 543.
{
"items": [
{
"object": {
"id": "7417",
"type": "user",
"created_on": "2020-09-29T01:15:56",
"modified_on": "2020-09-29T01:15:56"
}
},
{
"object": {
"id": "5008",
"type": "user",
"created_on": "2020-09-29T01:16:38",
"modified_on": "2020-09-29T01:16:38"
}
},
{
"object": {
"id": "3798",
"type": "user",
"created_on": "2020-09-29T01:17:16",
"modified_on": "2020-09-29T01:17:16"
}
}
]
}
It's a little harder to intuitively spot the quality of user recommendations, but if you run Recent Activity requests on user 543 and these recommended users, you should be able to spot some similarity across the other users they follow along with the types of restaurants they have liked.
You can read the reference docs for this endpoint here:
Get Recommended Users to Follow (for user)
Related Topics
GET request endpoint URL (replace "app_id" with your App ID for your cloned demo app)
https://api.pipeless.io/v1/apps/app_id/algos/recommendations/related-tags
Body data in JSON format
{
"object": {
"id": "Pizza",
"type": "category"
},
"content_object_type": "company",
"content_tagged_relationship_type": "categorizedIn",
"limit":3
}
Here we are looking for restaurant cuisine categories that other restaurants have where those restaurants also have the "Pizza" category tag.
{
"items": [
{
"object": {
"id": "Italian",
"type": "category",
"created_on": "2020-09-29T03:09:34",
"modified_on": "2020-09-29T03:09:34"
}
},
{
"object": {
"id": "Sandwiches",
"type": "category",
"created_on": "2020-09-29T03:09:35",
"modified_on": "2020-09-29T03:09:35"
}
},
{
"object": {
"id": "Nightlife",
"type": "category",
"created_on": "2020-09-29T03:09:35",
"modified_on": "2020-09-29T03:09:35"
}
}
]
}
These results are pulling in other categories "Italian", "Sandwiches" and "Nightlife" that are the most commonly shared categories by restaurants that have the "Pizza" category. Of note, if the categories or tags you have on your data are singular, such that every content item can only have one category, then this algo won't return results as there would be no shared/overlapping categories.
You can read the reference docs for this endpoint here:
Get Related Tags
Related Content
GET request endpoint URL (replace "app_id" with your App ID for your cloned demo app)
https://api.pipeless.io/v1/apps/app_id/algos/recommendations/related-content
Body data in JSON format
{
"object": {
"id": "Cherryblossom Noodle Cafe",
"type": "company"
},
"content_tagged_relationship_type": "categorizedIn",
"positive_rel": "liked",
"content_tagged_object_type": "category",
"limit": 3
}
The request above is going to look for content that has the same type as the target object (restaurants as type "company") that have also been liked by users who liked "Cherryblossom Noddle Cafe", with some weighting for similar cuisine categories.
{
"items": [
{
"object": {
"id": "Noodle Bar",
"type": "company",
"created_on": "2020-09-29T01:16:59",
"modified_on": "2020-09-29T01:16:59"
}
},
{
"object": {
"id": "The Clever Koi",
"type": "company",
"created_on": "2020-09-29T01:15:53",
"modified_on": "2020-09-29T01:15:53"
}
},
{
"object": {
"id": "Nishikawa Ramen",
"type": "company",
"created_on": "2020-09-29T01:18:01",
"modified_on": "2020-09-29T01:18:01"
}
}
]
}
You can read the reference docs for this endpoint here:
Get Related Content
Related Accounts
GET request endpoint URL (replace "app_id" with your App ID for your cloned demo app)
https://api.pipeless.io/v1/apps/app_id/algos/recommendations/related-users
Body data in JSON format
{
"object": {
"id": "8978",
"type": "user"
},
"followed_relationship_type": "followed",
"content_tagged_relationship_type": "categorizedIn",
"content_tagged_object_type": "category",
"content_object_type": "company",
"content_published_relationship_type": "liked",
"limit": 3
}
This request is looking for users similar to user 8978, which starts with collaborative filtering where the algo looks at users who followed user 8978 and who else they followed. Then it factors in the restaurants ("company" type) that user 8978 has liked and the cuisine categories those restaurants have to adjust the recommended users from the collaborative filtering to find those that share similar tastes in restaurants. (due to the limited nature of this dataset, there are not a lot of users in the dataset who follow other users who also follow other users in the dataset, so trying out different user_id's will show a good number of blank responses).
{
"items": [
{
"object": {
"id": "7205",
"type": "user",
"created_on": "2020-09-29T01:16:01",
"modified_on": "2020-09-29T01:16:01"
}
},
{
"object": {
"id": "6905",
"type": "user",
"created_on": "2020-09-29T01:17:26",
"modified_on": "2020-09-29T01:17:26"
}
},
{
"object": {
"id": "2156",
"type": "user",
"created_on": "2020-09-29T01:16:49",
"modified_on": "2020-09-29T01:16:49"
}
}
]
}
Like with Recommended Accounts we talked about earlier, it's harder to intuitively spot the quality of related users, but if you run Recent Activity requests on user 8978 and these related users, you should be able to spot some similarity across the other users they follow along with the types of restaurants they have liked.
Now if you don't have category or tag data, you can also have this algo use only collaborative filtering, which will look at people who follow the target user and who else they follow.
You can see that here:
{
"object": {
"id": "5000",
"type": "user"
},
"followed_relationship_type": "followed",
"limit": 3
}
This is a related users, starting with a target user who is following users who happen to follow other users in this limited dataset, so collaborative filtering is happening without the category data. Which ends up being "users who follow user 5000 also follow these other users." If we added back in the category params in the previous example, it would be "users who follow user 5000 also follow these other users who like restaurants similar to what user 5000 likes."
{
"items": [
{
"object": {
"id": "2525",
"type": "user",
"created_on": "2020-09-29T01:16:44",
"modified_on": "2020-09-29T01:16:44"
}
},
{
"object": {
"id": "7360",
"type": "user",
"created_on": "2020-09-29T01:16:04",
"modified_on": "2020-09-29T01:16:04"
}
},
{
"object": {
"id": "6554",
"type": "user",
"created_on": "2020-09-29T01:17:59",
"modified_on": "2020-09-29T01:17:59"
}
}
]
}
It's a little harder to intuitively spot the quality of related users, but if you run Recent Activity requests on user 5000 and these recommended users, you should be able to spot some similarity across the other users they follow along with the types of restaurants they have liked.
You can read the reference docs for this endpoint here:
Get Related Users
Sorted Content
GET request endpoint URL (replace "app_id" with your App ID for your cloned demo app)
https://api.pipeless.io/v1/apps/app_id/algos/recommendations/sorted-content
Body data in JSON format
{
"object":{
"id":"3507",
"type":"user"
},
"primary_positive_relationship_type":"liked",
"content_tagged_relationship_type":"categorizedIn",
"content_tag_object_type":"category",
"content_object_type": "company",
"content_ids":["Rosita's Place", "The Sicilian Butcher", "Original Breakfast House", "32 Shea", "Noodle Bar", "Nishikawa Ramen", "Ollie Vaughn's", "Pizza People Pub", "Thai Delight", "Federal Pizza", "Times Square Pizzeria", "Angry Crab Shack", "Ranch House Grille", "Autumn Court Chinese Restaurant", "Duza's Kitchen", "Ticoz Latin Kitchen", "The Original Carolina's Mexican Food", "Popo's Mexican Food"],
"limit": 20
}
This request starts by taking a pre-defined list of restaurants (company id's) that you might have from a search result in your system. Then choosing a user (user 3507) to personalize these results for, we look at engagement activity for that user to see which restaurants on the list are most relevant to them based on their "liked" activity and the category tags associated with those restaurants, and then re-sort the list with the most relevant restaurants first and least relevant restaurants last.
{
"items": [
{
"id": "Autumn Court Chinese Restaurant",
"ranked": true
},
{
"id": "Noodle Bar",
"ranked": true
},
{
"id": "Nishikawa Ramen",
"ranked": true
},
{
"id": "The Sicilian Butcher",
"ranked": true
},
{
"id": "Federal Pizza",
"ranked": true
},
{
"id": "Duza's Kitchen",
"ranked": true
},
{
"id": "Original Breakfast House",
"ranked": false
},
{
"id": "Angry Crab Shack",
"ranked": false
},
{
"id": "Ticoz Latin Kitchen",
"ranked": false
},
{
"id": "The Original Carolina's Mexican Food",
"ranked": false
},
{
"id": "Pizza People Pub",
"ranked": false
},
{
"id": "32 Shea",
"ranked": false
},
{
"id": "Ollie Vaughn's",
"ranked": false
},
{
"id": "Rosita's Place",
"ranked": false
},
{
"id": "Thai Delight",
"ranked": false
},
{
"id": "Ranch House Grille",
"ranked": false
},
{
"id": "Popo's Mexican Food",
"ranked": false
},
{
"id": "Times Square Pizzeria",
"ranked": false
}
]
}
The returned list of restaurants shows Asian restaurants bubbling to the top for this user, as they have previously engaged with similar restaurant categories, along with engaging with other restaurants which have users with similar tastes. So now instead of showing generic search results to all of your users, you can re-sort your results in real-time to provide personalized results. Because this data set is limited for the demo, some of the restaurants don't have enough relevant data to change the rank, which is why they are listed as "ranked: false" meaning they are not being affected by the personalization.
You can read the reference docs for this endpoint here:
Get Sorted Content (for user)
Try it yourself
If you've just being reading through this tutorial, first congrats making it to the end! Hopefully you a better sense of what Pipeless can do, though we still encourage you try out some requests on the demo dataset and familiarize yourself with the different values and optional parameters. Again, this is a limited pared down dataset, so you might get some limited responses that you are less likely to encounter with your own full data.
For more details on the parameters of each algo endpoint, check out the reference docs:
Read API Reference Docs
Ready to start your own app?
Once you're done with the demo app, start fresh with your own new app. For a free plan, there is a limit to only one free app per account, so you will need to delete the demo app first. You can learn about deleting an app here..
If you're not sure what calls and storage plan is right for your product, you can also read about estimating usage here.
Updated almost 2 years ago