Jacques
Jacques

Reputation: 384

Elastic search recreating query in NEST not working

Im trying to recreate query in from Kibana dev into NEST but it's not giving me the same results.

The query I run in Kibana works perfectly returning 1 result

Here is my Kibana query:

GET /cats/_doc/_search
{   
"query":{
    "bool" : {     
        "minimum_should_match" :3,
        "should": [
           {"term" : { "name" : "cats" }},
           {"term" : { "name" : "are" }},
           {"term" : { "name" : "craze" }}

         ]
      }
   }
}

When I create the query in NEST it returns no results except when I change the minimum_should_match to 1 (it then returns 2 results )

Here is my NEST query:

        string[] tmp = "Cats are craze".ToLower().Split(new string[] { " " }, StringSplitOptions.None);

        var cats = ElasticMain.Search<dynamic>(s => s.From(from).Size(20).Query(
                  q => q.Bool(
                      b => b.MinimumShouldMatch(tmp.Length).Should(
                          l => l.Terms(
                              t => t.Name("name").Field("name").Terms(tmp)))

               )));

What am I doing wrong?

Upvotes: 0

Views: 299

Answers (1)

Russ Cam
Russ Cam

Reputation: 125488

You are not building the same query in NEST as you have in Kibana; the former is using a terms query, whilst the latter is using three term queries in a bool query should clause. The semantics of these two queries in combination with minimum should match is different.

The same query in NEST is

var client = new ElasticClient();

string[] tmp = "Cats are craze".ToLower().Split(new string[] { " " }, StringSplitOptions.None);
var from = 0;

var searchResponse = client.Search<dynamic>(s => s
    .From(from)
    .Size(20)
    .Query(q => q
        .Bool(b =>
        {
            b.MinimumShouldMatch(tmp.Length);
            var shouldQueries = 
                new List<Func<QueryContainerDescriptor<dynamic>, QueryContainer>>(tmp.Length);

            for (var i = 0; i < tmp.Length; i++)
            {
                var value = tmp[i];              
                shouldQueries.Add(qc => qc.Term(t => t
                    .Field("name")
                    .Value(value)
                ));
            }

            b.Should(shouldQueries);

            return b;
        })
    )
);

which builds the following query

{
  "from": 0,
  "query": {
    "bool": {
      "minimum_should_match": 3,
      "should": [
        {
          "term": {
            "name": {
              "value": "cats"
            }
          }
        },
        {
          "term": {
            "name": {
              "value": "are"
            }
          }
        },
        {
          "term": {
            "name": {
              "value": "craze"
            }
          }
        }
      ]
    }
  },
  "size": 20
}

When the number of should clauses that must match is equal to minimum_should_match as in this example, it's effectively the same as saying that they are all must clauses (without the minimum_should_match)

var client = new ElasticClient();

string[] tmp = "Cats are craze".ToLower().Split(new string[] { " " }, StringSplitOptions.None);
var from = 0;

var searchResponse = client.Search<dynamic>(s => s
    .From(from)
    .Size(20)
    .Query(q => 
        tmp.Aggregate((QueryContainer)null, (qc, v) => qc && q.Term("name", v))
    )
);

which takes advantage of operator overloading on NEST queries to && them together, to build the query

{
  "from": 0,
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "name": {
              "value": "cats"
            }
          }
        },
        {
          "term": {
            "name": {
              "value": "are"
            }
          }
        },
        {
          "term": {
            "name": {
              "value": "craze"
            }
          }
        }
      ]
    }
  },
  "size": 20
}

Upvotes: 1

Related Questions