[英]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
。
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
. 在弹性搜索响应中,您可以调用records
或results
。 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.