Search code examples
elasticsearchnestelasticsearch-net

QueryContainerDescriptor vs QueryContainer vs QueryBase


Can anyone explain what is the difference between QueryContainerDescriptor, QueryContainer & QueryBase?

How can I assign a query (or QueryBase) to QueryContainer?

In the code below, I can assign the same TermQuery to QueryBase and QueryContainer objects:

QueryBase bq = new TermQuery
{
    Field = Field<POCO>(p => p.Title),
    Value = "my_title"
};

QueryContainer tq = new TermQuery
{
    Field = Field<POCO>(p => p.Title),
    Value = "my_title"
};

Also I am not sure if there is any difference between, creating a TermQuery using QueryContainerDescriptor and the above method?

QueryContainer qcd = new QueryContainerDescriptor<POCO>().
    Term(r => r.Field(f => f.Title).Value("my_title"));

Solution

    • QueryBase is the base type for all concrete query implementations

    • QueryContainer is a container for a query. It is used in places where a query is expected.

    • QueryContainerDescriptor<T> is a type for building a QueryContainer using a builder / fluent interface pattern.

    NEST supports both an Object Initializer syntax where requests can be composed through instantiating types and composing an object graph by assigning types to properties, and also a Fluent API syntax, where requests can be composed using Lambda expressions and a fluent interface pattern. All *Descriptor types within NEST are builders for the Fluent API syntax. Use whichever syntax you prefer, or mix and match as you see fit :)

    You might be thinking, why do we need QueryContainer, why not just use QueryBase? Well, within the JSON representation, a query JSON object is keyed against the name of the query as a property of an outer containing JSON object i.e.

    {
      "query": { // <-- start of outer containing JSON object
        "term": { // <-- start of JSON query object
          "field": {
            "value": "value"
          }
        }
      }
    }
    

    Relating back to C# types, QueryBase will be serialized to the query JSON object and QueryContainer will be the outer containing JSON object. To make it easier to compose queries, there are implicit conversions from QueryBase to QueryContainer, so often you just need to instantiate a derived QueryBase implementation and assign it to a property of type QueryContainer

    var client = new ElasticClient();
    
    var termQuery = new TermQuery
    {
        Field = "field",
        Value = "value"
    };
    
    var searchRequest = new SearchRequest<MyDocument>
    {
        Query = termQuery // <-- Query property is of type QueryContainer
    };
    
    var searchResponse = client.Search<MyDocument>(searchRequest);
    

    With QueryContainerDescriptor<T>, you often don't need to instantiate an instance outside of the client call, as an instance will be instantiated within the call. Here's the same request with the Fluent API

    client.Search<MyDocument>(s => s
        .Query(q => q
            .Term("field", "value")
        )
    );