استفاده از MongoDB Atlas به عنوان پایگاه داده وکتور

استفاده از MongoDB Atlas به عنوان پایگاه داده وکتور

mongodb, embeddings
preview

این نوت‌بوک نحوه ساخت یک اپلیکیشن جستجوی معنایی در آرشیوی از فیلم‌ها را با استفاده از جستجوی برداری MongoDB Atlas نشان می‌دهد.

مرحله 1: تنظیم محیط #

دو پیش‌نیاز برای ساخت این اپلیکیشن وجود دارد:

  1. کلاستر MongoDB Atlas: برای ایجاد یک کلاستر رایگان MongoDB Atlas، ابتدا باید یک حساب کاربری MongoDB Atlas ایجاد کنید. برای این کار به وب‌سایت MongoDB Atlas مراجعه کرده و روی “Register” کلیک کنید. به داشبورد MongoDB Atlas بروید و کلاستر خود را تنظیم کنید. برای استفاده از اپراتور $vectorSearch باید MongoDB Atlas نسخه 6.0.11 یا بالاتر را اجرا کنید. لطفا پس از ساخت کلاستر خود اطلاعات ضروری مثل آدرس آی‌پی٬ نام کاربری و رمز عبور را در جایی ذخیره کنید. اگر به کمک بیشتری برای شروع نیاز دارید، به آموزش MongoDB Atlas مراجعه کنید.

  2. کلید Gilas API: برای این کار ابتدا یک حساب کاربری جدید بسازید یا اگر صاحب حساب کاربری هستید وارد پنل کاربری خود شوید. سپس، به صفحه کلید API بروید و با کلیک روی دکمه “ساخت کلید API” یک کلید جدید برای دسترسی به Gilas API بسازید.

1import getpass
2
3MONGODB_ATLAS_CLUSTER_URI = getpass.getpass("MongoDB Atlas Cluster URI:")
4GILAS_API_KEY = getpass.getpass("Gilas API Key:")
MongoDB Atlas Cluster URI:··········
Gilas API Key:··········

توجه: پس از اجرای مرحله بالا، از شما خواسته می‌شود که اطلاعات کاربری را وارد کنید.

برای این آموزش، از مجموعه داده نمونه MongoDB استفاده خواهیم کرد. ما از پایگاه داده “sample_mflix” استفاده خواهیم کرد که شامل مجموعه‌ای از فیلم‌هاست که هر سند آن شامل فیلدهایی مانند عنوان، خلاصه، ژانرها، بازیگران، کارگردانان و غیره است.

 1import openai
 2import pymongo
 3
 4client = pymongo.MongoClient(MONGODB_ATLAS_CLUSTER_URI)
 5db = client.sample_mflix
 6collection = db.movies
 7
 8openai.api_key = OPENAI_API_KEY
 9
10ATLAS_VECTOR_SEARCH_INDEX_NAME = "default"
11EMBEDDING_FIELD_NAME = "embedding_openai_nov19_23"

مرحله 2: تنظیم تابع تولید embeddings #

برای ساخت بردار امبدینگ از یک متن تابع زیر را می‌نویسیم.

 1from openai import OpenAI
 2import os
 3
 4client = OpenAI(
 5    api_key=os.environ.get(("GILAS_API_KEY", "<کلید API خود را اینجا بسازید https://dashboard.gilas.io/apiKey>")), 
 6    base_url="https://api.gilas.io/v1/" # Gilas APIs
 7)
 8
 9model = "text-embedding-3-small"
10def generate_embedding(text: str) -> list[float]:
11    return client.embeddings.create(input=user_query,
12                                            model="text-embedding-3-small",
13                                            )["data"][0]['embedding']

مرحله 3: ایجاد و ذخیره embeddings #

هر سند در مجموعه داده نمونه sample_mflix.movies مربوط به یک فیلم است؛ ما عملیاتی را اجرا خواهیم کرد تا یک vector embedding برای داده‌های موجود در فیلد “plot” ایجاد کرده و آن را در پایگاه داده ذخیره کنیم.

 1from pymongo import ReplaceOne
 2
 3### به‌روزرسانی مجموعه با `embeddings`
 4requests = []
 5
 6for doc in collection.find({'plot':{"$exists": True}}).limit(500):
 7  doc[EMBEDDING_FIELD_NAME] = generate_embedding(doc['plot'])
 8  requests.append(ReplaceOne({'_id': doc['_id']}, doc))
 9
