در دنیای دیجیتال امروزه، استفاده از دیتابیس ها برای ذخیره و مدیریت اطلاعات امری بسیار حیاتی است. یکی از ابزارهایی که به شما کمک میکند تا دیتابیس های خود را با سرعت و کارایی بالا ایجاد کنید، Supabase است. Supabase به عنوان یک پلتفرم متن باز برداری پایگاه داده با PostgreSQL عمل میکند و امکانات بسیاری را برای توسعهدهندگان فراهم میکند.
یکی از عناصر اساسی بسیاری از سیستمهای هوش مصنوعی و ML، مدیریت و دستکاری بردارها و جاسازیها است که دادههای پیچیده و با ابعاد بالا را در قالبی نشان میدهند که ماشینها بتوانند آن را درک و پردازش کنند.
در این مقاله، نحوه کار با بردارها و جاسازیها در زمینه پایگاههای داده را با تمرکز بر Supabase، یک جایگزین منبع باز برای Firebase، بررسی میکنیم. Supabase، با طراحی شیک و مجموعه ای از ویژگی های جامع، قلب ها را در میان توسعه دهندگانی که به دنبال راه حل های Backend با استفاده آسان و مقیاس پذیر هستند، به دست آورده است.
ما نحوه مدیریت دادههای برداری در پایگاه داده PostgreSQL با استفاده از Supabase را بررسی میکنیم و از قابلیتهای مدیریت داده قوی آن بهره میبریم. ما همچنین عمیقتر در ایجاد جاسازیها با استفاده از OpenAI غوطه ور میشویم، که روشی کارآمد برای تبدیل دادههای پیچیده به نمایشهای عددی معنادار ارائه میدهد و ما را قادر میسازد تا از قدرت هوش مصنوعی در برنامههای خود استفاده کنیم.
بردار ها یا vectors چیست؟
در سطح بالا، میتوان یک بردار را به عنوان یک ظرف دانست که مجموعهای از اعداد مرتب را در خود نگه میدارد. در ریاضیات، بردارها اغلب نمایانگر یک نقطه در فضا هستند، جایی که هر عدد به موقعیت در یک بعد مختلف اشاره دارد. در علوم کامپیوتر و به خصوص در یادگیری ماشین، بردارها نقش بسیار مهمتری ایفا میکنند؛ آنها به عنوان نمایش ریاضی دادهها عمل میکنند.
یک مثال ساده را در نظر بگیرید که میخواهیم انواع مختلف میوهها را در یک مدل یادگیری ماشین نمایش دهیم. میتوانیم یک بردار ایجاد کنیم که هر میوه را توصیف میکند، و هر عنصر یا عدد در بردار نمایانگر یک ویژگی یا مشخصه متمایز از میوه باشد.
بیایید یک سیب را به عنوان مثال در نظر بگیریم. یک بردار برای یک سیب ممکن است به این شکل باشد: [1، 150، 8.5، 10]. در این بردار، چهار عدد ممکن است به موارد زیر اشاره داشته باشند:
1. عدد اول، 1، ممکن است نوع میوه را نمایش دهد (1 برای سیب، 2 برای موز، و غیره).
2. عدد دوم، 150، ممکن است وزن میوه را به گرم نشان دهد.
3. عدد سوم، 8.5، ممکن است شیرینی میوه را در مقیاس 1 تا 10 نمایش دهد.
4. عدد چهارم، 10، ممکن است قرمزی میوه را در مقیاس 1 تا 10 نشان دهد.
به این ترتیب، بردار [1، 150، 8.5، 10] در مدل ما سیبی را با ویژگیهای خاص نمایان میکند.
جاسازی یا embeddings چیست؟
بردارها روش ساده ای برای نمایش داده های عددی هستند، اما بسیاری از انواع داده ها، مانند متن یا تصویر، برای تبدیل به اعداد به کمک نیاز دارند. جاسازی embeddings نوعی بردار است که برای نمایش داده های پیچیده تر و با ابعاد بالا در فضای برداری با ابعاد پایین تر و متراکم طراحی شده است.
برای مثال، تصور کنید که میخواهیم کلمه «Apple» را نشان دهیم تا رایانه بتواند آن را به کلمات مشابه بفهمد و به آن مرتبط کند. ما می توانیم از یک الگوریتم برای ترجمه کلمه "Apple" به لیستی از 300 عدد استفاده کنیم که یک بردار تعبیه شده را تشکیل می دهند.
این بردار تعبیه نه تنها خود کلمه بلکه رابطه آن را با کلمات دیگر نیز نشان می دهد. برای مثال، جاسازی برای «Apple» از نظر فاصله به جاسازی «میوه» نزدیکتر است تا جاسازی «ماشین»، که منعکسکننده رابطه معنایی نزدیکتر بین «Apple» و «میوه» است.
از موارد embeddings استفاده کنید
جاسازی ها ابزارهای قدرتمندی برای نمایش داده های با ابعاد بالا، به ویژه در فرم متن، در فضای با ابعاد پایین تر هستند. توانایی آنها در ضبط معنایی دادهها، آنها را در کاربردهای مختلف، از جمله جستجو، خوشهبندی، توصیهها، تشخیص ناهنجاری، اندازهگیری تنوع و طبقهبندی ارزشمند میکند. بیایید نگاهی دقیق تر به این موارد استفاده بیندازیم.
جستجو کردن
هنگامی که کاربر یک کوئری تایپ می کند، می خواهیم نتایجی را نشان دهیم که بیشترین ارتباط را با رشته کوئری دارند. با جاسازی ها، هر آیتم در فهرست جستجو و رشته کوئری را می توان به بردار تبدیل کرد. موارد مرتبط با کوئری مواردی هستند که بردارهای آنها به بردار کوئری نزدیک تر است و تجربه جستجوی مرتبط تری را امکان پذیر می کند.
خوشه بندی
خوشه بندی شامل گروه بندی رشته های متنی بر اساس شباهت آنهاست. ما می توانیم فاصله بین هر جفت جاسازی را با نمایش هر رشته متن به عنوان یک جاسازی محاسبه کنیم. رشته های متنی مشابه معنایی دارای تعبیه های نزدیک تری خواهند بود و بنابراین می توانند با هم گروه بندی شوند. این می تواند به ویژه برای کارهایی مانند مدل سازی موضوع یا تقسیم بندی کلاینت مفید باشد.
توصیه ها
در سیستمهای توصیه، اگر آیتمها (مثلاً کتابها یا فیلمها) با جاسازیها نشان داده میشوند، میتوانیم مواردی را به کاربری مشابه مواردی که قبلاً با آنها در ارتباط بودهاند توصیه کنیم. این شباهت با فاصله بین جاسازیهای اقلام مختلف تعیین میشود و توصیههای شخصیتر را ارائه میدهد.
تشخیص Anomaly
Anomaly ها نقاط داده ای هستند که به طور قابل توجهی با اکثریت متفاوت هستند. با تبدیل رشتههای متنی به جاسازیها، میتوانیم ناهنجاریها را به عنوان بردارهای دورتر از بقیه در فضای برداری تشخیص دهیم. این می تواند در برنامه هایی مانند تشخیص تقلب یا تشخیص خطا در داده های متنی استفاده شود.
اندازه گیری تنوع
جاسازی ها می توانند به اندازه گیری تنوع مجموعه ای از رشته های متنی کمک کنند. با تجزیه و تحلیل توزیع جاسازیها، میتوانیم تنوع مجموعه داده را کمی کنیم. به عنوان مثال، مجموعه ای از بردارها که به شدت خوشه بندی شده اند، تنوع کم را نشان می دهد، در حالی که یک مجموعه گسترده تر نشان دهنده تنوع بالاتر است. این چندین کاربرد مفید دارد، مانند اطمینان از تنوع در توصیههای محتوا یا درک تنوع نظرات در دادههای رسانههای اجتماعی.
طبقه بندی
برای طبقهبندی رشتههای متن، میتوانیم از جاسازیها برای تبدیل متن به بردار استفاده کنیم و سپس یک مدل یادگیری ماشینی را روی این بردارها آموزش دهیم. ما یک جاسازی برای یک رشته متن جدید ایجاد میکنیم و مدل کلاس را بر اساس نزدیکی آن به جاسازیهای کلاسهای مختلف پیشبینی میکند. این می تواند برای کارهایی مانند تشخیص هرزنامه، تجزیه و تحلیل احساسات و دسته بندی اسناد استفاده شود.
فعال کردن بردارها در Supabase
pgvector یک اکستنش PostgreSQL است که امکان ذخیره و جستجوی جاسازی های برداری را مستقیماً در پایگاه داده ما فراهم می کند.
اولین مرحله شامل فعال کردن اکستنش Vector است. ما می توانیم این کار را از طریق رابط وب Supabase با رفتن به پایگاه داده و سپس انتخاب Extensions انجام دهیم.
در قسمت modal نیر public را انتخاب می کنیم، دکمه Vector را کلیک کنید و بر روی Enable افزونه کلیک می کنیم.
در مرحله بعد، جدول پست ها را برای ذخیره پست ها و جاسازی های مربوطه ایجاد می کنیم.
اکستنش pgvector
یک نوع داده جدید به نام vector
را فعال می کند. در جدول، ستونی به نام embedding
ایجاد می کنیم که از این نوع داده برداری جدید استفاده می کند. ما همچنین ستونهای text
را برای ذخیره title
و content
اصلی اضافه میکنیم که منجر به ایجاد این جاسازی خاص شد.
ایجاد جاسازی embeddings با OpenAI
OpenAI یک API ارائه میکند که ایجاد جاسازیها را از یک رشته متنی با استفاده از مدل زبان آن تسهیل میکند. ما میتوانیم دادههای متنی (مانند پستهای وبلاگ و اسناد) را وارد کنیم و بردار اعداد ممیز شناور را به دست دهیم. این بردار اساساً "Contex" متن ورودی را کپسوله می کند.
برای ایجاد جاسازیها با استفاده از OpenAI، با راهاندازی محیط خود شروع میکنیم. ما وابستگی های لازم را با استفاده از دستور زیر نصب می کنیم:
npm i express @supabase/supabase-js openai dotenv
وابستگی ها شامل فریمورک Express برای مدیریت عملیات سرور، کلاینت Supabase برای تعامل با پایگاه داده Supabase ما، پکیج OpenAI برای تولید جاسازی های ما و پکیج dotenv برای مدیریت متغیرهای محیطی env است.
پس از وارد کردن ماژول های مورد نیاز، برنامه Express خود را با متد ()express
مقداردهی اولیه می کنیم. کلاینت Supabase با استفاده از متغیرهای محیطی برای URL و کلید Supabase ایجاد می شود. این کلاینت با پایگاه داده Supabase ما تعامل دارد.
برای OpenAI API، یک شی پیکربندی OpenAI با استفاده از شناسه سازمان OpenAI و کلید API از متغیرهای محیطی خود ایجاد می کنیم. هنگامی که پیکربندی آماده شد، کلاینت OpenAI API را با متد ()new openai.OpenAIApi
نمونه سازی می کنیم.
در نهایت، ما برنامه Express را برای گوش دادن به درخواستها در پورت 3001
راهاندازی میکنیم. برنامه ما اکنون آماده تعامل با OpenAI و Supabase برای تولید و ذخیره جاسازی است:
const express = require("express");
require("dotenv").config();
const supabase = require("@supabase/supabase-js");
const openai = require("openai");
const app = express();
const supabaseClient = supabase.createClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_KEY
);
const openAiConfiguration = new openai.Configuration({
organization: process.env.OPENAI_ORG,
apiKey: process.env.OPENAI_API_KEY,
});
const openAi = new openai.OpenAIApi(openAiConfiguration);
...
app.listen(3001, () => console.log("Server started"));
در مرحله بعد، اجازه دهید اجرای دو نقطه پایانی API و یک تابع کمکی برای تولید جاسازیها را ببینیم:
const getEmbedding = async (input) => {
try {
const embeddingResponse = await openAi.createEmbedding({
model: "text-embedding-ada-002",
input,
});
const [{ embedding }] = embeddingResponse.data.data;
return embedding;
} catch (err) {
console.log(err);
return null;
}
};
app.post("/api/generate-embeddings", async (_req, res) => {
try {
const posts = await supabaseClient.from("posts").select("*");
for (const post of posts.data) {
const embedding = await getEmbedding(`${post.title} ${post.content}`);
await supabaseClient
.from("posts")
.update({ embedding })
.eq("id", post.id);
}
return res.json({ isSuccess: true });
} catch (err) {
return res.json({ isSuccess: false, message: err?.message });
}
});
app.post("/api/create-post", async (req, res) => {
try {
const { title, content } = req.body;
const embedding = await getEmbedding(`${title} ${content}`);
await supabaseClient.from("posts").insert({ title, content, embedding });
return res.json({ isSuccess: true });
} catch (err) {
return res.json({ isSuccess: false, message: err?.message });
}
});
تابع هلپر ()getEmbedding
یک ورودی متن را می پذیرد و آن را به OpenAI API ارسال می کند تا یک جاسازی ایجاد کند. از متد ()createEmbedding
استفاده می کند و مدل را به عنوان "text-embedding-ada-002
" مشخص می کند. سپس embedding را از پاسخ استخراج کرده و آن را برمی گرداند. اگر در طول این فرآیند خطایی رخ دهد، ثبت می شود و null
برگردانده می شود.
مسیر /api/generate-embeddings
همه پستها را از جدول posts
در پایگاه داده Supabase با استفاده از کلاینت Supabase واکشی میکند. روی هر پست حلقه می زند، با استفاده از getEmbedding
یک جاسازی برای title
و content
پست ایجاد می کند و سپس پست را در پایگاه داده با جاسازی جدید به روز می کند.
مسیر /api/create-post
یک مسیر POST
است که درخواستی حاوی title
و content
موجود در بدنه را دریافت می کند. با استفاده از title
و content
یک جاسازی ایجاد می کند و از کلاینت Supabase برای درج یک پست جدید در جدول پست ها، از جمله title
، content
و جاسازی استفاده می کند.
پیاده سازی قابلیت جستجو
هنگامی که جاسازیهایی را برای پستها ایجاد میکنیم، محاسبه شباهت آنها با استفاده از عملیات ریاضی بردار، مانند فاصله کسینوس، نسبتاً ساده میشود. یک مورد اصلی برای فاصله کسینوس پیاده سازی قابلیت جستجو در یک برنامه کاربردی است.
از زمان نوشتن این مقاله، هیچ پشتیبانی API برای مقایسه بردارها با استفاده از کلاینت Supabase وجود ندارد. بنابراین، برای تسهیل جستجوی شباهت روی جاسازیها، باید یک تابع در پایگاه داده ایجاد کنیم.
تابع PostgreSQL زیر، match_posts
، برای یافتن پستهای مشابه با یک کوئری طراحی شده است، بر اساس فاصله کسینوس بین جاسازیهای برداری پستها و کوئری:
create or replace function match_posts (
query_embedding vector(1536),
match_threshold float,
match_count int
)
returns table (
id bigint,
title text,
content text,
similarity float
)
language sql stable
as $$
select
posts.id,
posts.title,
posts.content,
1 - (posts.embedding <=> query_embedding) as similarity
from posts
where 1 - (posts.embedding <=> query_embedding) > match_threshold
order by similarity desc
limit match_count;
$$;
تابع سه پارامتر دارد:
query_embedding
: بردار 1536 بعد که نشان دهنده جاسازی کوئری ورودی است.match_threshold
: یک عدد ممیز شناور که به عنوان حداقل امتیاز شباهت برای یک پست به عنوان منطبق در نظر گرفته می شود.match_count
: یک عدد صحیح که حداکثر تعداد پست برای بازگشت را تعیین می کند
فاصله کسینوس بین جاسازی ها با استفاده از عملگر <=>
محاسبه می شود که مقداری بین 0
(به معنای دقیقاً یکسان) و 2 (کاملاً متفاوت) برمی گرداند. ما این را از 1
کم می کنیم تا شباهت کسینوس را بدست آوریم، که مقدار محدود شده در [1، 1-]
است.
فقط پست هایی که دارای امتیاز تشابه بالاتر از match_threshold
هستند در نظر گرفته می شوند. اینها به ترتیب نزولی از نظر شباهت مرتب می شوند و فقط تعداد بالای match_count
از پست ها برگردانده می شوند.
ما یک نقطه پایانی یا همان endpoind مانند API /api/search
ایجاد می کنیم تا نتایج جستجو را برای پست های مشابه برتر بدست آوریم. ما عبارت جستجو را در پارامترهای کوئری ارسال می کنیم و یک جاسازی یک بار برای عملیات جستجو ایجاد می کنیم. برای فراخوانی یک تابع پایگاه داده، از متد ()rpc
کلاینت Supabase استفاده می کنیم:
app.get("/api/search", async (req, res) => {
try {
const { q } = req.query;
const embedding = await getEmbedding(q);
const matchedPosts = await supabaseClient.rpc("match_posts", {
query_embedding: embedding,
match_threshold: 0.8,
match_count: 3,
});
return res.json({ isSuccess: true, posts: matchedPosts.data });
} catch (err) {
return res.json({ isSuccess: false, message: err?.message });
}
});
و شما آن را دارید! اکنون می توانید سرور محلی خود را فعال و آن را آزمایش کنید. با استفاده از ابزارهایی مانند Postman، میتوانید درخواستهای HTTP را به نقاط پایانی خود ارسال کنید و نتایج جستجو را تأیید کنید. با قابلیت جستجوی برداری جدید شما، کاوش و تعامل با داده های شما باید بصری تر و پاسخگوتر باشد.
نتیجه
در این راهنما، ما بررسی کردیم که چگونه اکستنش PostgreSQL Supabase، pgvector
، میتواند با OpenAI برای مدیریت و پردازش تعبیههای برداری استفاده شود. ما به مفاهیم اساسی بردارها و جاسازیها و اینکه چگونه آنها میتوانند ویژگیهای پیشرفته مانند جستجوی شباهت را تقویت کنند، صحبت کردیم.
ما همچنین به جنبههای کدنویسی، از راهاندازی یک سرور Express اولیه برای رسیدگی به درخواستهای API گرفته تا ایجاد جاسازیها با OpenAI و استفاده از آنها در پایگاه دادهمان پرداختیم. با استفاده از این ابزارها، میتوانیم برنامههای هوشمندتر و آگاهتر از زمینه را توسعه دهیم.