如何在 NEST term 聚合查询 c# 中获得与 kibana 或 postman 一样的 Elasticsearch 结果

How to get Elasticsearch result same as kibana or postman like other rest client in NEST term aggregate query c#

kibana 开发工具

GET gltrans/_search?size=0
{
  "aggs": {
    "code": {
      "terms": {
        "field": "code.keyword"
      },
      "aggs": {
       "total":  {
          "sum": {
             "field": "tot"
          }
       }
      }
    }
  }
}

return

 "buckets" : [
        {
          "key" : "0220",
          "doc_count" : 30182,
          "total" : {
            "value" : 169779.83551708516
          }
        },
        {
          "key" : "3000",
          "doc_count" : 20360,
          "total" : {
            "value" : -477618.27972452715
          }
        },................

嵌套查询

var result = _connectionToEs.EsClient().Search<gltrans>(s => s.Size(0)
    .Aggregations(a => a
        .Terms("code", st => st
            .Field(o => o.code.Suffix("keyword"))
            .Size(10)
            .Aggregations(aa => aa
                .Sum("total", m => m
                    .Field(o => o.tot))))));

return 没有 "key" 如何获取密钥?

 "Items": [
        {
          "tot": {
            "Value": 169779.83551708516,
            "ValueAsString": null,
            "Meta": null
          }
        },
        {
          "tot": {
            "Value": -477618.27972452715,
            "ValueAsString": null,
            "Meta": null
          }
        },

您可以从响应中获取密钥

var result = _connectionToEs.EsClient().Search<gltrans>(s => s.Size(0)
    .Aggregations(a => a
        .Terms("code", st => st
            .Field(o => o.code.Suffix("keyword"))
            .Size(10)
            .Aggregations(aa => aa
                .Sum("total", m => m
                    .Field(o => o.tot))))));

var termsAgg = result.Aggregations.Terms("code");

foreach(var bucket in termsAgg.Buckets)
{
    // get the key
    var key = bucket.Key;

    // get the sum aggregation for this bucket
    var sumAgg = bucket.Sum("total");       
}

看看docs on handling aggregation responses

您发布的 JSON 看起来像是使用另一个 JSON 序列化程序(例如 JSON.NET)序列化 SearchResponse<T> 的结果。这不会像预期的那样工作

  1. SearchResponse<T> 并未设计为再次序列化,只能通过反序列化 Elasticsearch JSON 响应
  2. 来实现
  3. 如果 SearchResponse<T> 被设计为再次序列化,它可能无法与客户端序列化程序以外的任何其他序列化程序一起工作,因为类型可能需要特定的序列化例程。

如果您想将 Elasticsearch 的逐字响应发送回调用者,有两种选择:

1。使用 DisableDirectStreaming() 捕获响应字节,并将这些字节发送给调用者

根据每个请求

var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var settings = new ConnectionSettings(pool).DefaultIndex("gltrans");
var client = new ElasticClient(settings);

var searchResponse = client.Search<gltrans>(s => s
    .RequestConfiguration(r => r
        .DisableDirectStreaming()
    )
);

或所有调用

var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var settings = new ConnectionSettings(pool)
    .DefaultIndex("gltrans")
    .DisableDirectStreaming();
var client = new ElasticClient(settings);

然后响应字节在响应上可用

var bytes = searchResponse.ApiCall.ResponseBodyInBytes;
var json = Encoding.UTF8.GetString(bytes);

并不是说这会在内存中缓冲请求和响应字节,因此会以更高的内存使用和分配为代价。

2。使用低级客户端进行调用,返回低级响应

var client = new ElasticClient();

var searchRequest = new SearchDescriptor<gltrans>()
    .Query(q => q.MatchAll());

var index = "gltrans";

var searchResponse = client.LowLevel.Search<BytesResponse>(
    index, 
    PostData.Serializable(searchRequest));

var bytes = searchResponse.Body;

如果您需要使用它,您可以使用 client.RequestResponseSerializer 将低级别响应转换为高级响应

var bytes = searchResponse.Body;
SearchResponse<gltrans> response = null; 

using (var stream = client.ConnectionSettings.MemoryStreamFactory.Create(bytes))
{
    response = client.RequestResponseSerializer.Deserialize<SearchResponse<gltrans>>(stream);
}