Appending multiple bool filters to a NEST query

Ted Nyberg picture Ted Nyberg · Oct 28, 2013 · Viewed 10.9k times · Source

I'd like to append multiple bool filters with NEST, but I can't (practically) do it in a single statement as I want to build a set of Bool filters depending on different conditions.

Something like this pseudo code:

// Append a filter
searchDescriptor.Filter(f => f.Bool(b => b.Must(m => m.Term(i => i.SomeProperty, "SomeValue"))));

if (UserId.HasValue)
{
   // Optionally append another filter (AND condition with the first filter)
   searchDescriptor.Filter(f => f.Bool(b => b.Must(m => m.Term(i => i.AnotherProperty, "MyOtherValue"))));
}

var result = Client.Search(searchDescriptor);

Now it seems when the second optional filter is appended, it essentially replaces the first filter.

I'm sure I'm missing something syntactically, but I can't figure it out and the NEST documentation is a bit thin on the filter DSL. :)

Answer

Martijn Laarman picture Martijn Laarman · Nov 3, 2013

The section on writing queries pretty much applies to filters as well: http://nest.azurewebsites.net/nest/writing-queries.html

The solution you ended up with is less than ideal since you are wrapping bool filters inside an and filter which have very different caching mechanisms (and filters don't use the cached bitsets so in most cases perform worse then regular bool filters).

Highly recommend reading http://www.elasticsearch.org/blog/all-about-elasticsearch-filter-bitsets/ as it explains really well what the difference between and/or/not filters vs bool filters are.

You can actually rewrite this like so:

Client.Search(s=>s
    .Filter(f=> { 
        BaseFilter ff = f.Term(i => i.MyProperty, "SomeValue");
        if (UserId.HasValue)
            ff &= f.Term(i => i.AnotherProperty, "AnotherValue");
        return ff;
    })
);

If the second term is searching using UserId you can take advantage of NEST's conditionless queries

Client.Search(s=>s
    .Filter(f=> 
        f.Term(i => i.MyProperty, "SomeValue") 
        && f.Term(i => i.AnotherProperty, UserId)
    )
);

If UserId is null then the term query won't be genererated as part of the query, nest in this case won't even wrap the single remaining term in a bool filter but just send it as a plain term filter instead.