具有多个术语的 NEST 条件过滤器查询

Posted

技术标签:

【中文标题】具有多个术语的 NEST 条件过滤器查询【英文标题】:NEST Conditional filter query with multiple terms 【发布时间】:2016-06-08 09:00:05 【问题描述】:

我想做一个这样的 ElasticSearch 查询:


    "query" :
    
        "bool" :
        
            "filter" : [
                
                    "terms" :
                    
                        "name" : ["name1", "name2"]
                    
                ,
                
                    "terms" :
                    
                        "color" : ["orange", "red"]
                    
                
            ]
        
    

我尝试在 NEST 中像这样实现它:

_elasticClient
    .SearchAsync<MyDocument>(s =>
        s.Index("myindex")
            .Query(q => q
                .Bool(bq => bq
                    .Filter(fq =>
                    
                        QueryContainer query = null;

                        if (nameList.Any()) 
                            query &= fq.Terms(t => t.Field(f => f.Name).Terms(nameList));
                        

                        if (colorList.Any()) 
                            query &= fq.Terms(t => t.Field(f => f.Color).Terms(colorList));
                        

                        return query;
                    )
                )
            )
    );

但这给了我一个这样的查询,其中过滤器被包裹在 bool must 中:


    "query" :
    
        "bool" :
        
            "filter" : [
                
                    "bool" :
                    
                        "must" : [
                            
                                "terms" :
                                
                                    "name" : ["name1", "name2"]
                                
                            ,
                            
                                "terms" :
                                
                                    "color" : ["orange", "red"]
                                
                            
                        ]
                    
                
            ]
        
    

我应该如何更改我的 NEST 代码以提供正确的查询?除了 QueryContainer 之外,是否必须将我的条款添加到其他内容中?

【问题讨论】:

【参考方案1】:

如果要检查条件过滤器,可以在进行查询之前创建过滤器列表,如下所示:

var nameList = new[] "a", "b";
var colorList = new[] 1, 2;

var filters = new List<Func<QueryContainerDescriptor<MyDocument>, QueryContainer>>();
if (nameList.Any())

     filters.Add(fq=> fq.Terms(t => t.Field(f => f.Name).Terms(nameList)));


if (colorList.Any())

    filters.Add(fq => fq.Terms(t => t.Field(f => f.Color).Terms(colorList)));


ISearchResponse<Property> searchResponse =
     elasticClient.Search<MyDocument>(x => x.Query(q => q
     .Bool(bq => bq.Filter(filters))));

如果您在进行过滤查询之前不需要检查任何条件,那么您可以有类似的东西:

ISearchResponse<MyDocument> searchResponse =
elasticClient.Search<MyDocument>(x => x.Query(q => q
.Bool(bq => bq
.Filter(
        fq => fq.Terms(t => t.Field(f => f.Name).Terms(nameList)),
        fq => fq.Terms(t => t.Field(f => f.Color).Terms(colorList))
        ))));

【讨论】:

【参考方案2】:

bool 查询的Filter 方法采用params Func&lt;QueryContainerDescriptor&lt;T&gt;, QueryContainer&gt;[],以便您可以传递多个表达式来表示多个过滤器

var nameList = new string[]  "name1", "name2" ;
var colorList = new string[]  "orange", "red" ;

client.SearchAsync<MyDocument>(s => s
        .Index("myindex")
        .Query(q => q
            .Bool(bq => bq
                .Filter(
                    fq => fq.Terms(t => t.Field(f => f.Name).Terms(nameList)),
                    fq => fq.Terms(t => t.Field(f => f.Color).Terms(colorList))
                )
            )
        )
);

导致


  "query": 
    "bool": 
      "filter": [
        
          "terms": 
            "name": [
              "name1",
              "name2"
            ]
          
        ,
        
          "terms": 
            "color": [
              "orange",
              "red"
            ]
          
        
      ]
    
  

NEST also has the concept of conditionless queries,也就是说,如果一个查询被确定为无条件的,那么它将作为请求的一部分被序列化。

无条件是什么意思?好吧,这取决于查询;例如,在 terms 查询的情况下,如果以下任何一项为真,则认为它是无条件的

field 没有值 术语值列表是null terms 值是一个空集合 术语值列表有值,但它们都是null 或空字符串

演示

var emptyNames = new string[] ;
string[] nullColors = null;

client.SearchAsync<MyDocument>(s =>
s.Index("myindex")
    .Query(q => q
        .Bool(bq => bq
            .Filter(
                fq => fq.Terms(t => t.Field(f => f.Name).Terms(emptyNames)),
                fq => fq.Terms(t => t.Field(f => f.Color).Terms(nullColors)))
        )
    )
);

结果


无条件查询有助于更轻松地编写 NEST 查询,因为您无需在构造查询之前检查集合是否具有值。您可以在每个查询的基础上更改无条件语义using .Strict() and .Verbatim()

【讨论】:

【参考方案3】:
var searchResponse = client.Search<EventData>(s => s
            .From(0)
            .Query(q => q
                    .Bool(bq => bq
                    .Filter(
                            fq => fq.Terms(t => t.Field(f => f.Client.Id).Terms(17)),
                            fq => fq.Terms(t => t.Field(f => f.Item.Id).Terms(**new[]  34983, 35430, 35339, 35300 **)), 
                            fq => fq.Terms(t=>t.Field(f=>f.Event).Terms("Control de Panico")),
                            fq => fq.DateRange(dr => dr.Field(f => f.DateTime)
                                .GreaterThanOrEquals(new DateTime(2018, 07, 01))
                                .LessThanOrEquals(new DateTime(2018, 10, 02)))
                            )
                  ))
            .Size(2000)
            .Sort(g => sortDescriptor)
            );

【讨论】:

以上是关于具有多个术语的 NEST 条件过滤器查询的主要内容,如果未能解决你的问题,请参考以下文章

使用具有多个搜索条件的 Knex.js 和 SQL 的条件过滤器

如何过滤具有多个条件的托管对象实体

和/或具有满足多个条件的单因素水平的条件过滤

javascript 过滤具有多个条件的对象数组。

过滤具有多个条件的列表

Pandas:过滤具有多个字符串条件的行[重复]