2014-09-23 3 views
4

Я просто переезжаю с драгоценного камня Tire в официальный elasticsearch Ruby wrapper и работаю над реализацией лучших функций поиска.Rails elasticsearch - named scope search

У меня есть модель InventoryItem и модель Store. Store has_many :inventory_items. У меня есть модель на область видимости магазин называется local

scope :local, lambda{|user| near([user.latitude, user.longitude], user.distance_preference, :order => :distance)} 

Я хочу найти только возвращать результаты из этой области, так что я пробовал: InventoryItem.local(user).search...., но он ищет весь индекс, а не объем. После некоторых исследований, похоже, что фильтр - это хороший способ достичь этого, но я не уверен, как его реализовать. Я открыт для других способов достижения этого. Моя конечная цель - найти подмножество модели InventoryItem на основе местоположения магазина.

ответ

0

Я оставлю этот ответ, не принимая до тех пор, пока не наступит щедрость. Не стесняйтесь добавлять ответ, если считаете, что нашли лучшее решение, которое ниже.

Ответ на этот вопрос оказался довольно простым после некоторого рытья.

Использование имени сферы:

scope :for_stores, lambda{ |stores| where(store_id: stores.map(&:id)) } 

Мой метод управления:

def search 
    @stores = Store.local(current_user) # get local stores 
    response = InventoryItem.search 'whatever' # execute the search 
    @inventory_items = response.records.for_stores(@stores) # call records 
end 

На elasticsearch ответов, вы можете либо вызвать records или results. Вызов только results просто даст результаты из индекса, который вы можете отобразить и т. Д. Вызов records на самом деле тянет записи AR, которые позволяют вам цепочки методов, как я делал выше. Круто! Больше информации в docs очевидно.

5

Еще одна вещь, которую вы можете сделать, - это отправить список действительных идентификаторов справа на эластичный, чтобы они сами отфильтровывали записи, а затем выполняли поиск на оставшихся. Мы не проводили тестов, но это быстрее, но я думаю, что это нужно, потому что эластичность - это поисковая система.

Попробую составить пример использования вам классы + переменные и наш опыт с этим:

def search 
    # retrieve ids you want to perform search within 
    @store_ids = Store.local(current_user).select(:id).pluck(:id) 
    # you could also check whether there are any ids available 
    # if there is none - no need to request elastic to search 
    @response = InventoryItem.search_by_store_ids('whatever', @store_ids) 
end 

и модель:

class InventoryItem 
    # ... 

    # search elastic only for passed store ids 
    def self.search_by_store_ids(query, store_ids, options = {})  
    # use method below 
    # also you can use it separately when you don't need any id filtering 
    self.search_all(query, options.deep_merge({ 
     query: { 
     filtered: { 
      filter: { 
      terms: { 
       store_id: store_ids 
      } 
      } 
     } 
     } 
    })) 
    end 

    # search elastic for all inventory items 
    def self.search_all(query, options = {}) 
    self.__elasticsearch__.search(
     { 
     query: { 
      filtered: { 
      query: { 
       # use your fields you want to search, our's was 'text' 
       match: { text: query }, 
      }, 
      filter: {}, 
      strategy: 'leap_frog_filter_first' # do the filter first 
      } 
     } 
     }.deep_merge(options) 
     # merge options from self.search_by_store_ids if calling from there 
     # so the ids filter will be applied 
    ) 
    end 
    # ... 
end 

Таким образом, вы также должны индекса store_id.

Подробнее об фильтрах here.

+0

Я еще не тестировал это, но я согласен, что это может быть быстрее. Я награду за вознаграждение - спасибо за подробный ответ. Я проверю это и предоставит обратную связь, когда у меня будет шанс. – settheline

+0

Спасибо большое! Ваш ответ предоставил мне хороший шаблон, и я, наконец, смог создать поиск, который фильтрует с помощью набора идентификаторов (я не мог найти правильный способ сделать это на Rails и постоянно получал ошибки анализа). –

+0

Это было здорово! Я искал способ объединить области с elasticsearch. –