vburca
vburca

Reputation: 228

Filter with boolean block (Tire / ElasticSearch)

I have this search feature that has a text/keyword box and a bunch of filters; I have it implemented right now with the following structure:

query do
  boolean do
    must { string params[:text], default_operator: "AND" } unless params[:text].blank? 
    must { }   unless 
    must { }   unless 
    should { } unless
    # some more must / should / must_not queries
  end
end

# Some sorting

As far as I have read, it would be a better approach to implement it using the actual filter provided by tire (in terms of speed and cacheing).

I want to ask what would be the right way of implementing this? I couldn't find a way of passing a similar boolean block to a filter... That would be nice. Maybe I am doing it wrong?

I am thinking of doing something like

# This would be the main query, by text/keyword
query { string params[:text], default_operator: "AND" } unless params[:text].blank? 

filter do
  boolean do
    # My regular filters that I implemented with queries
    must { }   unless 
    must { }   unless 
    should { } unless
  end
end

# Some sorting

This gives me the following error (at the filter block line): ArgumentError - wrong number of arguments (0 for 1):

Also, I know that this behavior can be achieved using ElasticSearch JSON queries, as shown here: http://www.elasticsearch.org/guide/reference/query-dsl/bool-filter/ . So I assume tire provides a similar functionality on top of this feature.

Thank you for your help.

EDIT
What I am trying to do now is to use a filtered search, in the following way:

query do
  filtered do
    query { string params[:text], default_operator: "AND" } unless params[:text].blank?

    # And here I would like to add the filter block... but for now I am using the filter :and
    filter :and, { :terms => { } } unless params[:something1].blank?, 
                 { :terms => { } } unless params[:something2].blank?,
                 { :range => { } } unless params[:something3].blank?,
                 # more filters that need the AND behavior
    filter :or, { :terms => { } } unless params[:something4].blank?
                 # more filters that need the OR behavior
  end
end

I am thinking of this approach because I also read that a filter :and is faster than a boolean one. Is this correct?

Now, will these filters still get cached? Also, is this the right approach in this situation?

Thank you!

EDIT

From what I've read in the issue posted in the comments, I think I could do something like:

filter :bool => [
  { :must => { :terms => { } } } unless ... ,
  { :must => { :terms => { } } } unless ... ,
  { :should => { :terms => { } } } unless ... ,
  # and the other filters

]

Is this right?

Thanks!

Upvotes: 1

Views: 2434

Answers (1)

vburca
vburca

Reputation: 228

I just found the following issue https://github.com/karmi/tire/issues/2 . Seems like karmi did not really implement this feature for filter?

Meanwhile, as I saw in some of the integration tests, I think I can do something like this:

filter :bool => [
  { :must => { :terms => { } } } unless ... ,
  { :must => { :terms => { } } } unless ... ,
  { :should => { :terms => { } } } unless ... ,
  # and the other filters
]

Here is the source: https://github.com/karmi/tire/commit/01ba026

Also, I ended up writing simple, single filters for my particular case:

query { all } unless !params[:keyword].blank?
query { string params[:keyword], default_operator: "AND" } unless params[:keyword].blank?

filter :term, :a => params[:a] unless params[:a].blank?
filter :term, :b => params[:b] unless params[:b].blank?

filter :range, :c => { gte: params[:c_min] } unless params[:c_min].blank?
filter :range, :c => { lte: params[:c_max] } unless params[:c_max].blank?

filter :terms, :d => params[:d] unless params[:d].blank?

# and more such filters, just wanted to give more examples since 
# the documentation is so sparse over the internet and I know what 
# it takes to find everything in one place :)

I still think this is not the most convenient approach but it does the job in my case (a boolean block would be nice to have, for filter, but as far as I've read, an :and filter is faster than a :bool one - and listing a bunch of filters, as I did above, as far as I understood so far, creates such an :and filter).

I think this is a better approach than the initial one, of having only queries, since now these filters could be cached (as far as I read, again).

Hope this would help someone in the future :)

Also, if anyone has a better suggestion / explanation / helpful tip, please feel free to contribute!

Thanks!

Upvotes: 4

Related Questions