elasticsearchnest

elasticsearch NEST : get TopHits result directly without using bucket.TopHits()


With nest I am doing a Terms aggregation.

I am also doing an inner TopHits aggregation.

My result give me all results information in the response object except TopHits values which I can read thanks to TopHits() method.

I would like to have tophits values directly in result without using NEST TopHits() method for reading into aggs. I would like to have all datas in info as we have in elastic search classic requests.

This is what I am actually doing:

My aggregation request:

 var response = Client.Search<myclass>(s => s
                                     .Type("type")
                                      .Aggregations(a => a
                                        .Terms("code_bucket", t => t
                                         .Field("field_of_aggregation")
                                         .Size(30)
                                         .Order(TermsOrder.CountAscending)
                                         .Aggregations(a2 => a2
                                         .TopHits("code_bucket_top_hits", th => th.Size(20))
                                       )
                                       )));

I receive a result object in which I can access all information except TopHits.

if we examine results we can see TopHits values are stored in private field "_hits": enter image description here

If I stringify result object , i can see the total number of TopHits, but I can't see the field _hits so i can see the documents:

JavaScriptSerializer js = new JavaScriptSerializer();
string json = js.Serialize(response);

json does not contains topHits result:

enter image description here

I can access to values but i need to use nest method TopHits():

var firstBucket= response.Aggs.Terms("code_bucket");
foreach (var bucket in firstBucket.Buckets)
            {
                var hits = bucket.TopHits("code_bucket_top_hits");
                foreach (var hit in hits.Documents<myclass>())
                {
                    var prop1= hit.prop1;
                    var prop2= hit.prop2;
                }
            }
   }

But it would be really usefule if i could have all infos in one , like we have when we do elasticsearch request without nest

Do you know if there is a way?


Solution

  • NEST is a higher level abstraction over Elasticsearch that models each request and response with strong types, providing fluent and object initializer syntaxes to build requests, and methods to access portions of the response, without having to handle JSON serialization yourself.

    Sometimes however, you might want to manage this yourself, which is what it sounds like you'd like to do. In these cases, Elasticsearch.Net can be used, which is a low level client for Elasticsearch and is unopinionated in how you model your requests and responses.

    You can use the client in Elasticsearch.Net instead of NEST, however, the good news is NEST uses Elasticsearch.Net under the covers and also exposes the low level client through the .LowLevel property on IElasticClient. Why would you want to use the lowlevel client on NEST as opposed to just using Elasticsearch.Net directly? A major reason to do so is that you can take advantage of strong types for requests and responses when you need to and leverage NEST's usage of Json.NET for serialization, but bypass this and make calls with the low level client when you want/need to.

    Here's an example

    var client = new ElasticClient();
    
    var searchRequest = new SearchRequest<Question>
    {
        Size = 0,
        Aggregations = new TermsAggregation("top_tags")
        {
            Field = "tags",
            Size = 30,
            Order = new[] { TermsOrder.CountAscending },
            Aggregations = new TopHitsAggregation("top_tag_hits")
            {
                Size = 20
            }
        }
    };
    
    var searchResponse = client.LowLevel.Search<JObject>("posts", "question", searchRequest);
    
    // this will be of type JObject. Do something with it
    searchResponse.Body
    

    Here, I can use NEST's object initializer syntax to construct a request, but use the low level client to deserialize the response to a Json.NET JObject. You can deserialize to a T of your choosing by changing it in client.LowLevel.Search<T>(). You could for example use

    var searchResponse = client.LowLevel.Search<string>("posts", "question", searchRequest);
    

    to return a string, or

    var searchResponse = client.LowLevel.Search<Stream>("posts", "question", searchRequest);
    

    to return a stream, etc.