2

I am trying to convert some Java High Level REST Client code to new Elasticsearch Java API Client.

I want to convert this query which retrieves the contents if the id is equal to 10 or 20.

SearchRequest searchRequest = new SearchRequest().indices(indexName);

    List<Long> ids = new ArrayList<>();
    ids.add(10l);
    ids.add(20l);

    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

    searchSourceBuilder.query(QueryBuilders.boolQuery()
        .must(QueryBuilders.termQuery("id", ids)));

        searchRequest.source(searchSourceBuilder);

With the new Java API Client I've built something like this.

TermsQueryField termsQueryField = new TermsQueryField.Builder()
         .value(/*Expects List<FieldValue>*/)
         .build();

TermsQuery idTerms = new TermsQuery.Builder()
        .field("id")
        .terms(termsQueryField)
        .build();

Query idQuery = new Query.Builder()
        .terms(idTerms)
        .build();

BoolQuery boolQuery = new BoolQuery.Builder()
        .must(idQuery)
        .build();

Query query = new Query.Builder()
        .bool(boolQuery)
        .build();

SearchRequest searchRequest = new SearchRequest.Builder()
        .index(indexName)
        .query(query)
        .build();

I can add the termQuery options for single values but I could not find a way to add a list to the query.

I've came across with TermsQuery but that requires the values to be set as a List<FieldValue> so that's not very helpful.

Note: I know I can use lambda expressions for constructing these objects but I am trying to be as verbose as possible until I figure out how to use the new client.

cagdasalagoz
  • 460
  • 1
  • 12
  • 22
  • 1
    You can create two different `TermQuery` query in a `bool`->`should` clause. You cannot send multiple values to `TermQuery` becasue it expects a single value. Or you can use the `TermsQuery` as you stated in your question – YD9 May 11 '22 at 12:25
  • Have you tried building that `List`? Should be straightforward enough: just instantiate an `ArrayList` and then do `lst.add(FieldValue.of("strValue")` – ilvar May 12 '22 at 10:00
  • @ilvar Yes I know I can do that but that doesn't sound efficient. Why should I have to loop every ID just to create a query? There must be an easier way. That's what I am looking for. – cagdasalagoz May 13 '22 at 07:38
  • 1
    Did you get anywhere with this? I'm trying to the same. I'm finding the new Java Client quite...cumbersome / terrible for examples – MetaCoder Nov 29 '22 at 12:26
  • 1
    @MetaCoder I don't have any solutions at the moment. Sorry about that. I can't remember how I solved this but I believe it was not a pretty one so I did not post an answer. – cagdasalagoz Dec 01 '22 at 12:43

2 Answers2

2

Using streams seems currently to be the simplest way to create the list of terms:

List<String> countries = List.of("afg", "aus");

TermsQueryField countryTerms = new TermsQueryField.Builder()
    .value(countries.stream().map(FieldValue::of).toList())
    .build();

SearchRequest sr = SearchRequest.of(s -> s
    .query(q -> q
        .bool(b -> b 
            .filter(mCtry -> mCtry
                .bool(bCtry -> bCtry
                    .should(shdCtry -> shdCtry
                        .terms(tCtry -> tCtry
                            .field("country")
                            .terms(countryTerms)
                        )
                    )
                )
            )
        )
    )
);
0

You can use boolQuery like this

boolQuery().apply {
            ids.forEach {
                should(matchQuery("test.id", it))
            }
        }

Above solution has a limit on the criterias to add. Otherwise use

(termsQuery("FIELD", [value1, value2,value3])

bluecheese
  • 41
  • 3