{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"# Recommendation Systems: Two Tower Deep Learning Models with RedisVL\n",
"\n",
""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Recommendation systems are a common application of machine learning and serve many industries from e-commerce to music streaming platforms.\n",
"\n",
"There are many different architectures that can be followed to build a recommendation system. In previous example notebooks we demonstrated two common approaches that leverage different methods. Our first showed how to do [content filtering with RedisVL](content_filtering.ipynb) where an item's underlying features determine what gets recommended.\n",
"Next, we showcased how RedisVL can be used to build a [collaborative filtering recommender](collaborative_filtering.ipynb), which leverages users' ratings of items to create personalized recommendations. Before continuing with this notebook we encourage you to start with the previous two.\n",
"\n",
"In this notebook we'll demonstrate how to build a [two tower recommendation system](https://cloud.google.com/blog/products/ai-machine-learning/scaling-deep-retrieval-tensorflow-two-towers-architecture)\n",
"and compare it to architectures we've seen before."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To mix things up a bit, instead of using our movies dataset like the previous two examples, we'll look at brick & mortar restaurants in San Francisco as our items to recommend."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Environment Setup"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%pip install -q redis \"redisvl>=0.4.1\" pandas torch requests scikit-learn"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Install Redis Stack\n",
"\n",
"Later in this tutorial, Redis will be used to store, index, and query vector\n",
"embeddings. **We need to make sure we have a Redis instance available.**"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Redis in Colab\n",
"Use the shell script below to download, extract, and install [Redis Stack](https://redis.io/docs/getting-started/install-stack/) directly from the Redis package archive."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# NBVAL_SKIP\n",
"%%sh\n",
"curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg\n",
"echo \"deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main\" | sudo tee /etc/apt/sources.list.d/redis.list\n",
"sudo apt-get update > /dev/null 2>&1\n",
"sudo apt-get install redis-stack-server > /dev/null 2>&1\n",
"redis-stack-server --daemonize yes"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Other ways to get Redis\n",
"There are many ways to get the necessary redis-stack instance running\n",
"1. On cloud, deploy a [FREE instance of Redis in the cloud](https://redis.io/try-free/). Or, if you have your\n",
"own version of Redis Enterprise running, that works too!\n",
"2. Per OS, [see the docs](https://redis.io/docs/latest/operate/oss_and_stack/install/install-stack/)\n",
"3. With docker: `docker run -d --name redis-stack-server -p 6379:6379 redis/redis-stack-server:latest`"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Define the Redis Connection URL\n",
"\n",
"By default this notebook connects to the local instance of Redis Stack. **If you have your own Redis Enterprise instance** - replace REDIS_PASSWORD, REDIS_HOST and REDIS_PORT values with your own."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import requests\n",
"import pandas as pd\n",
"import json\n",
"\n",
"# Replace values below with your own if using Redis Cloud instance\n",
"REDIS_HOST = os.getenv(\"REDIS_HOST\", \"localhost\") # ex: \"redis-18374.c253.us-central1-1.gce.cloud.redislabs.com\"\n",
"REDIS_PORT = os.getenv(\"REDIS_PORT\", \"6379\") # ex: 18374\n",
"REDIS_PASSWORD = os.getenv(\"REDIS_PASSWORD\", \"\") # ex: \"1TNxTEdYRDgIDKM2gDfasupCADXXXX\"\n",
"\n",
"# If SSL is enabled on the endpoint, use rediss:// as the URL prefix\n",
"REDIS_URL = f\"redis://:{REDIS_PASSWORD}@{REDIS_HOST}:{REDIS_PORT}\""
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"def fetch_data(file_name):\n",
" dataset_path = 'datasets/two_towers/'\n",
" try:\n",
" with open(dataset_path + file_name, 'r') as f:\n",
" return json.load(f)\n",
" except:\n",
" url = 'https://redis-ai-resources.s3.us-east-2.amazonaws.com/recommenders/datasets/two-towers/'\n",
" r = requests.get(url + file_name)\n",
" if not os.path.exists(dataset_path):\n",
" os.makedirs(dataset_path)\n",
" with open(dataset_path + file_name, 'wb') as f:\n",
" f.write(r.content)\n",
" return json.loads(r.content.decode('utf-8'))"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"we have 147 restaurants in our dataset, with 14700 total reviews\n"
]
}
],
"source": [
"# the original dataset can be found here: https://www.kaggle.com/datasets/jkgatt/restaurant-data-with-100-trip-advisor-reviews-each\n",
"\n",
"restaurant_data = fetch_data('factual_tripadvisor_restaurant_data_all_100_reviews.json')\n",
"\n",
"print(f\"we have {restaurant_data['restaurant_count']} restaurants in our dataset, with {restaurant_data['total_review_count']} total reviews\")\n",
"\n",
"restaurant_data = restaurant_data[\"restaurants\"] # ignore the count fields"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
| \n", " | name | \n", "address | \n", "locality | \n", "latitude | \n", "longitude | \n", "cuisine | \n", "price | \n", "rating | \n", "hours | \n", "parking | \n", "... | \n", "meal_takeout | \n", "meal_cater | \n", "options_healthy | \n", "options_organic | \n", "options_vegetarian | \n", "options_vegan | \n", "options_glutenfree | \n", "options_lowfat | \n", "reviews | \n", "unique_name | \n", "
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | \n", "21st Amendment Brewery & Restaurant | \n", "563 2nd St | \n", "San Francisco | \n", "37.782448 | \n", "-122.392576 | \n", "[Cafe, Pub Food, American, Burgers, Pizza] | \n", "2 | \n", "4.0 | \n", "{'monday': [['11:30', '23:59']], 'tuesday': [[... | \n", "True | \n", "... | \n", "True | \n", "False | \n", "True | \n", "False | \n", "True | \n", "False | \n", "False | \n", "False | \n", "[{'review_website': 'TripAdvisor', 'review_url... | \n", "21st Amendment Brewery & Restaurant 563 2nd St | \n", "
| 1 | \n", "Absinthe Brasserie & Bar | \n", "398 Hayes St | \n", "San Francisco | \n", "37.777083 | \n", "-122.422882 | \n", "[French, Californian, Mediterranean, Cafe, Ame... | \n", "3 | \n", "4.0 | \n", "{'tuesday': [['11:30', '23:59']], 'wednesday':... | \n", "True | \n", "... | \n", "True | \n", "True | \n", "True | \n", "False | \n", "True | \n", "False | \n", "False | \n", "False | \n", "[{'review_website': 'TripAdvisor', 'review_url... | \n", "Absinthe Brasserie & Bar 398 Hayes St | \n", "
| 2 | \n", "Amber India Restaurant | \n", "25 Yerba Buena Ln | \n", "San Francisco | \n", "37.785772 | \n", "-122.404401 | \n", "[Indian, Chinese, Vegetarian, Asian, Pakistani] | \n", "2 | \n", "4.5 | \n", "{'monday': [['11:30', '14:30'], ['17:00', '22:... | \n", "True | \n", "... | \n", "True | \n", "True | \n", "True | \n", "False | \n", "True | \n", "True | \n", "True | \n", "False | \n", "[{'review_website': 'TripAdvisor', 'review_url... | \n", "Amber India Restaurant 25 Yerba Buena Ln | \n", "
| 3 | \n", "Americano | \n", "8 Mission St | \n", "San Francisco | \n", "37.793620 | \n", "-122.392915 | \n", "[Italian, American, Californian, Pub Food, Cafe] | \n", "3 | \n", "3.5 | \n", "{'monday': [['6:30', '10:30'], ['11:30', '14:3... | \n", "True | \n", "... | \n", "True | \n", "True | \n", "True | \n", "False | \n", "True | \n", "False | \n", "False | \n", "False | \n", "[{'review_website': 'TripAdvisor', 'review_url... | \n", "Americano 8 Mission St | \n", "
| 4 | \n", "Anchor & Hope | \n", "83 Minna St | \n", "San Francisco | \n", "37.787848 | \n", "-122.398812 | \n", "[Seafood, American, Cafe, Chowder, Californian] | \n", "3 | \n", "4.0 | \n", "{'monday': [['11:30', '14:00'], ['17:30', '22:... | \n", "True | \n", "... | \n", "True | \n", "True | \n", "True | \n", "False | \n", "True | \n", "True | \n", "True | \n", "False | \n", "[{'review_website': 'TripAdvisor', 'review_url... | \n", "Anchor & Hope 83 Minna St | \n", "
5 rows × 33 columns
\n", "| \n", " | user_id | \n", "name | \n", "username | \n", "address | \n", "phone_number | \n", "birthdate | \n", "likes | \n", "account_created_on | \n", "price_bracket | \n", "newsletter | \n", "notifications | \n", "profile_visibility | \n", "data_sharing | \n", "|
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | \n", "2d72a59b-5b12-430f-a5c3-49f8b093cb3d | \n", "Kayla Clark | \n", "debbie11 | \n", "teresa54@example.net | \n", "8873 Thompson Cape\\nOsborneport, NV 34895 | \n", "231.228.4452x008 | \n", "1982-06-10 | \n", "[pizza, pasta, shakes, brunch, bbq, ethiopian,... | \n", "2017-04-18 | \n", "middle | \n", "True | \n", "True | \n", "public | \n", "True | \n", "
| 1 | \n", "034b2b2f-1949-478d-abd6-add4b3275efe | \n", "Leah Hopkins | \n", "williamsanchez | \n", "darryl77@example.net | \n", "353 Kimberly Green\\nRoachfort, FM 34385 | \n", "4669094632 | \n", "1999-03-07 | \n", "[brunch, ethiopian, breweries] | \n", "1970-06-21 | \n", "low | \n", "False | \n", "True | \n", "public | \n", "False | \n", "
| 2 | \n", "5d674492-3026-4cc9-b216-be675cf8d360 | \n", "Mason Patterson | \n", "jamescurtis | \n", "lopezchristopher@example.com | \n", "945 Bryan Locks Suite 200\\nValenzuelaburgh, MI... | \n", "885-983-4573 | \n", "1914-02-14 | \n", "[cocktails, fine dining, pizza, shakes, ethiop... | \n", "2013-03-10 | \n", "high | \n", "False | \n", "False | \n", "friends-only | \n", "False | \n", "
| 3 | \n", "61e17d13-9e18-431f-8f06-208bd0469892 | \n", "Aaron Dixon | \n", "marshallkristen | \n", "becky20@example.org | \n", "42388 Russell Harbors Suite 340\\nNorth Andrewc... | \n", "448.270.3034x583 | \n", "1959-05-01 | \n", "[breweries, cocktails, fine dining] | \n", "1973-12-11 | \n", "middle | \n", "False | \n", "True | \n", "private | \n", "True | \n", "
| 4 | \n", "8cc208b6-0f4f-459c-a8f5-31d3ca6deca6 | \n", "Loretta Eaton | \n", "phatfield | \n", "aaustin@example.org | \n", "PSC 2899, Box 5115\\nAPO AE 79916 | \n", "663-371-4597x72295 | \n", "1923-07-02 | \n", "[brunch, italian, bbq, mexican, burgers, pizza] | \n", "2023-04-29 | \n", "high | \n", "True | \n", "True | \n", "private | \n", "True | \n", "
| \n", " | user_id | \n", "name | \n", "username | \n", "address | \n", "phone_number | \n", "birthdate | \n", "likes | \n", "account_created_on | \n", "newsletter | \n", "... | \n", "pasta | \n", "pizza | \n", "shakes | \n", "price_bracket_high | \n", "price_bracket_low | \n", "price_bracket_middle | \n", "profile_visibility_friends-only | \n", "profile_visibility_private | \n", "profile_visibility_public | \n", "feature_vector | \n", "|
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | \n", "2d72a59b-5b12-430f-a5c3-49f8b093cb3d | \n", "Kayla Clark | \n", "debbie11 | \n", "teresa54@example.net | \n", "8873 Thompson Cape\\nOsborneport, NV 34895 | \n", "231.228.4452x008 | \n", "1982-06-10 | \n", "[pizza, pasta, shakes, brunch, bbq, ethiopian,... | \n", "2017-04-18 | \n", "1 | \n", "... | \n", "1 | \n", "1 | \n", "1 | \n", "0 | \n", "0 | \n", "1 | \n", "0 | \n", "0 | \n", "1 | \n", "[1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, ... | \n", "
| 1 | \n", "034b2b2f-1949-478d-abd6-add4b3275efe | \n", "Leah Hopkins | \n", "williamsanchez | \n", "darryl77@example.net | \n", "353 Kimberly Green\\nRoachfort, FM 34385 | \n", "4669094632 | \n", "1999-03-07 | \n", "[brunch, ethiopian, breweries] | \n", "1970-06-21 | \n", "0 | \n", "... | \n", "0 | \n", "0 | \n", "0 | \n", "0 | \n", "1 | \n", "0 | \n", "0 | \n", "0 | \n", "1 | \n", "[0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, ... | \n", "
| 2 | \n", "5d674492-3026-4cc9-b216-be675cf8d360 | \n", "Mason Patterson | \n", "jamescurtis | \n", "lopezchristopher@example.com | \n", "945 Bryan Locks Suite 200\\nValenzuelaburgh, MI... | \n", "885-983-4573 | \n", "1914-02-14 | \n", "[cocktails, fine dining, pizza, shakes, ethiop... | \n", "2013-03-10 | \n", "0 | \n", "... | \n", "1 | \n", "1 | \n", "1 | \n", "1 | \n", "0 | \n", "0 | \n", "1 | \n", "0 | \n", "0 | \n", "[0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, ... | \n", "
| 3 | \n", "61e17d13-9e18-431f-8f06-208bd0469892 | \n", "Aaron Dixon | \n", "marshallkristen | \n", "becky20@example.org | \n", "42388 Russell Harbors Suite 340\\nNorth Andrewc... | \n", "448.270.3034x583 | \n", "1959-05-01 | \n", "[breweries, cocktails, fine dining] | \n", "1973-12-11 | \n", "0 | \n", "... | \n", "0 | \n", "0 | \n", "0 | \n", "0 | \n", "0 | \n", "1 | \n", "0 | \n", "1 | \n", "0 | \n", "[0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, ... | \n", "
| 4 | \n", "8cc208b6-0f4f-459c-a8f5-31d3ca6deca6 | \n", "Loretta Eaton | \n", "phatfield | \n", "aaustin@example.org | \n", "PSC 2899, Box 5115\\nAPO AE 79916 | \n", "663-371-4597x72295 | \n", "1923-07-02 | \n", "[brunch, italian, bbq, mexican, burgers, pizza] | \n", "2023-04-29 | \n", "1 | \n", "... | \n", "0 | \n", "1 | \n", "0 | \n", "1 | \n", "0 | \n", "0 | \n", "0 | \n", "1 | \n", "0 | \n", "[1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, ... | \n", "
5 rows × 32 columns
\n", "