简体   繁体   English

Rails elasticsearch - 命名范围搜索

[英]Rails elasticsearch - named scope search

I'm just moving over from the Tire gem to the official elasticsearch Ruby wrapper and am working on implementing better search functionality. 我只是从Tire gem转移到官方的弹性搜索Ruby包装器 ,我正在努力实现更好的搜索功能。

I have a model InventoryItem and a model Store . 我有一个模型InventoryItem和一个模型Store Store has_many :inventory_items . Store has_many :inventory_items I have a model scope on Store called local 我在Store上有一个名为local的模型范围

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

I want the search to only return results from this scope so I tried: InventoryItem.local(user).search.... but it searches the entire index, not the scope. 我希望搜索只返回此范围的结果,所以我尝试了: InventoryItem.local(user).search....但它搜索整个索引,而不是范围。 After doing some research, it looks like filter's are a good way to achieve this, but I'm unsure how to implement. 在做了一些研究后,看起来过滤器是实现这一目标的好方法,但我不确定如何实现。 I'm open to other ways of achieving this as well. 我也愿意采用其他方式实现这一目标。 My ultimate goal is be able to search a subset of the InventoryItem model based on store location. 我的最终目标是能够根据商店位置搜索InventoryItem模型的子集。

Another thing you can do is to send the list of valid ids right to elastic, so it will filter records out by itself and then perform a search on ones that left. 您可以做的另一件事是将有效ID列表发送到弹性,因此它将自己过滤掉记录,然后对剩下的记录执行搜索。 We were not doing tests whether it is faster yet, but I think it should, because elastic is a search engine after all. 我们没有测试它是否更快,但我认为应该,因为弹性是一个搜索引擎。

I'll try to compose an example using you classes + variables and our experience with that: 我将尝试使用类+变量和我们的经验撰写一个示例:

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

And a model: 一个模型:

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

That way you also have to index store_id . 这样你也必须索引store_id

You can read more about filters here . 您可以在此处详细了解过滤器。

I'll leave this answer without accepting until the bounty is over - feel free to add an answer if you think you've found a better solution that one below. 我会留下这个答案而不接受,直到赏金结束 - 如果你认为你已经找到了一个更好的解决方案,请随意添加答案。

The answer to this ended up being fairly simple after some digging. 经过一番挖掘后,答案最终变得相当简单。

Using the named scope: 使用命名范围:

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

My controller method: 我的控制器方法:

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

On elasticsearch responses, you can either call records or results . 在弹性搜索响应中,您可以调用recordsresults Calling just results will simply yield the results from the index that you can display etc. Calling records actually pulls the AR records which allows you to chain methods like I did above. 调用results只会产生您可以显示的索引的结果等。调用records实际上会拉动AR记录,这样您就可以像上面那样链接方法。 Cool! 凉! More info in the docs obviously. 显然, 文档中的更多信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM