Nest Elastic - Building Dynamic Nested Query
I agree with paweloque, it seems your first two conditions are contradictory and wouldn't work if AND-ed together. Ignoring that, here's my solution. I've implemented this in such a way that allows for more than the three specific conditions you have. I too feel it would fit better in a bool
statement.
QueryContainer andQuery = null;QueryContainer orQuery = null;foreach(var authorFilter in FilterOptions.Where(f=>f.Operator==Operator.And)){ andQuery &= new TermQuery { Field = authorFilter.FieldName, Value = authorFilter.Value };}foreach(var authorFilter in FilterOptions.Where(f=>f.Operator==Operator.Or)){ orQuery |= new TermQuery { Field = authorFilter.FieldName, Value = authorFilter.Value };}
After that, in the .Nested
call I would put:
.Path("books") .Query(q=>q .Bool(bq=>bq .Must(m=>m.MatchAll() && andQuery) .Should(orQuery) ))
In the specific case of the Condition 1
and Condition 2
you'd probably not get any results because these are exclusive conditions. But I assume now, that you want to get results which match either of those conditions. You've chosen nested which is definitely the way to go. With the nested type you can combine parameters for a single book.
Combining nested queries
For your use case I'd use bool
query type with must
or should
clauses.A query to get books for either Condition 1
or Condition 2
would be:
POST /books/_search{ "query": { "bool": { "should": [ { "nested": { "path": "books", "query": { "bool": { "must": [ { "match": { "books.isbn": "2" } }, { "match": { "books.author": "X" } } ] } } } }, { "nested": { "path": "books", "query": { "bool": { "must": [ { "match": { "books.isbn": "1" } }, { "match": { "books.author": "X" } } ] } } } } ] } }}
Can you explain, why are your books nested? Without nesting them in a top structure but indexing directly as a top level object in an index/type you could simplify your queries.
Not-Analyzed
There is another caveat that you have to remind: If you want to have an exact match on the author and the ISBN you have to make sure that the ISBN and author fields are set to not_analyzed
. Otherwise they get analyzed and splitted into parts and your match would'n work very well.
E.g. if you have a ISBN Number with dashes, then it would get split into parts:
978-3-16-148410-0
would become indexed as:
9783161484100
And a search with exactly the same ISBN number would give you all the books which have one of the sub-numbers in their ISBN number. If you want to prevent this, use the not_analyzed
index-type and Multi-fields:
"isbn": { "type": "string", "fields": { "raw": { "type": "string", "index": "not_analyzed" } } }
Then to address the not_analyzed
isbn field you'd have to call it:
books.isbn.raw
Hope this helps.