Reputation: 118
I've been trying to figure out how to do mixed boolean searches that use nested objects using Tire. All the simple examples I've found don't include a more complex query (when searching on other attributes).
My search involves finding a Team that 'needs' a specific type of person. When trying to build a football team, the team needs to fill the roster with certain types of players of a given weight class, with the option of excluding one term or the other.
Other parameters such as 'region' or 'kind' have to do with where the team plays, and what kind of team (casual, competitive, etc) it is.
My current setup:
mapping do
indexes :region, index: :not_analyzed
indexes :kind, index: :not_analyzed
indexes :role_requirements do
indexes :need, type: 'boolean'
indexes :weight_class_id, type: 'integer'
indexes :role_id, type: 'integer'
end
.
.
.
end
def self.search(params)
team_params = params[:team_search]
tire.search(page: params[:page], per_page: 10) do
query do
boolean do
must { string team_params[:query], default_operator: "AND" } if team_params[:query].present?
must { term :kind, team_params[:kind] } if team_params[:kind].present?
must { term :region, team_params[:region] } if team_params[:region].present?
if team_params[:weight_class_id].present? || team_params[:role_id].present?
must { term 'role_requirements.need', true }
end
must { term 'role_requirements.weight_class_id', team_params[:job_id].to_i } if team_params[:weight_class_id].present?
must { term 'role_requirements.role_id', team_params[:role_id].to_i } if team_params[:role_id].present?
.
.
.
end
end
end
end
I've tried a number of ways, but there usually seems to be a problem either with ElasticSearch not able to parse things or Tire not having the method within the scope:
With this implementation, here is the generated to_json: https://gist.github.com/8a615e701eb31ff2e250
Which are currently not giving me any results.
All the different ways I've tried: https://gist.github.com/907c9571caa0e87bad27
None are really able to give me full results.
Upvotes: 0
Views: 640
Reputation: 46
You seem to be missing the nested type in the mapping:
mapping do
indexes :region, index: :not_analyzed
indexes :kind, index: :not_analyzed
indexes :role_requirements, type: 'nested' do
indexes :need, type: 'boolean'
indexes :weight_class_id, type: 'integer'
indexes :role_id, type: 'integer'
end
# ..more mappings..
end
Then you can build your query like this:
tire.search(page: params[:page], per_page: 10) do
query do
boolean do
must { string team_params[:query], default_operator: "AND" } if team_params[:query].present?
must { term :kind, team_params[:kind] } if team_params[:kind].present?
must { term :region, team_params[:region] } if team_params[:region].present?
must do
nested path: 'role_requirements' do
query do
boolean do
if team_params[:weight_class_id].present? || team_params[:role_id].present?
must { term 'role_requirements.need', true }
end
must { term 'role_requirements.weight_class_id', team_params[:job_id].to_i } if team_params[:weight_class_id].present?
must { term 'role_requirements.role_id', team_params[:role_id].to_i } if team_params[:role_id].present?
end
end
end
end
end
end
end
Here are some examples in Tire's integration tests.
Hope this helps :)
Upvotes: 1