Search code examples
c#opensearch

How to query with `OpenSearch.Client` and add predetermined boolean clauses into queries


I use the OpenSearch.Client library to query OpenSearch and I perform complex queries like this one:

    var response = openSearchClient.Search<Document>(s => s
        .Index(documentsIndexName)
        .Query(q => q
            .Bool(bq => bq
                .Must(mq => {
                    return mq.Term("field1", value1) && (
                        mq.Term("field2", value2) || mq.Term("field3", value3)
                    );
                })
            )
        )
    );

I now want to introduce some constant boolean clauses, that are a result of querying data outside of OpenSearch, that will kinda short-circuit parts the query. Something like this, that eliminates part of the query (note: the following code does not compile):

    bool requireSearchingIntoField1 = false; // This value is calculated with some logic.
    var response = openSearchClient.Search<Document>(s => s
        .Index(documentsIndexName)
        .Query(q => q
            .Bool(bq => bq
                .Must(mq => {
                    return (!requireSearchingIntoField1 || mq.Term("field1", value1)) && (
                        mq.Term("field2", value2) || mq.Term("field3", value3)
                    );
                })
            )
        )
    );

I guess I could do this with pure C# code like that:

    bool requireSearchingIntoField1 = false; // This value is calculated with some logic.
    var response = openSearchClient.Search<Document>(s => s
        .Index(documentsIndexName)
        .Query(q => q
            .Bool(bq => bq
                .Must(mq => {
                    var q = mq.Term("field2", value2) || mq.Term("field3", value3);
                    if(requireSearchingIntoField1)
                    {
                        q = q && q.Term("field1", value1);
                    }
                    
                    return q;
                })
            )
        )
    );

...but I wonder if there is a fancier way to do this, and then let the library or OpenSearch simplify the query.


Solution

  • OK, I think I've found it!

    All I need to do is use the mq.MatchNone() for false and mq.MatchAll() for true. Like this:

    bool requireSearchingIntoField1 = false; // This value is calculated with some logic.
    var response = openSearchClient.Search<Document>(s => s
        .Index(documentsIndexName)
        .Query(q => q
            .Bool(bq => bq
                .Must(mq => {
                    return (BoolToQuery(!requireSearchingIntoField1) || mq.Term("field1", value1)) && (
                        mq.Term("field2", value2) || mq.Term("field3", value3)
                    );
                })
            )
        )
    );
    
    
        QueryContainer BoolToQuery(bool value)
        {
            return value ? mq.MatchAll() : mq.MatchNone();
        }