Search code examples
c#asp.netelasticsearchelasticsearch-dsl

Dynamically Build Search Query using Elasticsearch .NET client 8.3


I am new to ElasticSearch. I have a query that works but the values are hardcoded. I need to update the query to use a list of strings in the 'should' clause. I am not finding much documentation for the dotnet client. Is there a way to pass the 'should' clause a list of strings instead of hardcoding them here?

public async Task<SearchResponse<SubmissionDto>> GetRapbacksAsync(DateTime startDate, DateTime endDate, string destination)
        {
            ElasticsearchClient localClient = GetClient(destination);
            var rapbacks = await localClient.SearchAsync<SubmissionDto>(SUBMISSION_INDEX, s => s
                .Query(q => q
                    .Bool(b => b
                        .Should( // Changed Must to Should for OR condition
                            ss => ss.Term(tt => tt.Field(f => f.Tot).Value("RBIHS".ToLower())),
                            ss => ss.Term(tt => tt.Field(f => f.Tot).Value("RBMNT".ToLower())),
                            ss => ss.Term(tt => tt.Field(f => f.Tot).Value("RBSCRM".ToLower())),
                            ss => ss.Term(tt => tt.Field(f => f.Tot).Value("RBN".ToLower())),
                            ss => ss.Term(tt => tt.Field(f => f.Tot).Value("RBSCVL".ToLower())),
                            ss => ss.Term(tt => tt.Field(f => f.Tot).Value("RBRPT".ToLower())),
                            ss => ss.Term(tt => tt.Field(f => f.Tot).Value("RBRPTR".ToLower()))
                        )
                        .MinimumShouldMatch(1) // At least one of the Should conditions must match
                        .Must(
                            ss => ss.Range(rr => rr
                                .DateRange(dr => dr
                                    .Field(f => f.SubmissionCreation)
                                    .Gte(startDate.ToString("yyyy/MM/dd"))
                                    .Lte(endDate.ToString("yyyy/MM/dd"))
                                ))))).Size(MAX_DOCUMENTS).Sort(sort => sort
                    .Field(f => f.SubmissionCreation, d => d.Order(SortOrder.Desc)))
            );
            return rapbacks;
        }

I tried a bunch of queries from chat gpt however it keeps giving responses from the old NEST client. Not sure it has all the info on the dotnet client.


Solution

  • Something like this should do the trick, though you might want to look into using the Terms query instead if looking for any overlap of values in a single field.

    await localClient.SearchAsync<SubmissionDto>("myindex", s => s
        .Query(q => q
            .Bool(b => b
                .Should(sh =>
                    values
                        .Select<string, Action<QueryDescriptor<SubmissionDto>>>(value => 
                            sh => sh.Term(t => t.Field(f => f.Tot).Value(value.ToLower()))
                        )
                        .ToArray()
                )
            )
        )
    );
    

    Here is an example of using a the aforementioned Terms query, a bit nicer to read:

    await localClient.SearchAsync<SubmissionDto>("myindex", s => s
        .Query(q => q
            .Terms(t => t
                .Field(f => f.Tot)
                .Terms(new TermsQueryField(values.Select(value => FieldValue.String(value)).ToArray()))
            )
        )
    );