Nest Elastic - Building Dynamic Nested Query Nest Elastic - Building Dynamic Nested Query elasticsearch elasticsearch

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.