将 ElasticSearch 查询转换为 Nest c#

Translate ElasticSearch query to Nest c#

我需要一些帮助来根据以下 elasticsearch 查询创建 AggregationDictionary

GET organisations/_search
{
  "size": 0,
  "aggs": {
    "by_country": {
        "nested": {
          "path": "country"
        },
        "aggs": {
          "by_country2": {
            "filter": {
              "bool": {
                "must": [
                  {
                    "term": {
                      "country.isDisplayed": "true"
                    }
                  }
                ]
              }
            },
            "aggs": {
              "by_country3": {
                "terms": {
                  "field": "country.displayName.keyword",
                  "size": 9999
                }
              }   
            }
          }
        }
      }
    }
}

我设法写了这段可怕的代码,我很确定它是错误的,我对此完全陌生。

AggregationDictionary aggs = new AggregationDictionary()
{
  {
    "countries_step1",
    new NestedAggregation("countries_step1")
    {
      Path = "country",
      Aggregations = new AggregationDictionary()
      {
        {
          "countries_step2",
          new FilterAggregation("countries_step2")
          {
            Filter = new BoolQuery
            {
              Must = new QueryContainer[] {
                new NestedQuery
                {
                  Query = new TermQuery
                  {
                    Field = "country.isDisplayed",
                    Value = true
                  }
                }
              }
            },
            Aggregations = new AggregationDictionary
            {
              {
                "countries_step3",
                new TermsAggregation("countries_step3")
                {
                  Field = "country.displayName.keyword",
                  Size = 9999
                }
              }
            }
          }
        }
      }
    }
  }
};

有人可以告诉我我的方向是否正确吗?我正在使用 Nest 6.6.0。是否有任何工具可以帮助进行这些翻译?

到目前为止你所拥有的非常可靠,但是当你尝试使用以下调用执行此聚合时

var searchAsync = await client.SearchAsync<Document>(s => s.Size(0).Aggregations(aggs));

你会得到这个错误

{
  "error" : {
    "root_cause" : [
      {
        "type" : "illegal_argument_exception",
        "reason" : "query malformed, empty clause found at [14:22]"
      }
    ],
    "type" : "illegal_argument_exception",
    "reason" : "query malformed, empty clause found at [14:22]"
  },
  "status" : 400
}

检查发送到 elasticsearch 的请求会告诉我们发生原因

{
  "aggs": {
    "countries_step1": {
      "aggs": {
        "countries_step2": {
          "aggs": {
            "countries_step3": {
              "terms": {
                "field": "country.displayName.keyword",
                "size": 9999
              }
            }
          },
          "filter": {}
        }
      },
      "nested": {
        "path": "country"
      }
    }
  },
  "size": 0
}

filter 子句为空,这是因为您尝试使用嵌套查询但没有通过 path parameter。我们这里不需要嵌套查询(如您的示例查询所示),我们可以将整个查询简化为

var aggs = new AggregationDictionary()
{
    {
        "countries_step1",
        new NestedAggregation("countries_step1")
        {
            Path = "country",
            Aggregations = new AggregationDictionary()
            {
                {
                    "countries_step2",
                    new FilterAggregation("countries_step2")
                    {
                        Filter = new BoolQuery
                        {
                            Must = new QueryContainer[]
                            {
                                new TermQuery
                                {
                                    Field = "country.isDisplayed",
                                    Value = true
                                }
                            }
                        },
                        Aggregations = new AggregationDictionary
                        {
                            {
                                "countries_step3",
                                new TermsAggregation("countries_step3")
                                {
                                    Field = "country.displayName.keyword",
                                    Size = 9999
                                }
                            }
                        }
                    }
                }
            }
        }
    }
};

现在我们有一个有效的请求发送到 elasticsearch。

这里有几处我们可以改进:

1.删除不必要的布尔查询

Filter = new BoolQuery
{
    Must = new QueryContainer[]
    {
        new TermQuery
        {
            Field = "country.isDisplayed",
            Value = true
        }
    }
},

Filter =
    new TermQuery
    {
        Field = "country.isDisplayed",
        Value = true
    },

2。替换字符串字段名称

通常,当从 .Net 进行调用时,有某种 POCO 类型可以帮助我们将强类型请求写入 elasticsearch,从而帮助我们管理干净的代码和重构。有了这个,我们可以从

更改字段定义
"country.displayName.keyword"

Infer.Field<Document>(f => f.Country.FirstOrDefault().DisplayName.Suffix("keyword"))

我的类型定义

public class Document
{
    public int Id { get; set; }
    [Nested]
    public List<Country> Country { get; set; }
}

public class Country
{
    public bool IsDisplayed { get; set; }
    public string DisplayName { get; set; }
}

3。考虑使用流畅的语法

使用 NEST,您可以通过两种方式编写查询:使用对象初始化器语法(您已经这样做了)或借助流畅的语法。 Have a look。尝试用流畅的语法编写上面的查询,你会得到类似

的东西
var searchResponse = await client.SearchAsync<Document>(s => s
    .Size(0)
    .Aggregations(a => a.Nested("by_country", n => n
        .Path(p => p.Country)
        .Aggregations(aa => aa
            .Filter("by_country2", f => f
                .Filter(q => q
                    .Term(t => t
                        .Field(field => field.Country.FirstOrDefault().IsDisplayed)
                        .Value(true)))
                .Aggregations(aaa => aaa
                    .Terms("by_country3", t => t
                        .Field(field => field.Country.FirstOrDefault().DisplayName.Suffix("keyword"))
                        .Size(9999)
                    )))))));

我发现它更容易理解和编写,也许对您来说也会更好。

作为最后的说明,请查看 docs 并检查如何调试查询。

希望对您有所帮助。