Correct way to search with a PIT using the elasticsearch-java

In the context of converting from the high level client to the newer elasticsearch-java SDK, how should I provide a PIT when searching with the elasticsearch-java client? I cannot find any guidance. I think I am doing it right but if I want to use the option with a lambda providing a builder, I need to supply a the SearchRequest.Builder type for the lambda parameter. Otherwise I have a builder with no pit option. Is it best pratice to provide the type with the lambda parameter in this case? I am not far enough in my conversion to start changing and running my unit tests.

I have two options in the following code:

  1. Use a search with a builder but provide the desired type, which might not work at runtime.
  2. Use a builder separately and provide a SearchRequest when calling the search.
public <T> SearchResponse<T> executeRequest(final Selection selection, final Class<T> clazz) throws IOException {
        // specify SearchRequest.Builder her otherwise you just get a Builder type which does not have a .pit(...) method
        //REMARK: no sure if this works at runtime.
        return client.search((SearchRequest.Builder searchRequestBuilder) -> searchRequestBuilder
                        .pit(pitBuilder -> pitBuilder.id(selection.pitId())
                                .keepAlive(timeBuilder -> selection.keepAlive() == null ? timeBuilder : timeBuilder.time(selection.keepAlive() + "m")))
                        .searchAfter(searchAfterBuilder -> selection.tieBreaker() == null ? searchAfterBuilder : searchAfterBuilder.stringValue(selection.tieBreaker()))
                        .size(selection.size())
                        .sort(sortBuilder -> sortBuilder.field(fieldBuilder -> fieldBuilder.field(selection.sortField())))
                        .query(selection.query())
                , clazz);
    }
    public <T> SearchResponse<T> executeRequest2(final Selection selection, final Class<T> clazz) throws IOException {
        final var searchRequestBuilder= new SearchRequest.Builder()
                .pit(pitBuilder -> pitBuilder.id(selection.pitId())
                        .keepAlive(timeBuilder -> selection.keepAlive() == null ? timeBuilder : timeBuilder.time(selection.keepAlive() + "m")))
                .searchAfter(searchAfterBuilder -> selection.tieBreaker() == null ? searchAfterBuilder : searchAfterBuilder.stringValue(selection.tieBreaker()))
                .size(selection.size())
                .sort(sortBuilder -> sortBuilder.field(fieldBuilder -> fieldBuilder.field(selection.sortField())))
                .query(selection.query());
                
        return client.search(searchRequestBuilder.build(), clazz);
    }

The Selection record we provide to the method:

@Builder(toBuilder = true)
@JsonInclude(NON_NULL)
public record Selection(
        Query query,
        Integer size,
        String pitId,
        String tieBreaker,
        String sortField,
        Integer keepAlive,
        String[] sourceIncludes,
        String[] sourceExcludes
) {
    public Selection {
        if (null == sourceIncludes) {
            sourceIncludes = new String[0];
        }
        if ( null == sourceExcludes) {
            sourceExcludes = new String[0];
        }
    }
}

Hello!
No need to use builder explicitly, you can just use lambdas, here is an example from the documentation converted into java dsl:

esClient.search(s -> s
        .size(100)
        .query(q -> q
            .match(m -> m
                .field("title")
                .query("elasticsearch")
            )
        )
        .pit(p -> p
            .id("46ToAwMDaWR5BXV1a...")
            .keepAlive(k -> k
                .time("1m")
            )
        )
    , YourClass.class);
1 Like

@dadoonet A good example for your project.

It seems IntelliJ now does compile my first example without the type in the lambda reference. Basically that code is similar is the same as your example but more flexible. I guess it was an error in IntelliJ.