[英]Rails Elasticsearch - multiple filter terms
I have a model Campaign which can be created by a user of types: "NonProfit" and "Individual". 我有一个模型Campaign,可以由类型为“ NonProfit”和“ Individual”的用户创建。
Now I want to search campaigns who are created by either NonProfit or Individual only, or by any of them. 现在,我要搜索仅由非营利组织或个人或由任何一个组织创建的广告系列。
Here is my model: 这是我的模型:
class Campaign < ActiveRecord::Base
after_commit lambda { __elasticsearch__.index_document }, on: :create
after_commit lambda { __elasticsearch__.update_document }, on: :update
belongs_to :user
enum status: { waiting: 0, approved: 1, disapproved: 2, expired: 3, canceled: 4, draft: 5, published: 6}
def user_type
self.user.rolable_type
end
def as_json(options={})
super(:only => [:id, :status, :title, :description],
:methods => [:user_type])
end
settings index: {
number_of_shards: 1,
analysis: {
filter: {
trigrams_filter: {
type: 'ngram',
min_gram: 2,
max_gram: 10
},
content_filter: {
type: 'ngram',
min_gram: 4,
max_gram: 20
}
},
analyzer: {
index_trigrams_analyzer: {
type: 'custom',
tokenizer: 'standard',
filter: ['lowercase', 'trigrams_filter', 'asciifolding']
},
search_trigrams_analyzer: {
type: 'custom',
tokenizer: 'whitespace',
filter: ['lowercase']
},
english: {
tokenizer: 'standard',
filter: ['standard', 'lowercase', 'content_filter']
},
czech: {
tokenizer: 'standard',
filter: ['standard','lowercase','content_filter', 'asciifolding']
}
}
}
} do
mappings dynamic: 'false' do
indexes :status, type: 'string'
indexes :user_type, type: 'string'
indexes :en_title, index_analyzer: 'english', search_analyzer: 'english'
indexes :ma_title, index_analyzer: 'czech', search_analyzer: 'czech'
indexes :cs_title, index_analyzer: 'czech', search_analyzer: 'czech'
indexes :en_description, index_analyzer: 'english', search_analyzer: 'english'
indexes :ma_description, index_analyzer: 'czech', search_analyzer: 'czech'
indexes :cs_description, index_analyzer: 'czech', search_analyzer: 'czech'
end
end
def as_indexed_json(options={})
{ id: id,
status: status,
user_type: user_type,
ma_title: ma_title,
cs_title: cs_title,
en_title: en_title,
ma_description: ma_description,
cs_description: cs_description,
en_description: en_description
}
end
def self.search(query, user_type)
__elasticsearch__.search(
{
query: {
filtered: {
query: {
multi_match: {
query: query,
fields: ['ma_title^10', 'cs_title^10', 'en_title^10', 'ma_description', 'cs_description', 'en_description']
}
},
filter: {
term: {
status: "published"
},
term: {
user_type: user_type
}
}
}
}
}
)
end
end
My Controller would look something like this: 我的控制器看起来像这样:
Campaign.search(params[:q], 'NonProfit') # to search only NonProfit campaigns
Campaign.search(params[:q], 'Individual') # to search only Individual campaigns
Campaign.search(params[:q], ['NonProfit','Individual']) # to search any of the campaigns
However I always get 0 results. 但是我总是得到0个结果。 I works just fine when I remove the filter term 'user_type'. 删除过滤条件“ user_type”时,我的工作效果很好。 I am not succesffull to get the user_type filter term working as expected. 我无法使user_type过滤器术语按预期工作。
Any idea, how to make it working? 任何想法,如何使其工作? Thanks, Miroslav 谢谢,米罗斯拉夫
def as_json(options={})
super(:only => [:id, :status, :title, :description],
:methods => [:user_type]
# :include => {
# :employers => {:only => [:title]},
# :roles => {:only => [:name]}
# }
)
end
settings index: {
number_of_shards: 1,
analysis: {
filter: {
trigrams_filter: {
type: 'ngram',
min_gram: 2,
max_gram: 10
},
content_filter: {
type: 'ngram',
min_gram: 4,
max_gram: 20
}
},
analyzer: {
index_trigrams_analyzer: {
type: 'custom',
tokenizer: 'standard',
filter: ['lowercase', 'trigrams_filter', 'asciifolding']
},
search_trigrams_analyzer: {
type: 'custom',
tokenizer: 'whitespace',
filter: ['lowercase']
},
english: {
tokenizer: 'standard',
filter: ['standard', 'lowercase', 'content_filter']
},
czech: {
tokenizer: 'standard',
filter: ['standard','lowercase','content_filter', 'asciifolding']
}
}
}
} do
mappings dynamic: 'false' do
indexes :status, type: 'string', index: 'not_analyzed'
indexes :user_type, type: 'string', index: 'not_analyzed'
indexes :en_title, index_analyzer: 'english', search_analyzer: 'english'
indexes :ma_title, index_analyzer: 'czech', search_analyzer: 'czech'
indexes :cs_title, index_analyzer: 'czech', search_analyzer: 'czech'
indexes :en_description, index_analyzer: 'english', search_analyzer: 'english'
indexes :ma_description, index_analyzer: 'czech', search_analyzer: 'czech'
indexes :cs_description, index_analyzer: 'czech', search_analyzer: 'czech'
end
end
def as_indexed_json(options={})
{ id: id,
status: status,
ma_title: ma_title,
cs_title: cs_title,
en_title: en_title,
ma_description: ma_description,
cs_description: cs_description,
en_description: en_description,
:methods => [:user_type]
}
end
def self.search(query, user_type)
__elasticsearch__.search(
{
query: {
filtered: {
query: {
multi_match: {
query: query,
fields: ['ma_title^10', 'cs_title^10', 'en_title^10', 'ma_description', 'cs_description', 'en_description']
}
},
filter: {
bool: {
must: [
{
term: {
status: "published"
}
},
{
terms: {
user_type: user_type
}
}
]
}
}
}
}
}
)
end
You need to add "index" : "not_analyzed"
to your mapping
for the fields status
and user_type
. 您需要在字段status
和user_type
mapping
添加"index" : "not_analyzed"
。 As you did not specify any analyzer ES was using standard analyzer
for those fields. 由于您未指定任何分析器,因此ES在这些字段中使用了standard analyzer
。
mappings dynamic: 'false' do
indexes :status, type: 'string', index : 'not_analyzed' <--- here
indexes :user_type, type: 'string', index : 'not_analyzed' <--- here
If you need to use term filter, you need to make sure it is exact match as term queries
do not perform any analysis. 如果需要使用术语过滤器,则由于term queries
不执行任何分析,因此需要确保其完全匹配。
Also for Campaign.search(params[:q], ['NonProfit','Individual']) # to search any of the campaigns
you need to use terms filter as you are searching for more than one value. 同样对于Campaign.search(params[:q], ['NonProfit','Individual']) # to search any of the campaigns
都需要使用术语过滤器 。
EDIT Terms Query 编辑 条款查询
Terms Query expect array of values 字词查询期望值数组
Campaign.search(params[:q], ['NonProfit'])
Try this 尝试这个
{
"terms": {
"user_type": ['NonProfit']
}
}
I hope this helps. 我希望这有帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.