[英]ElasticSearch : Combining query string with term filters
I'm using tire and elasticsearch in my rails project, which is a retail site for car parts. 我在Rails项目中使用了Tire和elasticsearch,该项目是汽车零件的零售网站。 ES is powering a faceted search page used for browsing the parts catalog. ES正在为用于浏览零件目录的多面搜索页面提供动力。 My question is: How can I make the term filters return only exact matches while searching the same fields with a query string, making use of analyzers only on the query string? 我的问题是: 当使用查询字符串搜索相同字段时,如何使术语过滤器仅返回完全匹配项,而仅在查询字符串上使用分析器?
I hope that makes sense. 我希望这是有道理的。 I will try to provide an example: 我将尝试提供一个示例:
The model/index in question is called Parts. 有问题的模型/索引称为零件。 Assume that a part has mappings called categories
and sub_categories
. 假设一部分具有映射称为categories
和sub_categories
。 If a user selects the Brake category and the Brake Caliper Carrier subcategory (creating term filters) I have to make sure that parts from the Brake Caliper subcategory are not also returned – it is a separate subcategory. 如果用户选择了Brake 类别和Brake Caliper Carrier 子类别 (创建术语过滤器),我必须确保Brake Caliper 子类别的零件也不会返回,这是一个单独的子类别。 I do, however, want the user to be able to simply enter something like "brakes" into the search field (creating a query_string) and get results from products within all of those categories. 但是,我确实希望用户能够简单地在搜索字段中输入“刹车”之类的内容(创建query_string)并从所有这些类别的产品中获取结果。
Here is the relevant code from the Part model: 这是零件模型中的相关代码:
def to_indexed_json
fits = fitments.try(:map) do |fit|
{
make: fit.try(:make).try(:name),
make_id: fit.try(:make).try(:id),
model: fit.try(:model).try(:name),
model_id: fit.try(:model).try(:id),
year: fit.year,
sub_model: fit.sub_model
}
end
{
id: id,
name: name,
description: description,
fitments: fits,
categories: root_categories,
sub_categories: sub_categories,
price: price,
condition_id: condition_id,
country_of_origin: country_of_origin,
brand: brand,
oem: oem,
thumb_url: part_images.first.try(:image).try(:thumb).try(:url),
city: user.try(:city),
inventory: inventory,
part_number: part_number,
user: user.try(:public_name)
}.to_json
end
mapping do
indexes :id, type: 'integer'
indexes :name, analyzer: 'snowball', boost: 40
indexes :description, analyzer: 'snowball', boost: 12
indexes :price, type: "integer"
indexes :country_of_origin, index: :not_analyzed
indexes :condition_id, type: "integer"
indexes :brand, index: :not_analyzed
indexes :oem, type: "boolean"
indexes :city, index: :not_analyzed
indexes :inventory, type: "integer"
indexes :part_number, index: :not_analyzed
indexes :user, index: :not_analyzed
indexes :thumb_url, index: :not_analyzed
indexes :fitments do
indexes :make
indexes :make_id, type: "integer" #, index: 'not_analyzed'
indexes :model
indexes :model_id, type: "integer" #, index: 'not_analyzed'
indexes :year, type: "integer"
indexes :sub_model
end
indexes :categories do
indexes :name, index: :not_analyzed
indexes :id, type: "integer"
end
indexes :sub_categories do
indexes :name, index: :not_analyzed
indexes :id, type: "integer"
end
end
def search(params={})
query_filters = []
tire.search(:page => params[:page], :per_page => 20) do
query_filters << { :term => { 'fitments.make_id' => params[:make] }} if params[:make].present?
query_filters << { :term => { 'fitments.model_id' => params[:model] }} if params[:model].present?
query_filters << { :term => { 'categories.name' => params[:category] }} if params[:category].present?
query_filters << { :term => { 'sub_categories.name' => params[:sub_category] }} if params[:sub_category].present?
query_filters << { :term => { 'city' => params[:city] }} if params[:city].present?
query_filters << { :term => { 'condition_id' => params[:condition] }} if params[:condition].present?
query_filters << { :term => { 'brand' => params[:brand] }} if params[:brand].present?
query_filters << { :term => { 'oem' => params[:oem] }} if params[:oem].present?
query do
filtered do
query {
if params[:query].present?
string params[:query]
else
all
end
}
filter :and, query_filters unless query_filters.empty?
end
end
facet("categories") { terms 'categories.name', size: 50 } unless params[:category].present?
facet("cities") { terms 'city', size: 50 } unless params[:city].present?
if params[:category].present? && !params[:sub_category].present?
facet("sub_categories") { terms 'sub_categories.name', size: 50 }
end
facet("condition_id") { terms 'condition_id', size: 50 } unless params[:condition].present?
facet("brand") { terms 'brand', size: 50 } unless params[:brand].present?
facet("oem") { terms 'oem', size: 2 } unless params[:oem].present?
size params[:size] if params[:size]
end
end
You have to use the multi_field
feature of Elasticsearch and filter on the non-analyzed fields; 您必须使用Elasticsearch的multi_field
功能,并在未分析的字段上进行过滤; see eg. 见。 Why multi-field mapping is not working with tire gem for elasticsearch? 为什么多场映射不能与用于弹性搜索的轮胎宝石一起使用?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.