Milvus와 Python으로 영화 추천 엔진 만들기
이 글은 원래 The New Stack에 게시되었으며, 허가를 받아 여기에 다시 게시되었습니다.
오픈 소스 도구를 사용하여 사람들이 관심을 가질 만한 영화를 찾도록 도와보세요.
추천 시스템 또는 추천 엔진은 사용자가 관심을 가질 만한 것을 예측하고 제안하는 것을 목표로 하는 정보 필터링 시스템입니다. 이러한 항목에는 제품, 서비스, 그리고 영화, 책, 음악 또는 뉴스 기사와 같은 콘텐츠가 포함됩니다.
추천 시스템에는 협업 필터링, 콘텐츠 기반 필터링, 하이브리드 추천 시스템, 벡터 기반 추천 시스템 등 다양한 유형이 있습니다. 벡터 기반 시스템은 벡터 공간을 사용하여 데이터베이스에서 가장 가까운 항목을 찾습니다(추천합니다). 이러한 벡터를 저장하는 방법은 다양하며, 가장 효율적인 방법 중 하나는 Milvus 오픈 소스 벡터 데이터베이스를 사용하는 것입니다. 이 데이터베이스는 매우 유연하고 빠르며 안정적이고, 조 단위 바이트 규모의 벡터 추가, 삭제, 업데이트 및 거의 실시간 검색을 지원합니다.
이 글에서는 Milvus와 Python을 사용하여 영화 추천기를 구축하는 방법을 설명합니다. 이 시스템은 SentenceTransformers를 사용해 텍스트 정보를 벡터로 변환하고 이러한 벡터를 Milvus에 저장합니다. Milvus를 사용하면 사용자가 제공한 텍스트 정보를 기반으로 데이터베이스에서 영화를 검색할 수 있습니다.
Pexels의 Tima Miroshnichenko가 제공한 대표 이미지
환경 설정
이 글을 따라 하려면 다음 요구 사항이 설치되어 있어야 합니다.
패키지 설치를 위한 Python Package Manager (PIP)
코드 작성을 위한 Jupyter Notebook
최소 32GB RAM이 있는 시스템 또는 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로 직접 영화 추천 시스템을 구축하는 데 필요한 모든 요구 사항을 갖추었습니다.
데이터 수집 및 전처리
이 프로젝트에서는 45,000개 영화의 메타데이터가 포함된 Movies Dataset을 Kaggle에서 사용합니다. 이 데이터셋은 직접 다운로드하거나 Kaggle API를 사용해 Python으로 다운로드할 수 있습니다. Python으로 수행하려면 Kaggle.com의 profile section에서 kaggle.json 파일을 다운로드한 뒤 API가 찾을 수 있는 위치에 넣어야 합니다.
다음으로, Kaggle 인증을 위한 몇 가지 환경 변수를 설정합니다. 이를 위해 Jupyter Notebook을 열고 다음 코드 줄을 작성할 수 있습니다:
%env KAGGLE_USERNAME=username
%env KAGGLE_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
%env TOKENIZERS_PARALLELISM=true
완료되면 Kaggle의 Python dependency를 사용해 Kaggle에서 데이터셋을 다운로드할 수 있습니다:
# import kaggle dependency
import kaggle
kaggle.api.authenticate()
kaggle.api.dataset_download_files('rounakbanik/the-movies-dataset', path='dataset', unzip=True)
데이터셋이 다운로드되면 pandas의 read_csv() 메서드를 사용해 데이터셋을 읽을 수 있습니다:
# 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
데이터셋 형태
이미지는 24개의 메타데이터 열을 가진 45,466개의 레코드가 있음을 보여줍니다. 다음으로 이러한 모든 메타데이터 열을 확인하세요:
# 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 cloud 인스턴스에 연결하려면 Zilliz Cloud 대시보드에서 다운로드할 수 있는 Uniform Resource Identifier (URI)와 token이 필요합니다.
Zilliz 대시보드
URI와 API key가 준비되면 PyMilvus의 connect() 메서드를 사용해 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!")
영화 임베딩 생성
이제 영화 데이터셋의 텍스트 데이터에 대한 임베딩을 계산할 차례입니다. 먼저 텍스트 데이터의 영화 ID와 임베딩을 저장할 collection 객체를 만듭니다. 또한 검색을 더 효율적으로 만들기 위해 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가 임베딩을 생성하는 데 사용되는 기본 열이지만, 데이터를 더 논리적으로 만들기 위해 overview와 함께 genre 및 release data 정보도 사용합니다.
임베딩을 생성하려면 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() 메서드를 사용하여 임베딩을 만들 수 있습니다. 이 데이터셋은 단일 insert 문으로 Milvus에 보내기에는 너무 크지만, 데이터 행을 한 번에 하나씩 보내면 불필요한 네트워크 트래픽이 발생하고 시간이 너무 많이 추가됩니다. 따라서 대신 Milvus로 보낼 데이터 배치(예: 5,000행)를 만드세요.
# 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가 필요합니다. 이 함수는 시청자의 기준을 받아 Milvus를 채우는 데 사용한 동일한 transformer에 전달합니다.
search_for_movies(): 이 함수는 지원을 위해 다른 함수를 사용하여 실제 벡터 검색을 수행합니다.
# load collection memory before search
collection.load()
# 검색 매개변수 설정
topK = 5
SEARCH_PARAM = {
"metric_type":"L2",
"params":{"nprobe": 20},
}
# 검색 문자열을 임베딩으로 변환
def embed_search(search_string):
search_embeddings = transformer.encode(search_string)
return search_embeddings
# 사용자의 쿼리에 대해 유사한 임베딩 검색
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'])
위 코드는 상위 5개의 유사 벡터를 얻기 위한 매개변수 topK, 두 벡터 간의 거리를 계산하는 L2 (제곱 유클리드)인 metric_type, 그리고 검색할 클러스터 단위 수를 나타내는 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)
# 결과 확인
for hits in iter(results):
for hit in hits:
print(hit.entity.get('title'))
print(hit.entity.get('overview'))
print("-------------------------------")
영화 추천
Milvus의 벡터 검색 기능을 사용하면, 이 코드는 사용자의 쿼리를 기반으로 상위 5개의 유사한 영화를 추천합니다. 이것으로 끝입니다: 이제 Milvus를 사용하여 자신만의 영화 추천 시스템을 구축했습니다.
결론
이 글을 읽고 나면, 벡터 기반 추천 시스템이 무엇인지와 Milvus로 영화 추천 시스템을 만드는 방법을 알게 됩니다. Milvus는 효율적이고 확장 가능한 영화 추천 시스템 구축을 돕습니다. 벡터 저장소와 유사도 검색을 활용함으로써, Milvus는 개인화된 추천을 가능하게 하고, 사용자 참여를 향상시키며, 현대 추천 시스템에서 고급 벡터 기반 모델의 역할을 보여주는 데 큰 잠재력을 가지고 있습니다. 자세한 내용은 Milvus 웹사이트에서 확인할 수 있습니다.
계속 읽기

Zilliz Cloud Now Available in AWS Europe (Ireland)
Zilliz Cloud launches in AWS eu-west-1 (Ireland) — bringing low-latency vector search, EU data residency, and full GDPR-ready infrastructure to European AI teams. Now live across 30 regions on five cloud providers.

Legal Document Analysis: Harnessing Zilliz Cloud's Semantic Search and RAG for Legal Insights
Enhance legal document analysis with Zilliz Cloud’s Semantic Search and RAG. Improve accuracy, efficiency, and scalability for contracts, case law, and compliance.

Selecting the Right ETL Tools for Unstructured Data to Prepare for AI
Learn the right ETL tools for unstructured data to power AI. Explore key challenges, tool comparisons, and integrations with Milvus for vector search.



