نحوه پیاده سازی elasticsearch در پروژه روبی آن ریلز - قسمت دوم

توی قسمت اول تا اینجا پیش اومدیم که الستیک سرچ داخل پروژه کاملا پیاده سازی شد و قادر بود تا غلط های تایپی رو هم تا دو حرف تشخیص بده . این رو دوباره باید اضافه کنم که تمام این پروسه شامل تجربه من از نحوه پیاده سازی و قطعا بهتر هم میشه اون رو اجرا کرد . توی قسمت دوم قرار شد تا راجع به بهینه سازی متد جستجو و پیاده سازی ساختار پیشنهاد هم توضیح بدم . اول از همه این ایده ممکنه پیش بیاد که قرار باشه روی چندتا از مدل هایی که داخل پروژه داریم و فیلد هایی که دارن جستجو کنیم پس مدل هایی رو که مدنظر داریم رو هم باید آماده کنیم . اگر مدل از قبل ساخته شده باشه که هیچی اگر نه مدل رو مثل کد زیر به ساختار پروژه اضافه میکنیم : # models/ class Tag < ActiveRecord validates :name, presence: true endمن برای محتوایی که توی مدل Content داشتم میخواستم که Tag هایی هم تعریف کنم تا دسته بندی محتوا برام راحتر باشه پس مدل Tag رو ساختم . همونطور که میبینین مدل Tag یک فیلد جدید داره که قرار روی اون جستجو بشه . دوباره مثل قبل شروع میکنیم تا مدلی رو که قرار روش کار کنیم رو آمادش کنیم . class Tag < ActiveRecord include Searchable validates :name, presence: true settings index: { number_of_shards: 1 } do mappings dynamic: 'false' do indexes :name end end endحالا لازمه تا فایل Importer رو هم که قبلتر نوشتیم رو آپدیت کنیم .# to change this line [Content].each do |model_to_search| # into this one [Content, Tag].each do |model_to_search|فایل AutoCompleter رو هم به فرم زیر تغییر میدیم .MODELS_TO_SEARCH = [Content, Tag].freezeو فیلدی رو که میخوایم روش جستجو کنیم هم به فیلد های قبلی اضافه میکنیم .# Here we should all the fields that will be part of the search &quotfields&quot: %w[body title type description name]و یه تغییری هم باید داخل فایل HintBuilder بدیم :# instead of directly calling KarateDojo def call ContentResultBuilder.new(@record).autocomplete_hint end # we will use a method to call each one of the ResultBuilders def call result_builder.autocomplete_hint end private def result_builder &quot#{@record.class}ResultBuilder&quot.constantize.new(@record) end # and as a consequence we will need to create another result builder class TagResultBuilder < ResultBuilderBase def autocomplete_hint &quot#{record.title}, #{record.body},#{record.type}, #{record.description},#{record.name}&quot end endخب تا این جا همه شرایط احتمالی رو پیش بینی کردیم و درصورتی که کلمه ای مثل Cancer رو مثلا جستجو کنین نتیجه ای مثل نتیجه زیر میبینین :[ { hint: &quotCancer&quot, record_type: &quotContent&quot, record_id: 1 }, { hint: &quotCancer&quot, record_type: &quotTag&quot, record_id: 1 } ]تا اینجای کار همه چی اونطور که میخواستیم پیش رفت حالا اگر بخوایم تا موتور جستجوگر ما توانایی پیشنهاد رو هم داشته باشه باید دوباره تغییراتی توی کارهایی که کردیم بدیم، در ابتدا از فایل Searchable شروع میکنیم :# models/concerns/searchable.rb # outside the included block ngram_filter = { type: 'nGram', min_gram: 2, max_gram: 20 } ngram_analyzer = { type: 'custom', tokenizer: 'standard', filter: %w[lowercase asciifolding ngram_filter] } whitespace_analyzer = { type: 'custom', tokenizer: 'whitespace', filter: %w[lowercase asciifolding] } # inside the included block settings analysis: { filter: { ngram_filter: ngram_filter }, analyzer: { ngram_analyzer: ngram_analyzer, whitespace_analyzer: whitespace_analyzer } }قبل از هرچیزی دررابطه با مفاهیم جدیدی که توی تیکه کد بالا نوشتم باید توضیحاتی بدم :ngram- filter : اختصاص حداقل و حداکثر کاراکتر‌ها برای جستجو در هر بار اجرای جستجوngram-analyzer : نحوه نشانه گذاری کاراکتر ها برای ngram-filter whitespace-analyzer : خرد کردن متن به بخش های کوچکتر هرموقع که به فضای سفید رسید .توی مرحله بعدی برای تکمیل کارمون لازمه که علاوه بر تغییراتی رو که توی فایل Searchable دادیم ، تغییراتی توی مدل یا مدلهایی که قرار روی اونها کار کنیم هم انجام بدیم : # models/Content.rb settings index: { number_of_shards: 1 } do mappings dynamic: 'false' do indexes :name, type: 'text', analyzer: 'ngram_analyzer', search_analyzer: 'whitespace_analyzer' indexes :title, type: 'text', analyzer: 'ngram_analyzer', search_analyzer: 'whitespace_analyzer' indexes :description, type: 'text', analyzer: 'ngram_analyzer', search_analyzer: 'whitespace_analyzer' indexes :body, type: 'text', analyzer: 'ngram_analyzer', search_analyzer: 'whitespace_analyzer' indexes :type, type: 'text', analyzer: 'ngram_analyzer', search_analyzer: 'whitespace_analyzer' end endخب فکر میکنم تا اینجا برای این قسمت کافی باشه ، توی قسمت سوم راجع به نحوه تست کردن کارهایی که تا اینجا انجام دادیم توضیح میدم ، و در کنارش در رابطه با بعضی از مشکلاتی که ممکن درهنگام کار کردن با الستیک پیش بیاد و نحوه برطرف کردن اونها مینویسم .