رد کردن 6 افسانه رایج pgvector
Summarize this content to 400 words in Persian Lang
Pgvector پسوند بسیار محبوب Postgres برای ذخیره، نمایه سازی و پرس و جو بردارها است. بردارها برای مدت طولانی یک نوع داده مفید بودهاند، اما اخیراً به دلیل کاربردشان در معماریهای RAG (Retrieval Augmented Generation) برنامههای کاربردی مبتنی بر هوش مصنوعی، محبوبیت بیشتری پیدا کردهاند. بردارها معمولاً بخش بازیابی را نیرو میدهند – با استفاده از جستجوی شباهت برداری و الگوریتمهای نزدیکترین همسایه، میتوان مرتبطترین اسناد را برای یک سؤال کاربر مشخص پیدا کرد.
داشتن قابلیت ذخیره بردارها در پایگاه داده رابطهای معمولی، بر خلاف یک فروشگاه برداری اختصاصی، به این معنی است که میتوانید از تمام قابلیتهای پایگاه داده رابطهای معمولی همراه با جستجوی برداری استفاده کنید – جداول برداری را با دادهها و ابردادههای دیگر بپیوندید، از فیلدهای اضافی برای فیلتر کردن استفاده کنید. ، بازیابی اطلاعات مرتبط و غیره.
نایل از اولین نسخه بتا خصوصی ما، حدود یک سال پیش، از pgvector پشتیبانی کرده است. ما نمونههای کد بیشماری داریم که از pg_vector برای جستجوی شباهت برداری استفاده میکنند. از مکالمه با کاربران ما و در انجمن pg_vector، مشخص شد که برخی تصورات غلط و سوء تفاهم رایج در مورد بهترین شیوه ها و استفاده از آن وجود دارد. در نتیجه این سوء تفاهم ها، برخی از افراد به طور کامل از pg_vector اجتناب می کنند یا از آن به طور موثر کمتر از آن استفاده می کنند. بنابراین، بیایید این را درست کنیم!
افسانه 1: شما همیشه باید از یک شاخص برداری استفاده کنید
این افسانه نتیجه فروشگاههای برداری خاص و کتابخانههای محبوبی است که از اصطلاح «شاخص» برای توصیف هر روش ذخیرهسازی بردارها استفاده میکنند. این منجر به این تصور غلط شده است که شاخص ها تنها راه ذخیره بردارها هستند.
این در اصطلاحات Postgres درست نیست. ترفند این است که دیگر فروشگاههای بردار چیزی را دارند که آن را شاخص «مسطح» مینامند. شاخص تخت اساساً به معنای “بدون سلسله مراتب” است. در postgres، ساختار جدول پیش فرض مسطح است. بنابراین اگر فقط یک جدول با یک ستون از نوع برداری ایجاد کنید، چند بردار را وارد کنید و هیچ شاخصی ایجاد نکنید، در واقع چیزی را دارید که در جاهای دیگر شاخص برداری مسطح نامیده می شود.
اکنون که می دانیم از نظر فنی برای استفاده از pg_vector نیازی به ایجاد نمایه برداری ندارید، هنوز باید تصمیم بگیرید که چه زمانی از یک شاخص استفاده کنید، از کدام یک و چه زمانی از آن استفاده کنید.
بیایید به عنوان مثال برنامهای را در نظر بگیریم که رونوشتهای گفتگوهای فروش را برای جستجو و استخراج دانش جاسازی میکند. ممکن است 10 میلیون جاسازی در پایگاه داده خود داشته باشید، اما هر یک از مشتریان شما کمتر از 10000 جاسازی خواهد داشت. و هر فروشنده کمتر از 1000 نفر دارد. و شاید آنها معمولاً فقط تماس های چند هفته گذشته را جستجو می کنند، بنابراین در واقع کمتر از 100 است.
اگر معمولاً فقط به جستجوی 100 یا 1000 بردار نیاز دارید، تقریباً بدون هیچ شاخص برداری وضعیت بهتری دارید. در عوض، میتوانید از شاخصهای درخت b معمولی (شاید با پارتیشنها) برای محدود کردن پرس و جو برای اسکن کردن زیر مجموعه درست بردارها استفاده کنید. این بدان معناست که شما فراخوانی کامل خواهید داشت (نمایه ها جستجوی تقریبی نزدیکترین همسایه را انجام می دهند، بنابراین ممکن است فراخوانی از بین برود) و می توانید در زمان، حافظه و CPU نگهداری ایندکس هایی که بعید به شما کمک می کنند (و برنامه ریز Postgres ممکن است صرفه جویی کنید) به درستی تصمیم بگیرید که استفاده نکنید).
افسانه 2: معنایی نمایه های برداری مشابه سایر نمایه ها است
اگر با نمایهها در پایگاههای اطلاعاتی رابطهای آشنا هستید، اما کمتر با نمایههای برداری آشنا هستید، ممکن است چند پاراگراف آخر بسیار گیجکننده باشد. منظور من از معامله کردن عملکرد در مقابل فراخوان چیست؟
معمولاً پرس و جوی که از ایندکس استفاده می کند، دقیقاً همان داده هایی را برمی گرداند که توسط کوئری که از ایندکس استفاده نمی کند، بازگردانده می شود. این معناشناسی اولیه SQL/رابطه ای است و انتظار می رود برای هر شاخص و هر پرس و جو تضمین شود. این توقع به قدری ریشه دوانده است که اکثر ما حتی نمی دانیم که انتظارش را داریم.
اما شاخص های برداری اینطور نیستند. آنها ساختارهای داده ای برای جستجوی کارآمد تقریبی نزدیکترین همسایه (ANN) هستند. آنها با محدود کردن جستجوی نزدیکترین همسایگان به زیرمجموعه های خاصی از نمودار، عملکرد را بهبود می بخشند. این زیر مجموعهها به این دلیل انتخاب میشوند که احتمالاً نزدیکترین همسایهها را در خود دارند، اما تضمینی نیستند.
این همچنین به شما نکاتی را در مورد نحوه عملکرد مبادله عملکرد/یادآوری می دهد – هرچه زیر مجموعه های نمودار بیشتری را جستجو کنید، احتمال بیشتری وجود دارد که نزدیک ترین همسایگان واقعی را پیدا کنید، اما بیشتر طول می کشد. علاوه بر این، انواع مختلف نمایه های برداری گزینه های پیکربندی اضافی را در اختیار شما قرار می دهند – مجموعه را به چند زیر مجموعه تقسیم می کنید؟ هر زیرمجموعه را چقدر جامع “نقشه” می کنید؟ این تصمیمات همچنین بر عملکرد/معادل یادآوری شاخص تأثیر خواهد گذاشت.
مستندات PG Vector انواع ایندکس ها و پارامترهای مختلفی را که می توانید هنگام ایجاد و پرس و جو آنها را پیکربندی کنید، توضیح می دهد. قطعاً ارزش خواندن مفصل و آزمایش با آنها را دارد.
افسانه 3: شما نمی توانید بیش از 2000 بعد را در یک شاخص برداری ذخیره کنید
ریشه این افسانه این واقعیت ساده است که اندازه بلوک های Postgres به 8K محدود شده است. به طور پیش فرض، بردارها مجموعه ای از شناورها هستند و هر شناور 32 بیتی است. یک ریاضی ساده نشان می دهد که اگر سربار را در نظر بگیرید، در ابعاد حدود 2000، به حد 8K بسیار نزدیک می شوید. شما هنوز هم می توانید داده ها را ذخیره کنید، Postgres یک ویژگی TOAST دارد که از “اشاره گر” برای ذخیره یک ردیف در بیش از یک بلوک استفاده می کند. اما – اگر ردیف ها با استفاده از TOAST تقسیم شوند، نمی توانید یک شاخص برداری بسازید.
یکی از گزینهها استفاده از مدلهای تعبیهشده است که بردارهایی با ابعاد کمتر تولید میکنند، یا مدلی که آموزش داده شده است بدون از دست دادن کارایی، «کاهش» کند. اما، اگر یک مدل تعبیه شده داشته باشید که واقعاً برای داده های شما کار می کند و ابعاد بیشتری دارد، چه؟ تغییر به یک مدل دیگر ممکن است کاملاً غیرقابل قبول باشد.
گزینه دیگر استفاده از الگوریتم های استخراج ویژگی است که در عین تلاش برای حفظ دقت، ابعاد بردارها را از مدل های دیگر کاهش می دهد. PCA، t-SNE و UMAP برای این کار نسبتاً شناخته شده هستند، و نتایجی وجود دارد که نشان می دهد آنها کاملاً خوب عمل می کنند.
با این حال، یک روش بسیار ساده تر، استفاده از کوانتیزاسیون است. کوانتیزاسیون فرآیند استفاده از نوع داده کوچکتر برای هر بعد است. PG_vector پشتیبانی می کند half_vec با کوانتیزاسیون اسکالر تایپ کنید. با حذف حداقل ارقام، شناورها را به نوع 16 بیتی تبدیل می کند. این منطقی است – ما معمولاً از بردارها و شاخص ها برای جستجوی نزدیکترین همسایه استفاده می کنیم. این ارقام ناچیز معمولاً تأثیر زیادی بر فاصله نسبی بین بردارها ندارند.
از آنجایی که half_vec نصف اندازه شناور معمولی را می گیرد، می توانید ابعاد 4000 را ذخیره کنید half_vec نوع با نگاهی به آینده، جامعه همچنین در حال تکرار کوانتیزه سازی 8 بیتی جاسازی ها با نوع int_vec است که امکان ذخیره ابعاد 8000-ish را فراهم می کند.
حتی اگر جاسازیهای کوچکتری داشته باشید که قبلاً در بلوک Postgres قرار میگیرند و میتوان آنها را فهرست کرد، ذخیره نیمی از دادهها عملکرد را تا حد زیادی بهبود میبخشد و استفاده از منابع را کاهش میدهد. همه تقریباً هیچ تأثیری در یادآوری ندارند.
افسانه 4: استفاده از نمایه برداری با فیلترهای دیگر باعث از دست رفتن داده می شود
این کاملاً به اندازه بقیه افسانه نیست. در واقع، در زمان نگارش، این هنوز هم صادق است. اما در نسخه آتی pg_vector، 0.8.0، ما قادر خواهیم بود این را به یک افسانه تبدیل کنیم.بنابراین «استفاده از شاخص برداری با فیلترهای دیگر» به چه معناست؟
تصور کنید که ویکی شرکت خود را ایندکس کردهاید و اکنون میخواهید اسنادی را پیدا کنید که شبیهترین اسناد به «فرایند و خطمشی ارتقا» هستند. اما از آنجایی که شرکت شما دارای چندین واحد تجاری با خطمشیهای خاص خود است، میخواهید فقط در دسته «مهندسی» جستجو کنید. درخواست شما به این صورت خواهد بود:
select doc_id, doc_title from document_embeddings
where embedding <-> $1 < 1
and doc_category = ‘engineering’
order by embedding <-> $1
limit 10;
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
چگونه Postgres می تواند چنین پرس و جوی را اجرا کند؟
در حالی که ممکن است بخواهیم فقط زیرمجموعهای از نمایه برداری را جستجو کند که به دسته مهندسی تعلق دارد، مگر اینکه قبلاً پارتیشنها یا نمایههای جزئی ایجاد کرده باشید، چنین زیرمجموعهای وجود نخواهد داشت.
اتفاقی که می افتد این است که Postgres ابتدا از شاخص برداری استفاده می کند، 10 همسایه نزدیک را پیدا می کند و سپس آنها را فیلتر می کند و هر چیزی را که در رده مهندسی نیست بیرون می اندازد. البته مشکل این است که ممکن است بین 10 تا 0 ردیف باشد. و ما می خواستیم 10 ردیف را در نتایج جستجو نشان دهیم. مشکل این است – ما بعد از فیلتر کردن K نزدیکترین همسایه را میخواهیم، اما نمیتوانیم از قبل بدانیم که برای رسیدن به این هدف، به چند همسایه برای بازگشت نیاز داریم.
نسخه 0.8.0 شاخص های برداری تکراری را معرفی می کند. این به Postgres اجازه میدهد تا فهرست را اسکن کند، نزدیکترین همسایهها را بیابد، فیلتر را اعمال کند، اندیس را کمی بیشتر اسکن کند، بیشتر فیلتر کند… و تا زمانی که تعداد مورد نظر همسایهها پیدا شود و بتوان آنها را برگرداند ادامه دهد.
نسخه 0.8.0 همچنین شامل بهبود برآورد هزینه استفاده از شاخص های برداری است. این به Postgres کمک می کند تصمیم بگیرد که چه زمانی از شاخص برداری استفاده کند و چه زمانی فقط به شاخص های B-Tree یا GiST تکیه کند. هر دوی این پیشرفتها با هم، ایجاد ایندکسها و اجرای پرسوجوها را بسیار آسانتر میکنند، زیرا میدانند که Postgres کار درستی را با آنها انجام میدهد.
افسانه 5: شباهت برداری فقط برای RAG مفید است
تعبیههای برداری به دلیل نقشی که در Retrieval-Augmented Generation (RAG) دارند، به طور فزایندهای محبوب میشوند. در RAG، تعبیهها به مکانیابی و بازیابی بافت مرتبط کمک میکنند، که به مدلهای زبان بزرگ (LLM) اجازه میدهد تا به سؤالات دقیقتر پاسخ دهند و خطر توهم را کاهش دهند.
اما گاهی اوقات به نظر می رسد که ما همه استفاده های دیگر از جاسازی های برداری را فراموش کرده ایم. بردارها به یافتن موارد مشابه معنایی کمک می کنند. یافتن موارد مشابه حتی بدون LLM مفید است. به عنوان مثال:
پشتیبانی کنید: مقالات پایگاه دانش مرتبط با بلیط پشتیبانی را بیابید و آنها را به مشتری یا نماینده پشتیبانی پیشنهاد دهید.
ردیابی مشکل: گزارش های تکراری مربوط به یک موضوع را شناسایی کنید.
توصیه ها: مواردی را توصیه کنید که مشابه مواردی هستند که مشتری قبلاً دوست داشته است. «اگر از این کتاب لذت بردید، احتمالاً دوست خواهید داشت…»
تشخیص ناهنجاری: به جای یافتن مشابه ترین موارد، می توانیم از فاصله برداری برای تشخیص اینکه آیتم جدید نزدیکترین همسایه ندارد استفاده کنیم. اگر از هر مورد موجود بسیار دور باشد، یک ناهنجاری است و قابل گزارش است.
برای اقلام مشابه خرید کنید: با توجه به عکس یک محصول، می توانید مشابه ترین محصولات را جستجو کنید.
در تمام این موارد، فقط یافتن نزدیکترین همسایه ها کافی است، نیازی به LLM در حلقه نیست.
افسانه 6: pg_vector از BM25 (و سایر بردارهای پراکنده) پشتیبانی نمی کند.
دو نوع تعبیه برداری وجود دارد: متراکم و پراکنده.
بردارهای متراکم معمولاً توسط مدلهای زبانی آموزشدیده تولید میشوند و معنای معنایی پشت یک جمله یا یک سند را رمزگذاری میکنند. این نمایش کمی مبهم است، به این معنا که شما نمی توانید هر بعد را به یک کلمه یا مفهوم خاص ترسیم کنید. بردارهای متراکم معمولاً دارای ابعاد 256-4096 هستند.
بردارهای پراکنده معمولاً نتیجه الگوریتمهای جستجوی متن سنتی (TF-IDF، BM25، SPLADE) هستند که از بردارها برای نمایش اطلاعات در مورد اهمیت کلمات استفاده شده در هر متن استفاده میکنند. در بردارهای پراکنده، هر بعد یک کلمه را نشان می دهد و مقدار نشان می دهد که کلمه در هر متن چقدر مشترک / مهم است. تعداد ابعاد در بردارهای پراکنده به تعداد کلمات متمایز در مجموعه داده (TF-IDF، BM25) یا تعداد کلماتی که مدل روی آنها آموزش داده شده است (30522 در مورد SPLADE) بستگی دارد. از آنجایی که اکثر متون فقط شامل یک زیرمجموعه کوچک از همه کلمات هستند، هنگام استفاده از بردارهای پراکنده، بیشتر ابعاد دارای مقدار 0 هستند.
در نسخه 0.7.0، pg_vector پشتیبانی از بردارهای پراکنده را اضافه کرد sparsevec نوع این نوع فقط عناصر غیر صفر بردار را ذخیره می کند. شما بردارهای پراکنده را فقط با مشخص کردن مقادیر غیرصفر و شاخص های آنها درج می کنید. اگر از کتابخانه های کلاینت pg_vector استفاده می کنید (آنها کتابخانه هایی برای بسیاری از زبان ها و ORM ها دارند)، از نوع برداری پراکنده آنها استفاده خواهید کرد که به طور خودکار بردارها را به نمایش متن صحیح تبدیل می کند.
خلاصه
شاخص های برداری کمی متفاوت از نمایه های معمولی در پایگاه های داده رابطه ای رفتار می کنند. علاوه بر این، حوزه جاسازیهای برداری اصطلاحات خاص خود را دارد که همیشه برای تازه واردان واضح نیست.
زمانی که من برای اولین بار کار با embeddings وکتور و pg_vector را شروع کردم، بسیاری از موضوعات بالا را گیج کننده دیدم، و دیدم که دیگران در جامعه pg_vector با چالش های مشابهی روبرو هستند. امیدوارم این وبلاگ مفید باشد، و من معتقدم که تقریباً همه با حداقل یک بینش جدید کنار خواهند رفت.
شاید مهمترین درس این باشد که pg_vector دائما در حال تغییر است. نسخه 0.7.0 در آوریل امسال منتشر شد، نسخه 0.8.0 برای ماه اکتبر پیش بینی شده است. هر بردار قابلیت بیشتری را اضافه می کند و محدودیت های قدیمی را برطرف می کند. بنابراین مهم است که مفروضات خود را دوباره مرور کنیم و دانش خود را به طور منظم تجدید کنیم. به یاد داشته باشید: این چیزی نیست که نمی دانید، بلکه چیزی است که فکر می کنید می دانید اما دیگر درست نیست.
Pgvector پسوند بسیار محبوب Postgres برای ذخیره، نمایه سازی و پرس و جو بردارها است. بردارها برای مدت طولانی یک نوع داده مفید بودهاند، اما اخیراً به دلیل کاربردشان در معماریهای RAG (Retrieval Augmented Generation) برنامههای کاربردی مبتنی بر هوش مصنوعی، محبوبیت بیشتری پیدا کردهاند. بردارها معمولاً بخش بازیابی را نیرو میدهند – با استفاده از جستجوی شباهت برداری و الگوریتمهای نزدیکترین همسایه، میتوان مرتبطترین اسناد را برای یک سؤال کاربر مشخص پیدا کرد.
داشتن قابلیت ذخیره بردارها در پایگاه داده رابطهای معمولی، بر خلاف یک فروشگاه برداری اختصاصی، به این معنی است که میتوانید از تمام قابلیتهای پایگاه داده رابطهای معمولی همراه با جستجوی برداری استفاده کنید – جداول برداری را با دادهها و ابردادههای دیگر بپیوندید، از فیلدهای اضافی برای فیلتر کردن استفاده کنید. ، بازیابی اطلاعات مرتبط و غیره.
نایل از اولین نسخه بتا خصوصی ما، حدود یک سال پیش، از pgvector پشتیبانی کرده است. ما نمونههای کد بیشماری داریم که از pg_vector برای جستجوی شباهت برداری استفاده میکنند. از مکالمه با کاربران ما و در انجمن pg_vector، مشخص شد که برخی تصورات غلط و سوء تفاهم رایج در مورد بهترین شیوه ها و استفاده از آن وجود دارد. در نتیجه این سوء تفاهم ها، برخی از افراد به طور کامل از pg_vector اجتناب می کنند یا از آن به طور موثر کمتر از آن استفاده می کنند. بنابراین، بیایید این را درست کنیم!
افسانه 1: شما همیشه باید از یک شاخص برداری استفاده کنید
این افسانه نتیجه فروشگاههای برداری خاص و کتابخانههای محبوبی است که از اصطلاح «شاخص» برای توصیف هر روش ذخیرهسازی بردارها استفاده میکنند. این منجر به این تصور غلط شده است که شاخص ها تنها راه ذخیره بردارها هستند.
این در اصطلاحات Postgres درست نیست. ترفند این است که دیگر فروشگاههای بردار چیزی را دارند که آن را شاخص «مسطح» مینامند. شاخص تخت اساساً به معنای “بدون سلسله مراتب” است. در postgres، ساختار جدول پیش فرض مسطح است. بنابراین اگر فقط یک جدول با یک ستون از نوع برداری ایجاد کنید، چند بردار را وارد کنید و هیچ شاخصی ایجاد نکنید، در واقع چیزی را دارید که در جاهای دیگر شاخص برداری مسطح نامیده می شود.
اکنون که می دانیم از نظر فنی برای استفاده از pg_vector نیازی به ایجاد نمایه برداری ندارید، هنوز باید تصمیم بگیرید که چه زمانی از یک شاخص استفاده کنید، از کدام یک و چه زمانی از آن استفاده کنید.
بیایید به عنوان مثال برنامهای را در نظر بگیریم که رونوشتهای گفتگوهای فروش را برای جستجو و استخراج دانش جاسازی میکند. ممکن است 10 میلیون جاسازی در پایگاه داده خود داشته باشید، اما هر یک از مشتریان شما کمتر از 10000 جاسازی خواهد داشت. و هر فروشنده کمتر از 1000 نفر دارد. و شاید آنها معمولاً فقط تماس های چند هفته گذشته را جستجو می کنند، بنابراین در واقع کمتر از 100 است.
اگر معمولاً فقط به جستجوی 100 یا 1000 بردار نیاز دارید، تقریباً بدون هیچ شاخص برداری وضعیت بهتری دارید. در عوض، میتوانید از شاخصهای درخت b معمولی (شاید با پارتیشنها) برای محدود کردن پرس و جو برای اسکن کردن زیر مجموعه درست بردارها استفاده کنید. این بدان معناست که شما فراخوانی کامل خواهید داشت (نمایه ها جستجوی تقریبی نزدیکترین همسایه را انجام می دهند، بنابراین ممکن است فراخوانی از بین برود) و می توانید در زمان، حافظه و CPU نگهداری ایندکس هایی که بعید به شما کمک می کنند (و برنامه ریز Postgres ممکن است صرفه جویی کنید) به درستی تصمیم بگیرید که استفاده نکنید).
افسانه 2: معنایی نمایه های برداری مشابه سایر نمایه ها است
اگر با نمایهها در پایگاههای اطلاعاتی رابطهای آشنا هستید، اما کمتر با نمایههای برداری آشنا هستید، ممکن است چند پاراگراف آخر بسیار گیجکننده باشد. منظور من از معامله کردن عملکرد در مقابل فراخوان چیست؟
معمولاً پرس و جوی که از ایندکس استفاده می کند، دقیقاً همان داده هایی را برمی گرداند که توسط کوئری که از ایندکس استفاده نمی کند، بازگردانده می شود. این معناشناسی اولیه SQL/رابطه ای است و انتظار می رود برای هر شاخص و هر پرس و جو تضمین شود. این توقع به قدری ریشه دوانده است که اکثر ما حتی نمی دانیم که انتظارش را داریم.
اما شاخص های برداری اینطور نیستند. آنها ساختارهای داده ای برای جستجوی کارآمد تقریبی نزدیکترین همسایه (ANN) هستند. آنها با محدود کردن جستجوی نزدیکترین همسایگان به زیرمجموعه های خاصی از نمودار، عملکرد را بهبود می بخشند. این زیر مجموعهها به این دلیل انتخاب میشوند که احتمالاً نزدیکترین همسایهها را در خود دارند، اما تضمینی نیستند.
این همچنین به شما نکاتی را در مورد نحوه عملکرد مبادله عملکرد/یادآوری می دهد – هرچه زیر مجموعه های نمودار بیشتری را جستجو کنید، احتمال بیشتری وجود دارد که نزدیک ترین همسایگان واقعی را پیدا کنید، اما بیشتر طول می کشد. علاوه بر این، انواع مختلف نمایه های برداری گزینه های پیکربندی اضافی را در اختیار شما قرار می دهند – مجموعه را به چند زیر مجموعه تقسیم می کنید؟ هر زیرمجموعه را چقدر جامع “نقشه” می کنید؟ این تصمیمات همچنین بر عملکرد/معادل یادآوری شاخص تأثیر خواهد گذاشت.
مستندات PG Vector انواع ایندکس ها و پارامترهای مختلفی را که می توانید هنگام ایجاد و پرس و جو آنها را پیکربندی کنید، توضیح می دهد. قطعاً ارزش خواندن مفصل و آزمایش با آنها را دارد.
افسانه 3: شما نمی توانید بیش از 2000 بعد را در یک شاخص برداری ذخیره کنید
ریشه این افسانه این واقعیت ساده است که اندازه بلوک های Postgres به 8K محدود شده است. به طور پیش فرض، بردارها مجموعه ای از شناورها هستند و هر شناور 32 بیتی است. یک ریاضی ساده نشان می دهد که اگر سربار را در نظر بگیرید، در ابعاد حدود 2000، به حد 8K بسیار نزدیک می شوید. شما هنوز هم می توانید داده ها را ذخیره کنید، Postgres یک ویژگی TOAST دارد که از “اشاره گر” برای ذخیره یک ردیف در بیش از یک بلوک استفاده می کند. اما – اگر ردیف ها با استفاده از TOAST تقسیم شوند، نمی توانید یک شاخص برداری بسازید.
یکی از گزینهها استفاده از مدلهای تعبیهشده است که بردارهایی با ابعاد کمتر تولید میکنند، یا مدلی که آموزش داده شده است بدون از دست دادن کارایی، «کاهش» کند. اما، اگر یک مدل تعبیه شده داشته باشید که واقعاً برای داده های شما کار می کند و ابعاد بیشتری دارد، چه؟ تغییر به یک مدل دیگر ممکن است کاملاً غیرقابل قبول باشد.
گزینه دیگر استفاده از الگوریتم های استخراج ویژگی است که در عین تلاش برای حفظ دقت، ابعاد بردارها را از مدل های دیگر کاهش می دهد. PCA، t-SNE و UMAP برای این کار نسبتاً شناخته شده هستند، و نتایجی وجود دارد که نشان می دهد آنها کاملاً خوب عمل می کنند.
با این حال، یک روش بسیار ساده تر، استفاده از کوانتیزاسیون است. کوانتیزاسیون فرآیند استفاده از نوع داده کوچکتر برای هر بعد است. PG_vector پشتیبانی می کند half_vec
با کوانتیزاسیون اسکالر تایپ کنید. با حذف حداقل ارقام، شناورها را به نوع 16 بیتی تبدیل می کند. این منطقی است – ما معمولاً از بردارها و شاخص ها برای جستجوی نزدیکترین همسایه استفاده می کنیم. این ارقام ناچیز معمولاً تأثیر زیادی بر فاصله نسبی بین بردارها ندارند.
از آنجایی که half_vec
نصف اندازه شناور معمولی را می گیرد، می توانید ابعاد 4000 را ذخیره کنید half_vec
نوع با نگاهی به آینده، جامعه همچنین در حال تکرار کوانتیزه سازی 8 بیتی جاسازی ها با نوع int_vec است که امکان ذخیره ابعاد 8000-ish را فراهم می کند.
حتی اگر جاسازیهای کوچکتری داشته باشید که قبلاً در بلوک Postgres قرار میگیرند و میتوان آنها را فهرست کرد، ذخیره نیمی از دادهها عملکرد را تا حد زیادی بهبود میبخشد و استفاده از منابع را کاهش میدهد. همه تقریباً هیچ تأثیری در یادآوری ندارند.
افسانه 4: استفاده از نمایه برداری با فیلترهای دیگر باعث از دست رفتن داده می شود
این کاملاً به اندازه بقیه افسانه نیست. در واقع، در زمان نگارش، این هنوز هم صادق است. اما در نسخه آتی pg_vector، 0.8.0، ما قادر خواهیم بود این را به یک افسانه تبدیل کنیم.
بنابراین «استفاده از شاخص برداری با فیلترهای دیگر» به چه معناست؟
تصور کنید که ویکی شرکت خود را ایندکس کردهاید و اکنون میخواهید اسنادی را پیدا کنید که شبیهترین اسناد به «فرایند و خطمشی ارتقا» هستند. اما از آنجایی که شرکت شما دارای چندین واحد تجاری با خطمشیهای خاص خود است، میخواهید فقط در دسته «مهندسی» جستجو کنید. درخواست شما به این صورت خواهد بود:
select doc_id, doc_title from document_embeddings
where embedding <-> $1 < 1
and doc_category = 'engineering'
order by embedding <-> $1
limit 10;
چگونه Postgres می تواند چنین پرس و جوی را اجرا کند؟
در حالی که ممکن است بخواهیم فقط زیرمجموعهای از نمایه برداری را جستجو کند که به دسته مهندسی تعلق دارد، مگر اینکه قبلاً پارتیشنها یا نمایههای جزئی ایجاد کرده باشید، چنین زیرمجموعهای وجود نخواهد داشت.
اتفاقی که می افتد این است که Postgres ابتدا از شاخص برداری استفاده می کند، 10 همسایه نزدیک را پیدا می کند و سپس آنها را فیلتر می کند و هر چیزی را که در رده مهندسی نیست بیرون می اندازد. البته مشکل این است که ممکن است بین 10 تا 0 ردیف باشد. و ما می خواستیم 10 ردیف را در نتایج جستجو نشان دهیم. مشکل این است – ما بعد از فیلتر کردن K نزدیکترین همسایه را میخواهیم، اما نمیتوانیم از قبل بدانیم که برای رسیدن به این هدف، به چند همسایه برای بازگشت نیاز داریم.
نسخه 0.8.0 شاخص های برداری تکراری را معرفی می کند. این به Postgres اجازه میدهد تا فهرست را اسکن کند، نزدیکترین همسایهها را بیابد، فیلتر را اعمال کند، اندیس را کمی بیشتر اسکن کند، بیشتر فیلتر کند… و تا زمانی که تعداد مورد نظر همسایهها پیدا شود و بتوان آنها را برگرداند ادامه دهد.
نسخه 0.8.0 همچنین شامل بهبود برآورد هزینه استفاده از شاخص های برداری است. این به Postgres کمک می کند تصمیم بگیرد که چه زمانی از شاخص برداری استفاده کند و چه زمانی فقط به شاخص های B-Tree یا GiST تکیه کند. هر دوی این پیشرفتها با هم، ایجاد ایندکسها و اجرای پرسوجوها را بسیار آسانتر میکنند، زیرا میدانند که Postgres کار درستی را با آنها انجام میدهد.
افسانه 5: شباهت برداری فقط برای RAG مفید است
تعبیههای برداری به دلیل نقشی که در Retrieval-Augmented Generation (RAG) دارند، به طور فزایندهای محبوب میشوند. در RAG، تعبیهها به مکانیابی و بازیابی بافت مرتبط کمک میکنند، که به مدلهای زبان بزرگ (LLM) اجازه میدهد تا به سؤالات دقیقتر پاسخ دهند و خطر توهم را کاهش دهند.
اما گاهی اوقات به نظر می رسد که ما همه استفاده های دیگر از جاسازی های برداری را فراموش کرده ایم. بردارها به یافتن موارد مشابه معنایی کمک می کنند. یافتن موارد مشابه حتی بدون LLM مفید است. به عنوان مثال:
- پشتیبانی کنید: مقالات پایگاه دانش مرتبط با بلیط پشتیبانی را بیابید و آنها را به مشتری یا نماینده پشتیبانی پیشنهاد دهید.
- ردیابی مشکل: گزارش های تکراری مربوط به یک موضوع را شناسایی کنید.
- توصیه ها: مواردی را توصیه کنید که مشابه مواردی هستند که مشتری قبلاً دوست داشته است. «اگر از این کتاب لذت بردید، احتمالاً دوست خواهید داشت…»
- تشخیص ناهنجاری: به جای یافتن مشابه ترین موارد، می توانیم از فاصله برداری برای تشخیص اینکه آیتم جدید نزدیکترین همسایه ندارد استفاده کنیم. اگر از هر مورد موجود بسیار دور باشد، یک ناهنجاری است و قابل گزارش است.
- برای اقلام مشابه خرید کنید: با توجه به عکس یک محصول، می توانید مشابه ترین محصولات را جستجو کنید.
در تمام این موارد، فقط یافتن نزدیکترین همسایه ها کافی است، نیازی به LLM در حلقه نیست.
افسانه 6: pg_vector از BM25 (و سایر بردارهای پراکنده) پشتیبانی نمی کند.
دو نوع تعبیه برداری وجود دارد: متراکم و پراکنده.
بردارهای متراکم معمولاً توسط مدلهای زبانی آموزشدیده تولید میشوند و معنای معنایی پشت یک جمله یا یک سند را رمزگذاری میکنند. این نمایش کمی مبهم است، به این معنا که شما نمی توانید هر بعد را به یک کلمه یا مفهوم خاص ترسیم کنید. بردارهای متراکم معمولاً دارای ابعاد 256-4096 هستند.
بردارهای پراکنده معمولاً نتیجه الگوریتمهای جستجوی متن سنتی (TF-IDF، BM25، SPLADE) هستند که از بردارها برای نمایش اطلاعات در مورد اهمیت کلمات استفاده شده در هر متن استفاده میکنند. در بردارهای پراکنده، هر بعد یک کلمه را نشان می دهد و مقدار نشان می دهد که کلمه در هر متن چقدر مشترک / مهم است. تعداد ابعاد در بردارهای پراکنده به تعداد کلمات متمایز در مجموعه داده (TF-IDF، BM25) یا تعداد کلماتی که مدل روی آنها آموزش داده شده است (30522 در مورد SPLADE) بستگی دارد. از آنجایی که اکثر متون فقط شامل یک زیرمجموعه کوچک از همه کلمات هستند، هنگام استفاده از بردارهای پراکنده، بیشتر ابعاد دارای مقدار 0 هستند.
در نسخه 0.7.0، pg_vector پشتیبانی از بردارهای پراکنده را اضافه کرد sparsevec
نوع این نوع فقط عناصر غیر صفر بردار را ذخیره می کند. شما بردارهای پراکنده را فقط با مشخص کردن مقادیر غیرصفر و شاخص های آنها درج می کنید. اگر از کتابخانه های کلاینت pg_vector استفاده می کنید (آنها کتابخانه هایی برای بسیاری از زبان ها و ORM ها دارند)، از نوع برداری پراکنده آنها استفاده خواهید کرد که به طور خودکار بردارها را به نمایش متن صحیح تبدیل می کند.
خلاصه
شاخص های برداری کمی متفاوت از نمایه های معمولی در پایگاه های داده رابطه ای رفتار می کنند. علاوه بر این، حوزه جاسازیهای برداری اصطلاحات خاص خود را دارد که همیشه برای تازه واردان واضح نیست.
زمانی که من برای اولین بار کار با embeddings وکتور و pg_vector را شروع کردم، بسیاری از موضوعات بالا را گیج کننده دیدم، و دیدم که دیگران در جامعه pg_vector با چالش های مشابهی روبرو هستند. امیدوارم این وبلاگ مفید باشد، و من معتقدم که تقریباً همه با حداقل یک بینش جدید کنار خواهند رفت.
شاید مهمترین درس این باشد که pg_vector دائما در حال تغییر است. نسخه 0.7.0 در آوریل امسال منتشر شد، نسخه 0.8.0 برای ماه اکتبر پیش بینی شده است. هر بردار قابلیت بیشتری را اضافه می کند و محدودیت های قدیمی را برطرف می کند. بنابراین مهم است که مفروضات خود را دوباره مرور کنیم و دانش خود را به طور منظم تجدید کنیم. به یاد داشته باشید: این چیزی نیست که نمی دانید، بلکه چیزی است که فکر می کنید می دانید اما دیگر درست نیست.