Elastic Search .Net Combine Must and Should Showing All Queries rather than correct combination

I'm struggling to generate a .Net search which will combine a must field of one value and a should search of one of two values from a different field - e.g. results must contain value1 from field1 and either value2 or value3 from field2.

I have successfully created that search in Elastic Search. See below:-

GET stagingstock/_search
{
  "size" : 1000,
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "field1": {
              "query": "value1",
              "operator": "and",
              "fuzziness": "auto"
            }    
          }
        },
        {"bool": {
      "should": [
        {
          "match": {
            "field2": {
              "query": "value2",
              "operator": "or",
              "fuzziness": "auto"
            }    
          }
        },
        {
          "match": {
            "field2": {
              "query": "value3",
              "operator": "or",
              "fuzziness": "auto"
            }    
          }
        }
      ]
          
        }}
      ]
    }
  },
  "sort": [
    {
      "updatedDate": {
        "order": "desc"
      }
    }
  ]
}

But when I try to parse that query into .Net it is returning either value1, value2 or value3. Code below:

resp2 = await client.SearchAsync<ElasticStock>(s => s
	.Index(index)
	.Size(10000)
	.Query(q => q.Bool(
		b => b.Must(
			mq => mq.Match(
				m => m.Field(
					f => f.Field1)
						.Fuzziness(fuzz)
						.Query(value1)
						.Operator(Operator.And)
					).Bool(
						b2 => b2.Should(
							sq => sq.Match(m2 => m2.Field(f => f.Field2).Query(value2)),
							sq => sq.Match(m2 => m2.Field(f => f.Field2).Query(value3))
						)
					)
				)
			)
		)
	.Sort(so => so
		.Field(f => f.UpdatedDate, new FieldSort { Order = SortOrder.Desc }))
);

Can someone tell me what I am doing wrong in .Net as the logic seems the same to me?

Note: I removed the Or Operators in the .Net code but that didn't make any difference to the search.

Hi @GaryBtP ,

sorry, please ignore this part. I did not read your JSON payload correctly due to the strange indentation :stuck_out_tongue_winking_eye:

IMO your original query is already incorrect. A "bool" query with both "must" and "should" does not achieve the desired result. It only matches the "must" parts and optionally boost query score/relevance depending on the "should" part.

You want to nest "bool" queries to achieve a strict if (a == x && (b == y || b == z)):

var resp2 = await client.SearchAsync<ElasticStock>(s => s
    .Index(index)
    .Size(10000)
    .Query(q => q
        .Bool(
            b => b
                .Must(
                    mq => mq.Match(m => m
                        .Field(f => f.Field1)
                        .Fuzziness(new Fuzziness("auto"))
                        .Query("value1")
                        .Operator(Operator.And)
                    ),
                    mq => mq.Bool(b => b
                        .Should(
                            sq => sq.Match(m2 => m2.Field(f => f.Field2).Query("value2")),
                            sq => sq.Match(m2 => m2.Field(f => f.Field2).Query("value3"))
                        )
                    )
                )
            )
    )
    .Sort(so => so
        .Field(f => f.UpdatedDate, new FieldSort { Order = SortOrder.Desc })
    )
);

I tried to visualize the query DSL syntax tree as an ASCII art. Hope this helps :slightly_smiling_face:

// (Field1 == value1 && (Field2 == value2 || Field2 == value3))
// ^       ^         ^  ^       ^         ^         ^        ^^
// :       :         :  :       :         :         :        ::. outer bool query end
// :       :         :  :       :         :         :        :. inner bool query end
// :       :         :  :       :         :         :. match query
// :       :         :  :       :         :. inner bool query "should"
// :       :         :  :       :. match query
// :       :         :  :. inner bool query start
// :       :         :. outer bool query "must"
// :       :. match query
// :. outer bool query start
1 Like

Thanks. That seems to have worked. I thought by putting the Bool inside the first match I was doing that but clearly not. I did notice the difference between Elasticsearch and .Net was the comma but didn't realise how big of a difference that made.

Greatly appreciate the help.