Nest Elastic - Building Dynamic Nested Query

女生的网名这么多〃 提交于 2019-12-10 17:55:03

问题


I have to query a nested object using Nest, however the query is built in dynamic way. Below is code that demonstrate using query on nested "books" in a static way

QueryContainer qry;
         qry = new QueryStringQuery()
         {
             DefaultField = "name",
             DefaultOperator = Operator.And,
             Query = "salman"
         };

         QueryContainer qry1 = null;

         qry1 = new RangeQuery() // used to search for range ( from , to)
         {
             Field = "modified",
             GreaterThanOrEqualTo = Convert.ToDateTime("21/12/2015").ToString("dd/MM/yyyy"),
         };

         QueryContainer all = qry && qry1;

            var results = elastic.Search<Document>(s => s
               .Query(q => q
                    .Bool(qb => qb
                        .Must(all)))
                .Filter(f =>
                        f.Nested(n => n
                             .Path("books")
                                .Filter(f3 => f3.And(
                                            f1 => f1.Term("book.isbn", "122"),
                                            f2 => f2.Term("book.author", "X"))

                                        )
                                )
                        )   

                );

The problem is that i need to combine multiple queries (using And,OR operators) for "books" in dynamic fashion. For example, get the books that satisfy these set of conditions:

  1. Condition 1: Books that has Author "X" and isbn "1"
  2. Condition 2: Books that has Author "X" and isbn "2"
  3. Condition 3: Books that has Author "Z" and isbn "3"
  4. Other Condtions: .....

Now, the filter in the nested Query should retrieve books if:
Condition 1 AND Condition 2 Or Condition 3

Suppose that i have class name FilterOptions that contains the following attributes:

  1. FieldName
  2. Value
  3. Operator (which will combine the next filter)

I am going to loop on the given FilterOptions array to build the query.

Question:

What should i use to build the nested query? Is it a FilterDesciptor and how to combine them add the nested query to the Search Method?

Please, recommend any valuable link or example?


回答1:


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)
    ))



回答2:


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:

978
3
16
148410
0

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.



来源:https://stackoverflow.com/questions/34496476/nest-elastic-building-dynamic-nested-query

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!