Give me another drink, Cocktail Recommender2

I imagine a Cocktail Recommender system that feels like talking to a bartender.


If you share a similar dream with Anonymous, I have some good news for you🍹 ​

Photo by Helena Lopes on Unsplash

Cocktail Recommender 2 is the next version of Cocktail Recommender system. It recommends cocktails to its users based on a given cocktail name (i.e. Margarita), ingredients (i.e. orange juice, gin, etc.) and/or description (i.e. simple, tropical, refreshing cocktail with rum and cranberry).

It is deployed on using Streamlit and Heroku.


This version (Version 2) is designed to fix the shortcomings of the first version. The first version uses simple TF-IDF vectorizer to convert ingredients in the text form to numerical values and it is really good at recommending cocktails based on “ingredients”. However, it fails to perform well when a “description” is provided such as “refreshing, fruity, sweet”. You can read about the first version of the system here.

In this version, pre-trained BERT Large Universal Sentence Encoder model is used which is deployed using AWS Sagemaker Jumpstart. It was trained using ‘Wikipedia and BookCorpus datasets’ and it can be found at TensorFlow Hub. The pre-trained transformer model converts any text input (name, ingredients, and/or description of a cocktail) to a vector having dimensions of (1024,1). Cosine similarities of vectorized cocktail descriptions are calculated to compare semantic similarities between the cocktails.

The given cocktail description text is converted to numerical values, then semantic similarities between all the cocktails in the database and the description are calculated.

When a user provides a cocktail description, a bar chart showing cocktail names with corresponding similarities comes up.

Getting the Data

The data were collected (1020 cocktails with descriptions, ingredients and preparation instructions) from using python library Beautiful Soup. While scraping, I paid attention not to damage the website. time.sleep(random.randint(10,20)) function was used in between of get requests to make sure that I don’t send too frequent requests to the website.

Why did I choose this website for web scraping?

* There isn’t any statement prohibiting web scraping in the website, at the time of building the system. Privacy Policy and robots.txt of the website were checked for any restriction regarding web scraping. Unfortunately, Terms of Use of the website couldn’t be found.

* This website has amazing cocktail descriptions that could be helpful for the recommender system.

* Their data are public. The data aren’t behind a paywall and everyone having an internet access can reach them. In order to respect their intellectual property regarding the cocktail descriptions, contents of the cocktails aren’t displayed in our web app. Instead, directing links to their website are provided.


First, BERT Large Universal Sentence Encoder model is deployed to an endpoint using AWS Sagemaker. This endpoint was used to transform all the descriptions of the cocktails to numerical values. These embeddings were stored along with the cocktails.

Second, pairwise cosine similarities between all the cocktails were calculated and stored in a similarity matrix.

Third, a Lambda function that invokes the model endpoint was deployed.

Fourth, a REST API was created using Amazon API Gateway. This enables us to send POST requests to our Lambda function in a secure way.

Cocktail Recommender 2 Schematic

Whenever a user provides a cocktail name, the system checks if the given name is present in the database. If it is present in the database, the system retrieves the most similar cocktails to the given cocktail by checking the pre-computed similarity matrix.

If a user provides a description, then this description is sent to the Lambda function through the REST API. The Lambda function invokes the model endpoint with the cocktail description, hence the model transforms the text description input to numerical values. Lastly, pairwise cosine similarities between the vectorized input description and vectorized cocktails are calculated. The cocktails that are most similar to the given description are recommended to the user.

Strengths and Weaknesses of the System

Although this version uses more advanced and complex model for text embedding, it still has some shortcomings. Let’s discuss the strengths and weaknesses of the system by doing some experiments.

Photo by Ash Edmonds on Unsplash


The recommender system works best when we provide long descriptions. For example, when we input a description such as “citrus, refreshing cocktail with tequila”, it is able to recommend citrus cocktails even if the retrieved cocktails don’t have word “citrus” in their descriptions. This shows that the system can understand that orange and grapefruit are citrus ingredients.


The recommender system sometimes fails to retrieve related cocktails from the cocktail database, when we provide only ingredients. This is a major weakness compared to the first version. For example when we type ‘strawberry’ to the search engine, we see that none of the recommended cocktails include strawberry, even if cocktails with strawberry are present in the database. However, when we type ‘cranberry’, we see that the majority of the recommended cocktails have cranberry.


After realizing the system’s weakness, we also created embeddings only using cocktails’ ingredients. This enhanced the performance of the system for the simple queries including only ingredients. However, the first version still outperforms the second version when simple queries are provided.


It was really interesting to test BERT model for this task. This embedding technique enables us to discover more cocktails by providing a description. It sometimes feels like asking for recommendations to a real bartender but it still needs some improvements.

Photo by Adam Jaime on Unsplash
  • One way to improve the system could be mixing the recommendations coming from two different vectorization techniques; TF-IDF and BERT Large Universal Sentence Encoder. In this way, we could get the best recommendations for different cases. If a user is looking for specific ingredients in a cocktail, the TF-IDF-based system provides the best recommendations, while the BERT-based system provides the best results when a user provides a long description involving human perception, such as “refreshing, citrus, sweet”.
  • Another way to boost the performance of the system could be fine tuning the BERT model with cleaned cocktail descriptions. The cocktail descriptions that we used here are very informative. However, some of them have unrelated information about the taste of a cocktail. This could introduce some noise to the embeddings leading to decrease in overall system performance.
  • We can experiment further with the system to learn more about user experience. In this way, we can detect more problems and learn how our model fails in different situations. We can use Amazon Mechanical Turk for this and get feedbacks from random users.
  • What do you think about the recommendations you get?
  • Which other techniques or data could be used to improve recommendation performance?

All the codes and data are available on Github.

Hope you enjoy this post! I would be happy to receive your feedback, you can contact me on Linkedin.



I would like to thank Patryk Oleniuk for helpful post about quickly deploying ML models to web. I have used the template mentioned in the post.

I would also like to thank for not prohibiting scraping their data.



Assistant Specialist @UCSF

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store