Search code examples
c#elasticsearch.net-corenest

Search the fields of tickets with date range


I have the following model

public class Ticket
{
    public string Id { get; set; }

    public string Question { get; set; }

    public DateTime CreateDate { get; set; }

    public DateTime ClosedDate { get; set; }

    public int Votes { get; set; }
}

I'm using ElasticSearch Nest client to search for tickets where any field contains a certain text within a date range.

I tried the following:

        var result = client.Search<Ticket>(
            s => s.Query(q => 
                            q.Bool(b => 
                                b.Must(ms => ms.QueryString(qs => qs.Query(term)))
                                 .Filter(f => 
                                         f.Bool(bb => 
                                                bb.Must(ms => ms.DateRange(dr => dr.GreaterThanOrEquals(from).LessThanOrEquals(to))
            ))))));

It returns all tickets regardless of the time specified.

It also only search for complete word while I want to search for any part of the word in the text.

Any ideas?


Solution

  • The DateRange query requires a Field value for the field in Elasticsearch to run against. When a value is not provided for this, NEST considers the query to be conditionless and does not serialize it as part of the query sent.

    For example, given

    var term = "term";
    var to = DateTime.Now;
    var from = to.AddDays(-7);
    

    your current query serializes to

    {
      "query": {
        "bool": {
          "must": [
            {
              "query_string": {
                "query": "term"
              }
            }
          ]
        }
      }
    }
    

    If the Field is added

    var result = client.Search<Ticket>(s => s
        .Query(q => q
            .Bool(b => b
                .Must(ms => ms
                    .QueryString(qs => qs
                        .Query(term)
                    )
                )
                .Filter(f => f
                    .Bool(bb => bb
                        .Must(ms => ms
                            .DateRange(dr => dr
                                .Field(df => df.CreateDate)
                                .GreaterThanOrEquals(from)
                                .LessThanOrEquals(to)
                            )
                        )
                    )
                )
            )
        )
    );
    

    this now serializes to

    {
      "query": {
        "bool": {
          "must": [
            {
              "query_string": {
                "query": "term"
              }
            }
          ],
          "filter": [
            {
              "bool": {
                "must": [
                  {
                    "range": {
                      "createDate": {
                        "gte": "2018-07-17T12:20:02.8659934+10:00",
                        "lte": "2018-07-24T12:20:02.8659934+10:00"
                      }
                    }
                  }
                ]
              }
            }
          ]
        }
      }
    }
    

    Using operator overloading on queries, this can be written more succinctly

    var result = client.Search<Ticket>(s => s
        .Query(q => q
            .QueryString(qs => qs
                    .Query(term)
            ) && +q
            .DateRange(dr => dr
                .Field(df => df.CreateDate)
                .GreaterThanOrEquals(from)
                .LessThanOrEquals(to)
            )
        )
    );
    

    which serializes to

    {
      "query": {
        "bool": {
          "must": [
            {
              "query_string": {
                "query": "term"
              }
            }
          ],
          "filter": [
            {
              "range": {
                "createDate": {
                  "gte": "2018-07-17T12:21:50.2175114+10:00",
                  "lte": "2018-07-24T12:21:50.2175114+10:00"
                }
              }
            }
          ]
        }
      }
    }