Cugomastik
Cugomastik

Reputation: 1009

Creating Nested Query in Spring Data Elasticsearch

I am totally new to Spring Data Elasticsearch and trying to build a query like the one below; Any help would be greatly appreciated.

 {
   "query":{
      "bool":{
         "must":[
            {
               "bool":{
                  "should":[
                     {
                        "match_phrase":{
                           "firstPhrase":"A"
                        }
                     },
                     {
                        "match_phrase":{
                           "secondPhrase":"B"
                        }
                     },
                     {
                        "nested":{
                           "path":"things",
                           "query":{
                              "bool":{
                                 "should":[
                                    {
                                       "match_phrase":{
                                          "another.phraseOne":"C"
                                       }
                                    },
                                    {
                                       "match_phrase":{
                                          "another.phraseTwo":"D"
                                       }
                                    }
                                 ]
                              }
                           }
                        }
                     }
                  ]
               }
            },
            {
               "match_phrase":{
                  "otherPhase":"E"
               }
            }
         ]
      }
   }
}

I started with creating the first two boolean queries;

BoolQueryBuilder firstBool = QueryBuilders.boolQuery()
                .should(QueryBuilders.matchPhraseQuery("firstPhrase", "A"))
                .should(QueryBuilders.matchPhraseQuery("secondPhrase", "B"));

BoolQueryBuilder secondBool = QueryBuilders.boolQuery()
                .should(QueryBuilders.matchPhraseQuery("another.phraseOne", "C"))
                .should(QueryBuilders.matchPhraseQuery("another.phraseTwo", "D"));

Then I tried to create a nested query (Not sure how to use ScoreMode);

 QueryBuilder nestedQuery= nestedQuery("things",secondBool, ScoreMode.None);

I created another match-phrase which is in the must;

 QueryBuilder third = QueryBuilders.matchPhraseQuery("otherPhrase", "E");

I am not sure how to add them all to create the structure I have and most importantly not sure how to add the nested query to the "must".

  QueryBuilder allQueries = new BoolQueryBuilder()
            .must(first)
            .must(second)
            .must(third); 

And finally, using them all at once;

NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(allQueries).build();

Would this be a right approach to achive what I am trying to generate?

Upvotes: 1

Views: 4075

Answers (1)

Abacus
Abacus

Reputation: 19421

You almost had it, rearranging the order of querybuilding:

import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;

class Scratch {
    public static void main(String[] args) {

        BoolQueryBuilder boolShouldCD = QueryBuilders.boolQuery()
                .should(QueryBuilders.matchPhraseQuery("another.phraseOne", "C"))
                .should(QueryBuilders.matchPhraseQuery("another.phraseTwo", "D"));

        QueryBuilder nestedQuery= QueryBuilders.nestedQuery("things",boolShouldCD, ScoreMode.None);

        BoolQueryBuilder boolShouldABNested = QueryBuilders.boolQuery()
                .should(QueryBuilders.matchPhraseQuery("firstPhrase", "A"))
                .should(QueryBuilders.matchPhraseQuery("secondPhrase", "B"))
                .should(nestedQuery);

        QueryBuilder allQueries = new BoolQueryBuilder()
                .must(boolShouldABNested)
                .must(QueryBuilders.matchPhraseQuery("otherPhrase", "E"));

        System.out.println(allQueries.toString());
    }
}

This is plain Elasticsearch client code, to use that in Spring Data Elasticsearch using the NativeSearchQueryBuilder is the right way to go.


After inlining and static imports you get this shorter code:

import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;

import static org.elasticsearch.index.query.QueryBuilders.*;

class Scratch {
    public static void main(String[] args) {

        QueryBuilder allQueries = new BoolQueryBuilder()
                .must(boolQuery()
                        .should(matchPhraseQuery("firstPhrase", "A"))
                        .should(matchPhraseQuery("secondPhrase", "B"))
                        .should(nestedQuery("things", boolQuery()
                                .should(matchPhraseQuery("another.phraseOne", "C"))
                                .should(matchPhraseQuery("another.phraseTwo", "D")), ScoreMode.None)))
                .must(matchPhraseQuery("otherPhrase", "E"));

        System.out.println(allQueries.toString());
    }
}

Upvotes: 1

Related Questions