هنگامی که متنی را در Elasticsearch - الستیک سرچ جستجو کنید، حتما متوجه خواهید شد که فرایند اجرای کوئری و بازنمایی نتایج نسبت به سایر دیتابیسها، سرعت بالایی دارد. اگر تابحال چنین تجربهای نداشتید، پیشنهاد میکنم حتما برای جستجوی متون به جای استفاده از دیتابیسهای relational و سنتی، استفاده از Elasticsearch را نیز تجربه و مقایسه کنید. البته Elasticsearch نه تنها در سرعت بلکه در برخی قابلیتهای دیگر هم مزایایی دارد که از جمله مهمترین آنها امکان پیادهسازی جستجوی full-text و دارا بودن یک زبان کوئری قدرتمند است.
اما آنچه در این مقاله به آن میپردازیم، چگونگی اجرای جستجو با سرعت بالاست که برخواسته از دو مبحث پردازش موازی (parallel computing) و inverted index است. قصد دارم این مقاله را بر اساس بخشهای زیر دنبال کنیم:
- آشنایی با بخشهای مهم Elasticsearch
- اهمیت shard به عنوان مجموعهای از inverted index ها
- فرایند indexing، از متن ورودی تا تولید inverted index
- فرایند جستجو: همان analyzer، همان نتایج!
آشنایی با بخشهای مهم Elasticsearch
یک سرویس Elasticsearch به عنوان یک node یا گره از یک خوشه (cluster) در نظر گرفته میشود. در حقیقت Elasticsearch با معماری cluster طراحی شده و امکان استفاده از چندین سرویس Elasticsearch بطور همزمان در کنار هم به عنوان یک cluster وجود دارد. با توجه به این معماری مفاهیم زیر را تعریف میکنیم:
Node: هر سرویس Elasticsearch که معمولا در یک ماشین جداگانه راهاندازی میشود را یک node مینامیم.
Shard: واحدی برای نگهداری دادهها است. یک shard در حقیقت یک واحد از مجموعهای document است که روی هارد دیسک ذخیره میشود. Shard ها قابلیت replication دارند یعنی میتوان یک یا چند کپی از هر shard را نیز در cluster نگهداری کرد. به shard های اصلی primary و به کپیها replica میگوییم.
Index: مجموعهای از shard ها که دادههای مرتبط با هم را نگهداری میکنند را یک index مینامیم.
Document: دادههای ورودی در Elasticsearch که با فرمت JSON ذخیره میشود.
و در یک نگاه کلی 👀
در مثال بالا یک cluster شامل سه node داریم و یک index که سه shard اصلی (P1، P2 و P3) و به ازای هر shard اصلی، یک replica (R1، R2 و R3) وجود دارد. document ها نیز در shard ها ذخیره و نگهداری میشوند. دقت کنید که index الزاما دادههای خود را بر روی یک node قرار نداده و ممکن است shard های یک index در node های مختلفی نگهداری شوند.
✨اگر مشتاق به یادگیری الستیک سرچ هستید، میتوانید به دورهی آموزش گام به گام Elasticsearch در سایت سکان آکادمی مراجعه کنید.
در ادامه میخواهیم ببینیم داخل shard ها چه میگذرد. به نظر نمیرسد اگر وظیفهی shardها صرفا نگهداری مجموعهای از document باشد، مزیت چندانی نسبت به index ها داشته باشند! چراکه index ها نیز میتوانستند همین نقش را ایفا کنند.
اهمیت shard به عنوان مجموعهای از inverted index ها
نکته مهم این است که از دید توسعهدهندهای که با Elasticsearch کار میکند، آنچه به عنوان مجموعه نگهدارنده document ها به نظر میرسد، index است چرا که API های CRUD در Elasticsearch با index ها تعامل دارند. در حالیکه هماکنون میدانیم این shard ها هستند که document ها را دستهبندی و نگهداری میکنند و index ها صرفا مجموعهای از shard ها هستند!
اما آیا shard ها تنها مجموعهای برای نگهداری document ها هستند؟
بسیار خوب یک بار دیگر به عنوان این بخش نگاهی بیندازید: اهمیت shard به عنوان مجموعهای از inverted index ها
اما inverted index چیست؟! ابتدا باید بدانیم که ایندکس کردن دادهها در Elasticsearch به این معنی است که دادهی یک document را در Elasticsearch ثبت کنیم. برای مثال دادهی JSON زیر را درنظر بگیرید:
}
"title": "best scientific articles in 2022"
{
با ایندکس شدن document، یک id یا شناسه (مثلا 1) به آن اختصاص یافته و Elasticsearch میداند که کلمات "best"، "scientific"، "articles"، "2022" در document با شناسهی 1 قرار گرفتهاند. به عبارتی با رجوع به document میتوان بررسی کرد چه کلماتی در آن وجود دارد.
حال میتوانیم به مفهوم inverted index بپردازیم. با توضیحات بالا حتما میتوانید بگویید منظور از آن چیست. Inverted index یک ساختار داده (مثلا فرض کنید یک جدول) است که با استفاده از آن میتوان فهمید یک کلمهی خاص (مثلا "articles") در کدام document ها قرار دارد. دقیقا برعکس روند ایندکس شدن! یعنی با رجوع به یک کلمه میتوان فهمید آن کلمه در کدام document ها تکرار شده است.
به تصویر زیر که شمایی از inverted index است دقت کنید:
فرایند indexing، از متن ورودی تا تولید inverted index
بسیار خوب در این مرحله میدانیم دقیقا منظور از inverted index چیست و دیدیم که shard ها علاوه بر document ها، شامل inverted index نیز هستند. بنابراین Elasticsearch هنگامی که متنی را به عنوان ورودی دریافت میکند، نه تنها شکل اولیهی آن متن را ذخیره کرده بلکه با استفاده از analyzer هایی متن مورد نظر را تجزیه کرده و کلمات (term) های آن را نیز استخراج کرده و در inverted index ثبت میکند.
صحبت از analyzer شد اما تاکنون در این مقاله اشارهای به آن نکرده بودم. Analyzer ها ماژولهایی در Elasticsearch هستند که قابلیت تجزیه و تحلیل متون را بر عهده دارند. قصد ندارم در این مقاله وارد جزییات شیوه عملکرد آنها بشوم (هدف این مقاله آموزش analyzer ها نمیباشد اما در دورهی آموزش گام به گام Elasticsearch مفصل در خصوص آنها صحبت کردهام).
نکته مهم این است که متن ورودی طی فرایندهایی توسط analyzer تجزیه شده و term هایی از آن تولید و در inverted index ثبت میشود. در Elasticsearch امکان استفاده از analyzer های از پیش تعریف شده وجود دارد و همچنین میتوان طبق نیازمندی analyzer های دلخواه نیز ساخت.
فرایند جستجو: همان analyzer، همان نتایج!
هنگامی که متنی برای جستجوی full-text به Elasticsearch ارسال میشود، متن مورد جستجو نیز توسط analyzer ها تجزیه شده و term های آن تولید میشود، اما این بار نه برای ذخیره شدن در inverted index بلکه برای تطبیق با term هایی که قبلا در inverted index ثبت شدهاند!
اینجا همان مرحلهای است که ابتدای مقاله به آن اشاره کردم و گفتم که یکی از عوامل جستجوی سریع Elasticsearch، استفاده از inverted index ها است. بله دقیقا همین روش باعث پیدا کردن بسیار سریع document هایی است که شامل term هایی از متن مورد جستجو بوده و این document ها همان نتایج جستجوی ما هستند.
بطور پیشفرض Elasticsearch از همان analyzer ای که برای ایندکس کردن دادههای ورودی استفاده شده است، برای متن مورد جستجو نیز استفاده میکند که در اکثر شرایط نیز همین روش مورد نظر خواهد بود، چراکه اصولا روش تجزیه و تحلیل متون ثبت شده در Elasticsearch و متن جستجو شده باید یکسان باشد تا term های تولید شده امکان تطبیق داشته باشند اما موارد خاصی هم وجود دارد که طبق نیازمندی بهتر است از analyzer متفاوتی برای متن جستجو شده استفاده شود. (نکته مهم این است که در هر صورت متن مورد جستجو نیز توسط analyzer ها تجزیه شده و term های تولیدشده از آن مورد تطیبق قرار میگیرند!)
اما یکی از عوامل تاثیرگذار دیگر در سرعت جستجو، پردازش موازی یا parallel computing است. الستیک سرچ هنگام جستجو، فرایندِ تطبیق term ها را به صورت موازی در تمامی shard ها دنبال میکند. هریک از shard ها برترین نتایج را به ترتیب بازگردانده سپس نتایج تمامی shard ها با یکدیگر ادغام شده و خروجی نهایی جستجو را تشکیل میدهد. بدین وسیله Elasticsearch عملیات جستجو را موازی سازی میکند. اما این به آن معنا نیست که هرچه تعداد shard های ایندکس بیشتر باشد، الزاما عملیات جستجو سریعتر خواهد بود بلکه باید موازنهای بین تعداد shard و حجم دادههای قرار گرفته در هر shard برقرار کرد. به طور کلی وجود تعداد زیادی shard با حجم دادهی کم (برای مثال کمتر از 10 گیگابایت) میتواند به جای تاثیر مثبت، اثر مخربی بر سرعت جستجو داشته باشد جراکه سربار عملیات جستجو در هر shard و ادغام نتایج نهایتا منجر به کاهش سرعت جستجو شود اما برای حجم بالای داده (مثلا 100 گیگابایت یا بیشتر) بهتر است هر 10 تا 30 گیگابایت داده در یک shard قرار گیرد تا اثر مثبت پردازش موازی ضمن جستجو در حجم بالایی از دادهها برقرار باشد.
نتیجهگیری
در این مقاله دیدیم که Elasticsearch برای جستجو و تطبیق term های متن جستجو شده با دادههای ایندکس شده، از ساختاردادهای به نام inverted index استفاده میکند که به کمک آن به سرعت میتواند با رجوع به هر term بفهمد آن term در کدام document ها تکرار شدهاند و در نتیجه بهترین نتایج که با متن مورد جستجو تطبیق دارند را بازگرداند.
همچنین به ماهیت و نقش shard ها در Elasticsearch پرداختیم و دیدیم که وجود shard ها چگونه میتواند برای موازیسازی عملیات جستجو کمک کننده باشد.
امیدوارم این مقاله توانسته باشد کمکی برای درک بهتر عملکرد Elasticsearch به شما عزیزان کرده باشد.