Создайте рекомендательную систему фильмов с Milvus и Python
Эта статья была первоначально опубликована в The New Stack и перепечатывается здесь с разрешения.
Используйте инструменты с открытым исходным кодом, чтобы помогать людям находить фильмы, которые им может быть интересно посмотреть.
Рекомендательные системы или рекомендательные движки — это системы фильтрации информации, цель которых — прогнозировать и предлагать вещи, которые могут заинтересовать пользователей. К таким объектам относятся продукты, услуги и контент, например фильмы, книги, музыка или новостные статьи.
Существуют различные типы рекомендательных систем, такие как коллаборативная фильтрация, фильтрация на основе контента, гибридные рекомендательные системы и векторные рекомендательные системы. Векторные системы используют векторное пространство, чтобы находить (рекомендовать) ближайшие элементы в базе данных. Существуют разные способы хранения этих векторов; один из самых эффективных — использование Milvus векторной базы данных с открытым исходным кодом. Эта база данных отличается высокой гибкостью, скоростью и надежностью и позволяет добавлять, удалять, обновлять и выполнять почти в реальном времени поиск векторов в масштабе триллионов байтов.
В этой статье объясняется, как создать рекомендатель фильмов с помощью Milvus и Python. Эта система будет использовать SentenceTransformers для преобразования текстовой информации в векторы и хранения этих векторов в Milvus. Milvus позволяет пользователям искать фильм в базе данных на основе предоставленной ими текстовой информации.
Изображение для статьи от Tima Miroshnichenko на Pexels
Настройка среды
Для этой статьи вам потребуется установить следующее:
Python Package Manager (PIP) для установки пакетов
Jupyter Notebook для написания кода
Система как минимум с 32 ГБ ОЗУ или учетная запись Zilliz Cloud
Требования Python
Вам также нужно установить набор библиотек, которые понадобятся на протяжении всего этого руководства. Установите библиотеки с помощью PIP:
$ python -m pip install pymilvus pandas sentence_transformers kaggle
Хранилище данных векторов (Milvus)
Вы будете использовать векторную базу данных Milvus для хранения эмбеддингов, которые сгенерируете с использованием описаний фильмов. Набор данных относительно большой, по крайней мере для сервера, работающего на персональном компьютере. Поэтому, возможно, вы захотите использовать экземпляр Zilliz Cloud для хранения этих векторов.
Если вы предпочитаете остаться с локальным экземпляром, вы можете скачать конфигурацию docker-compose и запустить ее с помощью:
$ wget https://github.com/milvus-io/milvus/releases/download/v2.3.0/milvus-standalone-docker-compose.yml -O docker-compose.yml
$ docker-compose up -d
Теперь у вас есть все необходимое, чтобы создать собственную рекомендательную систему фильмов с Milvus.
Сбор и предварительная обработка данных
Для этого проекта вы будете использовать Movies Dataset с Kaggle, который содержит метаданные для 45 000 фильмов. Вы можете скачать этот набор данных напрямую или использовать Kaggle API, чтобы скачать набор данных с помощью Python. Чтобы сделать это с Python, вам нужно скачать файл kaggle.json из раздела профиля на Kaggle.com и поместить его в место, где API сможет его найти.
Далее настройте некоторые переменные окружения для аутентификации Kaggle. Для этого вы можете открыть Jupyter Notebook и написать следующие строки кода:
%env KAGGLE_USERNAME=username
%env KAGGLE_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
%env TOKENIZERS_PARALLELISM=true
После этого вы можете использовать Python-зависимость Kaggle, чтобы скачать набор данных с Kaggle:
# import kaggle dependency
import kaggle
kaggle.api.authenticate()
kaggle.api.dataset_download_files('rounakbanik/the-movies-dataset', path='dataset', unzip=True)
После скачивания набора данных вы можете использовать метод read_csv() из pandas, чтобы прочитать набор данных:
# import pandas
import pandas as pd
# read csv data
movies=pd.read_csv('dataset/movies_metadata.csv',low_memory=False)
# check shape of data
movies.shape
Форма набора данных
Изображение показывает, что у вас есть 45 466 записей с 24 столбцами метаданных. Проверьте все эти столбцы метаданных с помощью:
# check column names
movies.columns
Столбцы набора данных
Есть много столбцов, которые вам не нужны для создания рекомендательной системы. Вы можете отфильтровать необходимые столбцы с помощью:
# filter required columns
trimmed_movies = movies[["id", "title", "overview", "release_date", "genres"]]
trimmed_movies.head(5)
Необходимые столбцы
Также некоторые поля в данных отсутствуют, поэтому удалите эти строки, чтобы получить чистый набор данных:
unclean_movies_dict = trimmed_movies.to_dict('records')
print('{} movies'.format(len(unclean_movies_dict)))
movies_dict = []
for movie in unclean_movies_dict:
if movie["overview"] == movie["overview"] and movie["release_date"] == movie["release_date"] and movie["genres"] == movie["genres"] and movie["title"] == movie["title"]:
movies_dict.append(movie)
Подключение к Milvus
Теперь, когда у вас есть все необходимые столбцы, подключитесь к Milvus, чтобы начать загрузку данных. Чтобы подключиться к облачному экземпляру Milvus, вам понадобятся Uniform Resource Identifier (URI) и токен, которые вы можете скачать из панели управления Zilliz Cloud.
Панель управления Zilliz
Когда у вас будут URI и API-ключ, вы можете использовать метод connect() из PyMilvus, чтобы подключиться к серверу Milvus:
# import milvus dependency
from pymilvus import *
# connect to milvus
milvus_uri="YOUR_URI"
token="YOUR_API_TOKEN"
connections.connect("default", uri=milvus_uri, token=token)
print("Connected!")
Генерация эмбеддингов для фильмов
Теперь пришло время рассчитать эмбеддинги для текстовых данных в наборе данных фильмов. Сначала создайте объект collection, который будет хранить ID фильма и эмбеддинги для текстовых данных. Также создайте поле index, чтобы сделать поиск более эффективным:
COLLECTION_NAME = 'film_vectors'
PARTITION_NAME = 'Movie'
# Here's our record schema
"""
"title": Film title,
"overview": description,
"release_date": film release date,
"genres": film generes,
"embedding": embedding
"""
id = FieldSchema(name='title', dtype=DataType.VARCHAR, max_length=500, is_primary=True)
field = FieldSchema(name='embedding', dtype=DataType.FLOAT_VECTOR, dim=384)
schema = CollectionSchema(fields=[id, field], description="movie recommender: film vectors", enable_dynamic_field=True)
if utility.has_collection(COLLECTION_NAME): # drop the same collection created before
collection = Collection(COLLECTION_NAME)
collection.drop()
collection = Collection(name=COLLECTION_NAME, schema=schema)
print("Collection created.")
index_params = {
"index_type": "IVF_FLAT",
"metric_type": "L2",
"params": {"nlist": 128},
}
collection.create_index(field_name="embedding", index_params=index_params)
collection.load()
print("Collection indexed!")
Теперь, когда у вас есть индексированная коллекция, создайте функцию для генерации эмбеддингов для текста. Хотя overview является основным столбцом, используемым для генерации эмбеддингов, вы также будете использовать информацию genre и release data вместе с overview, чтобы сделать данные более логичными.
Чтобы сгенерировать эмбеддинги, используйте SentenceTransformer:
from sentence_transformers import SentenceTransformer
import ast
# function to extract the text from genre column
def build_genres(data):
genres = data['genres']
genre_list = ""
entries= ast.literal_eval(genres)
genres = ""
for entry in entries:
genre_list = genre_list + entry["name"] + ", "
genres += genre_list
genres = "".join(genres.rsplit(",", 1))
return genres
# create an object of SentenceTransformer
transformer = SentenceTransformer('all-MiniLM-L6-v2')
# function to generate embeddings
def embed_movie(data):
embed = "{} Released on {}. Genres are {}.".format(data["overview"], data["release_date"], build_genres(data))
embeddings = transformer.encode(embed)
return embeddings
Эта функция использует метод build_genres(), чтобы очистить столбец genre и извлечь из него текст. Затем она создает объект SentenceTransformer, который помогает генерировать эмбеддинги из текста. Наконец, она использует метод encode() для генерации эмбеддингов с использованием признаков overview, release_date и genre.
Отправка эмбеддингов в Milvus
Теперь вы можете создать эмбеддинги с помощью метода embed_movie(). Этот набор данных слишком велик, чтобы отправить его в Milvus одним оператором insert, но отправка строк данных по одной создала бы ненужный сетевой трафик и заняла бы слишком много времени. Поэтому вместо этого создайте пакеты данных (например, по 5 000 строк) для отправки в Milvus:
# Loop counter for batching and showing progress
j = 0
batch = []
for movie_dict in movies_dict:
try:
movie_dict["embedding"] = embed_movie(movie_dict)
batch.append(movie_dict)
j += 1
if j % 5 == 0:
print("Embedded {} records".format(j))
collection.insert(batch)
print("Batch insert completed")
batch=[]
except Exception as e:
print("Error inserting record {}".format(e))
pprint(batch)
break
collection.insert(movie_dict)
print("Final batch completed")
print("Finished with {} embeddings".format(j))
Примечание: Вы можете подобрать размер пакета в соответствии со своими индивидуальными потребностями и предпочтениями. Кроме того, несколько фильмов не будут обработаны из-за ID, которые невозможно привести к целым числам. Это можно исправить изменением схемы или проверкой их формата.
Отправка эмбеддингов в Milvus
Рекомендация новых фильмов с помощью Milvus
Теперь вы можете использовать функциональность векторного поиска Milvus почти в реальном времени, чтобы получить близкое совпадение фильмов, соответствующих критериям зрителя. Для этого создайте две разные функции:
embed_search(): Вам нужен transformer, чтобы преобразовать поисковую строку пользователя в эмбеддинг. Эта функция принимает критерии зрителя и передает их тому же transformer, который вы использовали для заполнения Milvus.
search_for_movies(): Эта функция выполняет фактический векторный поиск, используя другую функцию для поддержки.
# load collection memory before search
collection.load()
# Set search parameters
topK = 5
SEARCH_PARAM = {
"metric_type":"L2",
"params":{"nprobe": 20},
}
# convert search string to embeddings
def embed_search(search_string):
search_embeddings = transformer.encode(search_string)
return search_embeddings
# search similar embeddings for user's query
def search_for_movies(search_string):
user_vector = embed_search(search_string)
return collection.search([user_vector],"embedding",param=SEARCH_PARAM, limit=topK, expr=None, output_fields=['title', 'overview'])
Приведенный выше код определяет параметры topK для получения пяти наиболее похожих векторов, metric_type как L2 (квадрат евклидова расстояния), который вычисляет расстояние между двумя векторами, и nprobe, который указывает количество кластерных единиц для поиска. Он также реализует различные функции для получения похожих векторов из пользовательского запроса (рекомендации).
Наконец, используйте функцию search_for_movies(), чтобы рекомендовать фильмы на основе поисковой строки пользователя:
from pprint import pprint
search_string = "A comedy from the 1990s set in a hospital. The main characters are in their 20s and are trying to stop a vampire."
results = search_for_movies(search_string)
# check results
for hits in iter(results):
for hit in hits:
print(hit.entity.get('title'))
print(hit.entity.get('overview'))
print("-------------------------------")
Рекомендовать фильмы
Используя функцию векторного поиска Milvus, код рекомендует пять наиболее похожих фильмов на основе запроса пользователя. Вот и всё: теперь вы создали собственную систему рекомендаций фильмов с использованием Milvus.
Заключение
После прочтения этой статьи вы знаете, что такое рекомендательная система на основе векторов и как создать систему рекомендаций фильмов с помощью Milvus. Milvus помогает создать эффективную и масштабируемую систему рекомендаций фильмов. Используя векторное хранилище и поиск по сходству, Milvus обладает большим потенциалом для предоставления персонализированных рекомендаций, повышения вовлеченности пользователей и демонстрации роли передовых моделей на основе векторов в современных рекомендательных системах. Вы можете узнать больше об этом на сайте Milvus.
Читать далее

VDBBench Adds Cost-Aware Benchmarking for Vector Databases
Compare Zilliz Cloud, Pinecone, and turbopuffer with VDBBench cost-aware vector database benchmarks across latency, freshness, multitenancy, and cold starts.

Notion's Vector Search Is Excellent. Their Next Problem Is Harder.
Notion solved vector search scaling in two years. The next bottleneck — offline context engineering, unified data, and the real-time/offline gap — is harder.

Vector Databases vs. Graph Databases
Use a vector database for AI-powered similarity search; use a graph database for complex relationship-based queries and network analysis.



