I have a model Campaign which can be created by a user of types: "NonProfit" and "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. I works just fine when I remove the filter term 'user_type'. I am not succesffull to get the user_type filter term working as expected.
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
. As you did not specify any analyzer ES was using standard analyzer
for those fields.
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.
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.
EDIT Terms Query
Terms Query expect array of values
Campaign.search(params[:q], ['NonProfit'])
Try this
{
"terms": {
"user_type": ['NonProfit']
}
}
I hope this helps.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.