Complex queries in OpenSearch via Java client

OpenSearch is a text-based search engine that is forked from ElasticSearch and is based on Apache Lucene.

OpenSearch provides full-text search and we can have complex query structures as well.

Let’s say we have a query where we want certain things to must match and few things can or cannot match (optional).

In such condition OpenSearch provide us a boolean query with multiple options like must, should, must_not, filter.

Using these parameters we can form the query.

Let us consider the following sample document.

{
  "name": "prashant",
  "age": 27,
  "salary": 5000,
  "gender": "male"
}

There are multiple entries of these, and we want to form a query where we want the age to be 27, but gender can be male or female. In this case, we can use a combination of must and should queries.

{
    "query": {
        "bool": {
            "must": [
                {"match": {"age": 27}}
            ],
            "should": [
                {"match": {"gender": "male"}},
                {"match": {"gender": "female"}},
            ],
            "minimum_should_match": 1
        }
    }
}

Here we have also used minimum_should_match and set it to 1, this is an optional field for should queries that will return the result if any one of the above should query matches.

You can use the combination and form your search query as per your requirement.

Similary, we can do the same in Java or Spring boot, using the Java SDK provided by OpenSearch.

MatchQuery mustMatchQuery1 = new MatchQuery.Builder().field("age").query(27).build();

// create a list of queries
List mustQueries = new ArrayList<>();
mustQueries.add(mustMatchQuery1._toQuery());

//create multiple queries
MatchQuery shouldMatchQuery1 = new MatchQuery.Builder().field("gender").query("male").build();
MatchQuery shouldMatchQuery2 = new MatchQuery.Builder().field("gender").query("female").build();

// create a list of queries
List<Query> shouldQueries = new ArrayList<>();
shouldQueries.add(shouldMatchQuery1._toQuery());
shouldQueries.add(shouldMatchQuery2._toQuery());

// pass the list to boolean query for each query to must not match
BoolQuery boolQuery = new BoolQuery.Builder().must(mustQueries).should(shouldQueries).minimumShouldMatch("1").build();

// perform the search
SearchResponse<Object> searchResponse = client.search(s -> {
    s.query(boolQuery._toQuery());
    return s;
}, Object.class);

// store the result
List<Object> output = new ArrayList<>();
for (int i = 0; i < searchResponse.hits().hits().size(); i++) {
    output.add(searchResponse.hits().hits().get(i).source());
}