4

How spring data elastisearch use offset and limit to query. I want to use offset and limit param to query page.But I can not find methods support. For Example:

    queryBuild.withPageable(PageRequest.of(pageIndex, pageSize));
    Page<Content> content = elasticsearchOperations.queryForPage(queryBuild.build(),Content.class);

it could be ok

But I can not found method with offset and limit

    queryBuild.withPageable(PageRequest.of(offset, limit));
Michael
  • 41
  • 1
  • 3

2 Answers2

2

I have the same problem, so I implemented the following class

import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;

public class OffsetLimitPageable implements Pageable {

    private int offset;
    private int page;
    private int size;
    private Sort sort = Sort.unsorted();

    protected OffsetLimitPageable(int offset, int page, int size) {
        if (offset < 0) {
            throw new IllegalArgumentException("Offset must not be less than zero!");
        }

        if (page < 0) {
            throw new IllegalArgumentException("Page index must not be less than zero!");
        }

        if (size < 1) {
            throw new IllegalArgumentException("Page size must not be less than one!");
        }

        this.offset = offset;
        this.page = page;
        this.size = size;
    }

    public static OffsetLimitPageable of(int offset, int page, int size) {
        return new OffsetLimitPageable(offset, page, size);
    }

    /*
     * (non-Javadoc)
     * @see org.springframework.data.domain.Pageable#getPageNumber()
     */
    @Override
    public int getPageNumber() {
        return page;
    }

    /*
     * (non-Javadoc)
     * @see org.springframework.data.domain.Pageable#getPageSize()
     */
    @Override
    public int getPageSize() {
        return size;
    }

    /*
     * (non-Javadoc)
     * @see org.springframework.data.domain.Pageable#getOffset()
     */
    @Override
    public long getOffset() {
        return offset + page * size;
    }

    /*
     * (non-Javadoc)
     * @see org.springframework.data.domain.Pageable#getSort()
     */
    @Override
    public Sort getSort() {
        return sort;
    }

    /*
     * (non-Javadoc)
     * @see org.springframework.data.domain.Pageable#next()
     */
    public Pageable next() {
        return of(offset, page + 1, size);
    }

    /*
     * (non-Javadoc)
     * @see org.springframework.data.domain.Pageable#previousOrFirst()
     */
    public Pageable previousOrFirst() {
        return hasPrevious() ? of(offset, page - 1, size) : first();
    }

    /*
     * (non-Javadoc)
     * @see org.springframework.data.domain.Pageable#first()
     */
    public Pageable first() {
        return of(offset, 0, size);
    }

    /*
     * (non-Javadoc)
     * @see org.springframework.data.domain.Pageable#hasPrevious()
     */
    public boolean hasPrevious() {
        return page > 0;
    }
}

And, use like this

queryBuild.withPageable(OffsetLimitPageable.of(offset, page, limit));
Rüdiger Schulz
  • 2,588
  • 3
  • 27
  • 43
LuisComS
  • 452
  • 4
  • 20
  • What is `getPageNumber()` used for anyway? Do you not also technically have a previous page when `offset` is greater 0 (even if `page` is 0)? – Zyl Nov 26 '21 at 16:36
  • This method is required by `Pageable` interface – LuisComS Dec 02 '21 at 13:22
  • I learned `Pageable` can also be involved in returning information about the URL to the next page in the HTTP response, so it might be related to that. Either way, your implementation can't be used to seek entries before `offset` in page 0. For an implementation like this, when `offset` is > 0, for page 0 it should return `offset` in `getPageSize()` and 0 in `getOffset()`. Page number might not even need to be zero-based, but it's what `PageRequest` does. We just don't know. – Zyl Dec 02 '21 at 15:02
1

This is not supported in spring-data-es (or in ANY spring-data project), so you'll have to provide your own custom implementation for the Pageable interface

Take a look here or here and here if you attempt to use the repository variant (extending ElasticsearchRepository<...,...>) and implement your own.

Then perform the query just as you noted, with

PageRequest p = new MyOwnPageRequest(offset, limit);
SearchQuery sq = new NativeSearchQueryBuilder()
            .withQuery(matchAllQuery())
            .withPageable(p)
            .build();

Page<SampleEntity> result = elasticsearchTemplate.queryForPage(sq, SampleEntity.class);
a.k
  • 1,035
  • 10
  • 27
  • 1
    Thanks for your answer. I have a question. Ther source code of Spring-data-elasticsearch uses pageNumber and pageSize to query. Such as: ```Java if (query.getPageable().isPaged()) { startRecord = query.getPageable().getPageNumber() * query.getPageable().getPageSize(); searchRequestBuilder.setSize(query.getPageable().getPageSize()); } ``` So when offset=9, limit=10, pageNumber and pageSize will not have corresponding value.(Whether pageSize=10 and pageNumber=1 or 0, the startRecord would be wrong) – Michael Sep 25 '19 at 02:24
  • @Michael The source code seems to have changed now. Look at [the latest code](https://github.com/spring-projects/spring-data-elasticsearch/blob/master/src/main/java/org/springframework/data/elasticsearch/core/RequestFactory.java#L874), and you will see it uses offset :) – ch271828n Jul 07 '20 at 00:13
  • @ch271828n I see it. Thank you. – Michael Jul 22 '20 at 09:03