弹性巢状查询栏位应存在筛选器

时间:2018-11-14 15:51:49

标签: c# elasticsearch nest

我正在将Elasticsearch 5.2与Nest客户端一起使用进行查询。我有一个有效的查询,日期范围如下:

var boolQuery = new BoolQueryDescriptor<AttractionDocument>();

//https://github.com/elastic/elasticsearch-net/issues/2570 must is not additive, we cannot split out query as before it all has to be one big one

boolQuery.Must(
    mn => AddRegionQuery(permissions, mn),
    mn => AddOffersQuery(permissions, mn),
    mn => request.AddDateFilter ? mn.DateRange(d => d.Field(f => f.AvailableFrom).LessThanOrEquals(DateTime.Now)) : mn,
    mn => request.AddDateFilter ? mn.DateRange(d => d.Field(f => f.AvailableTo).GreaterThanOrEquals(DateTime.Now)) : mn,
    mn => AddGenresQuery(genres, mn)
);

我遇到的问题Availableava并不总是填充,因此对于某些文档来说将不存在。

我尝试添加以下内容:

if (request.AddDateFilter)
{
    boolQuery.MustNot(mn => mn.Exists(f => f.Field(e => e.AvailableTo)));
}

现在的问题是查询变得过于严格。理想情况下,我应该作为存在的一部分?我要达到的目标是,如果我们具有该字段,则仅对AvailableTo应用日期范围,否则忽略并返回没有该日期的结果。如果我删除了AvailableTo部分,我会得到结果。

2 个答案:

答案 0 :(得分:2)

您应该能够将exists查询与range上的AvailableTo查询合并,以包含AvailableTo字段存在且必须满足范围条件的文档,并在AvailableTo查询bool子句中与must_not存在查询创建分词,即反转存在。

类似于以下内容(我已注释掉未提供的查询)

var client = new ElasticClient(settings);

var request = new 
{
    AddDateFilter = true
};

var boolQuery = new BoolQueryDescriptor<AttractionDocument>();

boolQuery.Must(
    // mn => AddRegionQuery(permissions, mn),
    // mn => AddOffersQuery(permissions, mn),
    mn => request.AddDateFilter ? mn.DateRange(d => d.Field(f => f.AvailableFrom).LessThanOrEquals(DateTime.Now)) : mn,
    mn => request.AddDateFilter ? (mn.Exists(d => d.Field(f => f.AvailableTo)) &&
                                  mn.DateRange(d => d.Field(f => f.AvailableTo).GreaterThanOrEquals(DateTime.Now))) ||
                                  !mn.Exists(d => d.Field(f => f.AvailableTo)) : mn //,
    // mn => AddGenresQuery(genres, mn)
);

client.Search<AttractionDocument>(s => s
    .Query(q => q.Bool(b => boolQuery))
);

这将产生以下查询

{
  "query": {
    "bool": {
      "must": [
        {
          "range": {
            "availableFrom": {
              "lte": "2018-11-15T20:18:10.528482+10:00"
            }
          }
        },
        {
          "bool": {
            "should": [
              {
                "bool": {
                  "must": [
                    {
                      "exists": {
                        "field": "availableTo"
                      }
                    },
                    {
                      "range": {
                        "availableTo": {
                          "gte": "2018-11-15T20:18:10.5304815+10:00"
                        }
                      }
                    }
                  ]
                }
              },
              {
                "bool": {
                  "must_not": [
                    {
                      "exists": {
                        "field": "availableTo"
                      }
                    }
                  ]
                }
              }
            ]
          }
        }
      ]
    }
  }
}

由于范围查询和存在查询是谓词(文档匹配条件或不匹配),而不是应该计算相关性得分的查询,因此这些查询可能是bool查询filter子句< / p>

boolQuery.Must(
    // Uncomment below queries, or add (QueryContainer[])null to run
    // mn => AddRegionQuery(permissions, mn),
    // mn => AddOffersQuery(permissions, mn),
    // mn => AddGenresQuery(genres, mn)
).Filter(
    mn => request.AddDateFilter ? mn.DateRange(d => d.Field(f => f.AvailableFrom).LessThanOrEquals(DateTime.Now)) : mn,
    mn => request.AddDateFilter ? (+mn.Exists(d => d.Field(f => f.AvailableTo)) &&
                                  +mn.DateRange(d => d.Field(f => f.AvailableTo).GreaterThanOrEquals(DateTime.Now))) ||
                                  !mn.Exists(d => d.Field(f => f.AvailableTo)) : mn    
);

client.Search<AttractionDocument>(s => s
    .Query(q => q.Bool(b => boolQuery))
);

创建查询

{
  "query": {
    "bool": {
      "filter": [
        {
          "range": {
            "availableFrom": {
              "lte": "2018-11-15T20:22:25.4556963+10:00"
            }
          }
        },
        {
          "bool": {
            "should": [
              {
                "bool": {
                  "filter": [
                    {
                      "exists": {
                        "field": "availableTo"
                      }
                    },
                    {
                      "range": {
                        "availableTo": {
                          "gte": "2018-11-15T20:22:25.4587138+10:00"
                        }
                      }
                    }
                  ]
                }
              },
              {
                "bool": {
                  "must_not": [
                    {
                      "exists": {
                        "field": "availableTo"
                      }
                    }
                  ]
                }
              }
            ]
          }
        }
      ]
    }
  }
}

Operator overloading on queries在这里确实有帮助,可以更简洁地编写复杂的布尔查询

答案 1 :(得分:0)

好吧,以为我对此感到怀疑。我取出了必须的日期范围,并将其设为应有的日期,因此现在查询如下:

 var boolQuery = new BoolQueryDescriptor<AttractionDocument>();

        if (request.AddDateFilter)
        {
            boolQuery.Should(mn => mn.DateRange(d => d.Field(f => f.AvailableTo).GreaterThanOrEquals(DateTime.Now)));
        }


        //https://github.com/elastic/elasticsearch-net/issues/2570 must is not additive, we cannot split out query as before it all has to be one big one
        boolQuery.Must(
            mn => AddRegionQuery(permissions, mn),

            mn => AddOffersQuery(permissions, mn),

            mn => request.AddDateFilter ? mn.DateRange(d => d.Field(f => f.AvailableFrom).LessThanOrEquals(DateTime.Now)) : mn,

            mn => AddGenresQuery(genres, mn)
         );

我现在返回日期和匹配范围内未设置availableTo日期的结果。