Nest Elastic - 构建动态嵌套查询

Nest Elastic - Building Dynamic Nested Query

我必须使用 Nest 查询嵌套对象,但是查询是以动态方式构建的。下面是演示以静态方式

对嵌套 "books" 使用查询的代码
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"))

                                        )
                                )
                        )   

                );

问题是我需要以动态方式组合 "books" 的多个查询(使用 And、OR 运算符)。例如,获取满足这组条件的书籍:

  1. 条件 1:作者为 "X" 且 isbn 为“1”的图书
  2. 条件 2:作者为 "X" 且 isbn 为“2”的图书
  3. 条件 3:作者为 "Z" 且 isbn 为“3”的图书
  4. 其他条件:.....

现在,嵌套查询中的过滤器应该检索书籍,如果:
条件 1 AND 条件 2 Or 条件 3

假设我有 class 包含以下属性的名称 FilterOptions:

  1. 字段名
  2. 价值
  3. 运算符(将结合下一个过滤器)

我将在给定的 FilterOptions 数组上循环以构建查询。

Question:

我应该使用什么来构建嵌套查询?它是 FilterDesciptor 以及如何组合它们将嵌套查询添加到搜索方法?

请推荐任何有价值的link或示例?

Condition 1Condition 2 的特定情况下,您可能不会得到任何结果,因为这些是排他性条件。但我现在假设,您希望获得符合这些条件之一的结果。您选择了嵌套,这绝对是正确的选择。使用嵌套类型,您可以为一本书组合参数。

组合嵌套查询

对于您的用例,我将使用带有 mustshould 子句的 bool 查询类型。 获取 Condition 1Condition 2 书籍的查询将是:

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"
                              }
                           }
                        ]
                     }
                  }
               }
            }
         ]
      }
   }
}

你能解释一下,为什么你的书是嵌套的?无需将它们嵌套在顶级结构中,而是直接作为 index/type 中的顶级对象进行索引,您可以简化查询。

Not-Analyzed

还有一点需要提醒您:如果您希望作者和 ISBN 完全匹配,您必须确保 ISBN 和作者字段设置为 not_analyzed。否则他们会被分析并分成几部分,你的比赛就不会很好地进行。

例如如果您有带破折号的 ISBN 编号,那么它会被分成几部分:

978-3-16-148410-0

将被索引为:

978
3
16
148410
0

使用完全相同的 ISBN 编号进行搜索会为您提供 ISBN 编号中包含 sub-numbers 之一的所有图书。如果你想防止这种情况,使用 not_analyzed index-type 和 Multi-fields:

  "isbn": {
     "type": "string",
     "fields": {
        "raw": {
           "type": "string",
           "index": "not_analyzed"
        }
     }
  }

然后要解决 not_analyzed isbn 字段,您必须调用它:

books.isbn.raw

希望这对您有所帮助。

我同意 paweloque 的观点,看来你的前两个条件是矛盾的,如果 AND-ed 在一起就不会起作用。忽略它,这是我的解决方案。我以允许超过三个特定条件的方式实现它。我也觉得它更适合 bool 声明。

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
    };
}

之后,在 .Nested 调用中我会输入:

.Path("books")
    .Query(q=>q
        .Bool(bq=>bq
            .Must(m=>m.MatchAll() && andQuery)
            .Should(orQuery)
    ))