Search code examples
c#elasticsearchnest

How to apply multiple conditions when querying the ElasticSearch server using NEST library?


I have an ElasticSearch server that I want to query using the C# NEST library.

Here is the command I am trying to generate

GET /records/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "available": true
          }
        },
        {
          "match": {
            "out_scope": false
          }
        }
      ]
    }
  }
}

Here is what I have done, I can't seem to find the right way to specify the field name and the value to search for.

var products = await client.SearchAsync<Product>(x => 
                    x.Query(q => 
                        q.Bool(b => 
                            b.Should(bs1 => 
                                bs1.Match(bsm => 
                                    bsm.Field(fff => fff.IsAvailable)
                                       .Term(isAvailable.Value) // This does not work!
                                       ),
                                bs2 =>
                                bs2.Match(bsm =>
                                    bsm.Field(fff => fff.IsAvailable)
                                       .Term(isAvailable.Value) // This does not work!
                                       )
                                )
                            );

How can I correctly specify the field's name and the value to match?


Solution

  • Assuming a model like

    public class Product
    {
        [Keyword(Name = "available")]
        public bool? IsAvailable { get; set; }
        
        [Keyword(Name = "out_scope")]
        public bool? OutScope { get; set; }
    }
    

    Then it would be

        var searchResponse = await client.SearchAsync<Product>(x => x
            .Query(q =>
                q.Bool(b =>
                    b.Should(bs1 =>
                        bs1.Match(bsm =>
                            bsm.Field(fff => fff.IsAvailable)
                               .Query(isAvailable.Value ? "true" : "false")
                               ),
                        bs2 =>
                        bs2.Match(bsm =>
                            bsm.Field(fff => fff.OutScope)
                               .Query(isAvailable.Value ? "true" : "false")
                            )
                        )
                    )
                )
            );
    

    Some things to consider:

    1. The query input for a match query is the .Query field/method. The JSON DSL example shown uses the short form for expressing the query; NEST always generates the long form.
    2. The query input for a match query is ultimately coerced to a string in Elasticsearch. The client exposes it as a string argument.
    3. A term query looks like it might be a better query to use for this example; A term query does not undergo analysis like a match query does. Term-level queries like the term query are suited for structured search.
    4. NEST overloads operators on queries to make writing bool queries more succinct. The above can also be written as
    var searchResponse = client.Search<Product>(x => x
        .Query(q => q
            .Match(bsm => bsm
                .Field(fff => fff.IsAvailable)
                    .Query(isAvailable.Value ? "true" : "false")
                ) || q
            .Match(bsm => bsm
                .Field(fff => fff.OutScope)
                .Query(isAvailable.Value ? "true" : "false")
            )
        )
    );