10collection.bulk_write(requests)

پس از اجرای موارد بالا، اسناد در مجموعه “movies” شامل یک فیلد اضافی به نام “embedding” خواهند بود، همانطور که توسط متغیر EMBEDDDING_FIELD_NAME تعریف شده است، علاوه بر فیلدهای موجود مانند عنوان، خلاصه، ژانرها، بازیگران، کارگردانان و غیره.

توجه: ما این کار را به 500 سند محدود کرده‌ایم تا زمان صرفه‌جویی شود. اگر می‌خواهید این کار را بر روی کل مجموعه داده 23,000+ سند در پایگاه داده sample_mflix انجام دهید، کمی زمان خواهد برد. به طور جایگزین، می‌توانید از مجموعه sample_mflix.embedded_movies استفاده کنید که شامل فیلد plot_embedding از پیش پر شده است که embeddings ایجاد شده با استفاده از مدل text-embedding-3-small OpenAI را شامل می‌شود و می‌توانید از آن با ویژگی جستجوی برداری Atlas Search استفاده کنید.

مرحله 4: ایجاد یک ایندکس جستجوی برداری #

ما یک ایندکس جستجوی برداری Atlas بر روی این مجموعه ایجاد خواهیم کرد که به ما امکان انجام جستجوی Approximate KNN را می‌دهد که جستجوی معنایی را قدرت می‌بخشد. ما دو روش برای ایجاد این ایندکس را نشان خواهیم داد - رابط کاربری Atlas و استفاده از درایور پایتون MongoDB.

در صورت علاقه می‌توانید مستندات مربوط به ایجاد یک ایندکس جستجوی برداری را مطالعه کنید.

اکنون به رابط کاربری Atlas بروید و یک ایندکس جستجوی برداری Atlas با استفاده از مراحل توضیح داده شده اینجا ایجاد کنید. فیلد ‘dimensions’ با مقدار 1536، مربوط به text-embedding-ada002 openAI است.

از تعریف زیر در ویرایشگر JSON در رابط کاربری Atlas استفاده کنید.

{
  "mappings": {
    "dynamic": true,
    "fields": {
      "embedding": {
        "dimensions": 1536,
        "similarity": "dotProduct",
        "type": "knnVector"
      }
    }
  }
}

(اختیاری) به طور جایگزین، می‌توانیم از درایور pymongo برای ایجاد این ایندکس‌های جستجوی برداری به صورت برنامه‌ریزی شده استفاده کنیم. دستور پایتون داده شده در سلول زیر ایندکس را ایجاد خواهد کرد (این فقط برای نسخه‌های اخیر درایور پایتون MongoDB و کلاستر Atlas نسخه 7.0+ کار می‌کند).

 1collection.create_search_index(
 2    {"definition":
 3        {"mappings": {"dynamic": True, "fields": {
 4            EMBEDDING_FIELD_NAME : {
 5                "dimensions": 1536,
 6                "similarity": "dotProduct",
 7                "type": "knnVector"
 8                }}}},
 9     "name": ATLAS_VECTOR_SEARCH_INDEX_NAME
10    }
11)

مرحله 5: جستجوی داده‌های خود #

نتایج جستجو در اینجا فیلم‌هایی را پیدا می‌کند که دارای خلاصه‌های معنایی مشابه با متن موجود در رشته جستجو هستند. این روش جستجو تفاوت های بسیار زیادی با جستجوی روش جستجوی کلمات کلیدی دارد و به کاربر این اجازه را می‌دهد که به استفاده از زبان طبیعی و تعریف آنجه در ذهن دارد در میان داده‌ها جستجو کند.

(اختیاری) مستندات: اجرای جستجوی برداری

 1def query_results(query, k):
 2  results = collection.aggregate([
 3    {
 4        '$vectorSearch': {
 5            "index": ATLAS_VECTOR_SEARCH_INDEX_NAME,
 6            "path": EMBEDDING_FIELD_NAME,
 7            "queryVector": generate_embedding(query),
 8            "numCandidates": 50,
 9            "limit": 5,
10        }
11    }
12    ])
13  return results

حال می‌توان با نوشتن توضیحاتی در مورد یک فیلم آن را در آرشیو فیلم‌ها جستجو کرد.

1query="imaginary characters from outerspace at war with earthlings"
2movies = query_results(query, 5)
3
4for movie in movies:
5    print(f'Movie Name: {movie["title"]},\nMovie Plot: {movie["plot"]}\n')