Search code examples
elasticsearchnestelasticsearch-6

Writing a NEST query to sort aggregation buckets by score


What I want is to create an aggregation bucket for each unitId (which is a field in my document). I want each bucket to be ordered by the max score in that bucket. I have written the following query which does what I want:

 "aggs": {
    "UnitAggregationBucket": {
      "terms": {
        "field": "unitId",
        "size": 10,
        "order": {
          "max_score": "desc"
        }
      },
      "aggs": {
        "max_score": {
          "max": {
            "script": "_score"
          }
        }
      }
    }

I am using script to find the max score per bucket, in a sub-aggregation. I don't know how to write the above query using NEST?


Solution

  • Upadate:

    This is the answer that I got from Elastic Community:

    With 6.x, this would be something like:

    var client = new ElasticClient();
    
    var searchResponse = client.Search<object>(s => s
        .Aggregations(a => a
              .Terms("UnitAggregationBucket", t => t
                  .Field("unitId")
              .Size(10)
              .Order(o => o
                  .Descending("maximum_score")
              )           
                .Aggregations(aa => aa
                  .Max("maximum_score", m => m
                      .Script("_score")
                  )
              )
          )
      ) 
    );
    
    var termsAgg = searchResponse.Aggregations.Terms("UnitAggregationBucket");
    
    foreach(var bucket in termsAgg.Buckets)
    {     
        // do something with buckets  
        var maxScore = bucket.Max("maximum_score").Value; 
    }
    

    Note that you can't use max_score for the name of the aggregation as it's a reserved keyword name in the client, which the client uses in its heuristics based aggregation response JSON deserialization method.


    Original Answer

    I managed to write the following NEST Query:

    var unitAggregations = new TermsAggregation("UnitAggregationBucket")
    {
        Size 10,
        Field = Field<MyDocument>(p => p.UnitId),
        Order = new List<TermsOrder>
        {
            new TermsOrder()
            {
                Key = "max_score_in_bucket",
                Order = SortOrder.Descending
            }
        },
        Aggregations = new MaxAggregation("max_score_in_bucket", string.Empty)
        {
            Script = new InlineScript("_score")
        }
    };
    

    Which produces, the following json:

    "aggs": {
        "UnitAggregationBucket": {
          "aggs": {
            "max_score_in_bucket": {
              "max": {
                "script": {
                  "source": "_score"
                }
              }
            }
          },
          "terms": {
            "field": "unitId",
            "order": [
              {
                "max_score_in_bucket": "desc"
              }
            ],
            "size": 10
          }
        }
      }
    

    It's not the exact json that I wanted, but it does what I want.


    Note: max_score is a reserved key-word in Elasticsearch, so I had to use a different name: max_score_in_bucket