جزئیات و نکات تکمیلی text indexها

Text Index Tips

25 اردیبهشت 1401
درسنامه درس 60 از سری دوره جامع آموزش MongoDB
MongoDB: جزئیات و نکات تکمیلی text index ها (قسمت 62)

تا اینجای کار به شما خسته نباشید می گویم! مبحث text index ها نیز در سه قسمت آینده به پایان می رسد و در فصل بعدی به سراغ مباحث دیگر می رویم اما قبل از آن باید جزئیات ریزی در مورد text index ها را بررسی کنیم. اولین نکته مربوط به جست و جوی کلمات خاص است. ما تا این قسمت یاد گرفته ایم که با استفاده از text index ها می توان به دنبال کلمه ای خاص یا عبارتی خاص گشت اما برعکس این مسئله نیز قابل انجام است! یعنی ما می توانیم به MongoDB بگوییم که اگر رشته ای دارای کلمه مورد نظر ما بود، آن سند را از نتایج حذف کن! بگذارید برایتان یک مثال بزنم. ما می توانیم به دنبال کلمه awesome بگردیم (از همان کالکشن products استفاده می کنیم):

db.products.find({$text: {$search: "awesome"}}).pretty()

هر دو مقداری را پیدا می کنیم که کلمه awesome در آن وجود دارد:

"_id" : ObjectId("5ebe3d68c8ead79df676bcfe"),                    
 "title" : "A Book",                                              
 "description" : "This is an awesome book about a young artist!"  
                                                                         
 "_id" : ObjectId("5ebe3d68c8ead79df676bcff"),                    
 "title" : "Red T-Shirt",                                         
 "description" : "This T-Shirt is red and it's pretty awesome!"   

در نتیجه دوم کلمه t-shirt را نیز داریم. حالا فرض کنید کوئری ما بدین شکل باشد: به دنبال کلمه awesome بگرد، البته در سند هایی که حاوی کلمه t-shirt نباشند. برای انجام این کار کافی است علامت منفی (-) را به t-shirt اضافه کنیم:

db.products.find({$text: {$search: "awesome -t-shirt"}}).pretty()

با این کار فقط نتیجه زیر را می گیریم:

"_id" : ObjectId("5ebe3d68c8ead79df676bcfe"),                  
"title" : "A Book",                                            
"description" : "This is an awesome book about a young artist!" 

به دلیل اینکه گفته ایم نباید در نتایج ما کلمه t-shirt وجود داشته باشد. ما می توانیم این کار را با کلمه book نیز انجام بدهیم:

db.products.find({$text: {$search: "awesome -book"}}).pretty()

تا نتیجه دیگر برایمان برگردانده شود:

"_id" : ObjectId("5ebe3d68c8ead79df676bcff"),                 
 "title" : "Red T-Shirt",                                      
 "description" : "This T-Shirt is red and it's pretty awesome!" 

تغییر زبان و weight ها

برای بررسی جزئیات بیشتر از text index ها باید ابتدا ایندکس قبلی را حذف کنیم:

db.products.dropIndex("title_text_description_text")

سپس یک ایندکس جدید می سازیم اما این بار از آرگومان دوم نیز استفاده خواهیم کرد که مربوط به پیکربندی ایندکس است. من می خواهم زبان را برای ایندکس های رشته ای تعریف کنم (هنوز این کوئری را اجرا نکنید):

db.products.createIndex({title: "text", description: "text"}, {default_language: "english"})

default_language زبان پیش فرض را برای ایندکس های رشته ای شما تعیین می کند. این گزینه به MongoDB می گوید که چه حروفی در هر زبان، از حروف اضافه هستند و نباید در ایندکس قرار بگیرند. به طور مثال در انگلیسی a و the و کلماتی اینچنینی در لیست ایندکس ها قرار نمی گیرند. متاسفانه زبان فارسی هنوز در این نسخه از MongoDB پشتیبانی نمی شود به همین دلیل English را برایش گذاشته ام.

نکته بعدی weight (به معنی «وزن») است. ما در کوئری بالا گفته ایم که ایندکس ما ترکیبی از title و description باشد اما شاید یکی از این دو فیلد ارزش بیشتری برای ما داشته باشند یا به قولی وزن بیشتر داشته باشند. این وزن بیشتر در score یا امتیاز نهایی هر سند برگردانده شده تاثیر می گذارد. برای این کار به شکل زیر عمل می کنیم:

db.products.createIndex({title: "text", description: "text"}, {default_language: "english", weights: {title: 1, description: 10}})

من برای title عدد 1 و برای description عدد 10 را انتخاب کرده ام. شما می توانید هر عددی دیگری را انتخاب کنید، مهم ارتباط بین این دو عدد و نسبت آن ها به هم است نه مقدار آن ها. مثلا در کوئری بالا 1 به 10 یعنی description ده برابر title اهمیت دارد بنابراین می توانستیم این کار را با 100 و 1000 نیز انجام بدهیم. پس از اجرای کوئری بالا ایندکس ما تعریف می شود و می توانیم مثل همیشه آن را جست و جو کنیم:

db.products.find({$text: {$search: "red"}}, {score: {$meta: "textScore"}}).pretty()

نتیجه برگردانده شده به شکل زیر خواهد بود:

"_id" : ObjectId("5ebe3d68c8ead79df676bcff"),                  
"title" : "Red T-Shirt",                                       
"description" : "This T-Shirt is red and it's pretty awesome!",
"score" : 6.666666666666667                                    

اگر یادتان باشد در جلسات قبل این مقدار 6.66666 نبود بلکه حالا با اولویت دادن به description آن را تغییر داده ایم. برای اینکه این موضوع را ثابت کنیم، اول از همه ایندکس خودمان را حذف می کنیم. در ابتدا باید با getIndex نام ایندکس خودمان را پیدا کنیم:

db.products.getIndexes()

سپس این نام را به dropIndex پاس می دهیم:

db.products.dropIndex("title_text_description_text")

حالا ایندکس ما حذف شده است و می توانیم یک ایندکس جدید و بدون weight برایش تعریف کنیم:

db.products.createIndex({title: "text", description: "text"}, {default_language: "english"})

سپس دوباره همان کوئری قبلی را اجرا می کنیم:

db.products.find({$text: {$search: "red"}}, {score: {$meta: "textScore"}}).pretty()

این بار نتیجه به شکل زیر خواهد بود:

"_id" : ObjectId("5ebe3d68c8ead79df676bcff"),                  
 "title" : "Red T-Shirt",                                       
 "description" : "This T-Shirt is red and it's pretty awesome!",
 "score" : 1.2666666666666666                                   

همانطور که مشخص است این بار به جای 6.66666 عدد 1.2666 را گرفته ایم! چرا؟ به دلیل اینکه دیگر Description نسبت به title اولویت ندارد بنابراین score به شکل متفاوتی محاسبه می شود.

نکته: اگر بخواهید کوئری های خود را به شکل case-sensitive (حساس به بزرگی و کوچکی حروف انگلیسی) بنویسید، می توانید از اپراتور خاص caseSensitive استفاده کنید:

db.products.find({$text: {$search: "red", $caseSensitive: true}}).pretty()

با این کار کوئری شما فقط به دنبال red می گردد و از Red صرف نظر می کند.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری دوره جامع آموزش MongoDB توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

مقالات مرتبط
آخرین سوالات کاربران
5451218 در 4 سال قبل پرسیده:
ما را دنبال کنید
اینستاگرام روکسو تلگرام روکسو ایمیل و خبرنامه روکسو