1

Started working on NEST api for elastic search recently, got stuck on following query, the data.e would be dynamically populated using the input from client in the HttpGet, ex: user sends eventA,eventB,eventC then we would add in the should part:

GET events/_search
{
  "_source": false, 
  "query": {
    "bool": {
      "must": [
        {"range": {
          "timestamp": {
            "gte": 1604684158527,
            "lte": 1604684958731
            }
        }},
        {"nested": {
          "path": "data",
          "query": {
            "bool": {
              "should": [
                {"match": {
                   "data.e": "eventA"
                }},
                {"match": {
                  "data.e": "eventB"
                }},
                {"match": {
                   "data.e": "eventC"
                }},
              ]
            }
            },
          "inner_hits": {} 
        }}
      ]
    }
  }
}

Following is what I came up with till now:

var graphDataSearch = _esClient.Search<Events>(s => s
                .Source(src => src
                    .Includes(i => i
                        .Field("timestamp")
                        )
                 )
                .Query(q => q
                    .Bool(b => b
                        .Must(m => m
                                .Range(r => r
                                    .Field("timestamp")
                                    .GreaterThanOrEquals(startTime)
                                    .LessThanOrEquals(stopTime)
                                    ),
                                m => m
                                .Nested(n => n
                                    .Path("data")
                                    .Query(q => q
                                        .Bool(bo => bo
                                            .Should(
                                            // what to add here?
                                    )
                                    )
                                )
                        )
                    )
                ));

Can someone please help how to build the should part dynamically based on what input the user sends?

Thanks.

1 Answer 1

3

You can replace the nested query in the above snippet as shown below

// You may modify the parameters of this method as per your needs to reflect user input
// Field can be hardcoded as shown here or can be fetched from Event type as below
// m.Field(f => f.Data.e)

public static QueryContainer Blah(params string[] param)
{
    return new QueryContainerDescriptor<Events>().Bool(
        b => b.Should(
            s => s.Match(m => m.Field("field1").Query(param[0])),
            s => s.Match(m => m.Field("field2").Query(param[1])),
            s => s.Match(m => m.Field("field3").Query(param[2]))));
}

What we are essentially doing here is we are returning a QueryContainer object that will be passed to the nested query

.Query(q => Blah(<your parameters>))

The same can be done by adding this inline without a separate method. You may choose which ever route you perfer. However, in general, having a method of its own increases the readability and keeps things cleaner.

You can read more about Match usage here

Edit:

Since you want to dynamically add the match queries inside this, below is a way you can do it.

private static QueryContainer[] InnerBlah(string field, string[] param)
{
    QueryContainer orQuery = null;
    List<QueryContainer> queryContainerList = new List<QueryContainer>();
    foreach (var item in param)
    {
        orQuery = new MatchQuery() {Field = field, Query = item};
        queryContainerList.Add(orQuery);
    }
    return queryContainerList.ToArray();
}

Now, call this method from inside of the above method as shown below

public static QueryContainer Blah(params string[] param)
{
    return new QueryContainerDescriptor<Events>().Bool(
        b => b.Should(
            InnerBlah("field", param)));
}
Sign up to request clarification or add additional context in comments.

6 Comments

The part inside the should(), needs to be dynamically created, user could send 4 events or 5 events, so we have to match those too, the solution you posted is hardcoded for 3 type of params only which I showed as example.
You can loop over the items that are sent across and generate the inner match query inside of should. Will edit the answer to provide pointers on how to do it
@Ghanendra - Added the dynamic generation logic for multiple match queries
Thanks for the help! I had to modify your code a bit to the following private QueryContainer[] InnerBlah(string field, List<string> param) { QueryContainer orQuery = null; List<QueryContainer> lq = new List<QueryContainer>(); foreach (string item in param) { orQuery = new MatchQuery() { Field = field, Query = item }; lq.Add(orQuery); } return lq.ToArray(); } , Otherwise it was creating multiple should[bool( elements in the Request json
@Ghanendra - Ah! True that. I have amended the answer to reflect the change. Cheers!
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.