set*_*ine 5 ruby-on-rails elasticsearch
我只是从Tire gem转移到官方的弹性搜索Ruby包装器,我正在努力实现更好的搜索功能.
我有一个模型InventoryItem和一个模型Store.Storehas_many :inventory_items.我在Store上有一个模型范围local
scope :local, lambda{|user| near([user.latitude, user.longitude], user.distance_preference, :order => :distance)}
Run Code Online (Sandbox Code Playgroud)
我希望搜索只返回此范围的结果,所以我尝试了:InventoryItem.local(user).search....但它搜索整个索引,而不是范围.在做了一些研究之后,看起来过滤器是实现这一目标的好方法,但我不确定如何实现.我也愿意采用其他方式实现这一目标.我的最终目标是能够InventoryItem根据商店位置搜索模型的子集.
您可以做的另一件事是将有效ID列表发送到弹性,因此它将自己过滤掉记录,然后对剩下的记录执行搜索.我们没有测试它是否更快,但我认为应该,因为弹性是一个搜索引擎.
我将尝试使用类+变量和我们的经验撰写一个示例:
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
Run Code Online (Sandbox Code Playgroud)
一个模型:
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
Run Code Online (Sandbox Code Playgroud)
这样你也必须索引store_id.
您可以在此处详细了解过滤器.
在赏金结束之前,我将保留此答案而不接受 - 如果您认为您已经找到了比下面更好的解决方案,请随时添加答案。
经过一番挖掘后,这个问题的答案相当简单。
使用命名范围:
scope :for_stores, lambda{ |stores| where(store_id: stores.map(&:id)) }
Run Code Online (Sandbox Code Playgroud)
我的控制器方法:
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
Run Code Online (Sandbox Code Playgroud)
在 elasticsearch 响应中,您可以调用records或results。调用只是results简单地从可以显示的索引中产生结果等。调用records实际上会拉取 AR 记录,这允许您像我上面那样链接方法。凉爽的!文档中显然有更多信息。