4

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

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

                                        )
                                )
                        )   

                );

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

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

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

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

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

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

问题:

我应该使用什么来构建嵌套查询?它是 FilterDescriptor 吗?如何将它们组合起来,将嵌套查询添加到搜索方法中?

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

4

2 回答 2

12

我同意 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)
    ))
于 2016-01-04T16:37:30.693 回答
1

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

组合嵌套查询

对于您的用例,我将使用带有or子句的bool查询类型。获取书籍的查询或将是:mustshouldCondition 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"
                              }
                           }
                        ]
                     }
                  }
               }
            }
         ]
      }
   }
}

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

未分析

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

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

978-3-16-148410-0

将被索引为:

978
3
16
148410
0

使用完全相同的 ISBN 号进行搜索会为您提供所有在其 ISBN 号中具有子编号之一的书籍。如果要防止这种情况,请使用not_analyzedindex-type 和Multi-fields

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

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

books.isbn.raw

希望这可以帮助。

于 2015-12-28T21:44:57.037 回答