Как реализовать разбиение на страницы с помощью nextPageToken? - PullRequest
0 голосов
/ 07 марта 2020

Я пытаюсь реализовать разбиение на страницы, используя nextPageToken.

У меня есть таблица:

CREATE TABLE IF NOT EXISTS categories
(
    id        BIGINT PRIMARY KEY,
    name      VARCHAR(30) NOT NULL,
    parent_id BIGINT REFERENCES categories (id)
);

, поэтому у меня есть категория объекта:

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;
    @Column(name = "name")
    private String name;
    @OneToOne
    @JoinColumn(name = "parent_id", referencedColumnName = "id")
    private Category category;

I не понимаю, что мне делать дальше. клиент запрашивает токен (который хранит что?)

Предположим, у меня есть контроллер:

@GetMapping
    public ResponseEntity<CategoriesTokenResponse> getCategories(
            @RequestParam String nextPageToken
    ) {
        return ResponseEntity.ok(categoryService.getCategories(nextPageToken));
    }

Служба:

public CategoriesTokenResponse getCategories(String nextPageToken) {
        return new CategoriesTokenResponse(categoryDtoList, "myToken");
    }
@Data
@AllArgsConstructor
public class CategoriesTokenResponse {
    private final List<CategoryDto> categories;
    private final String token;
}

Как я должен реализовать sql запрос для этого? И как мне генерировать nextPagetoken для каждого идентификатора?

SELECT * FROM categories WHERE parent_id = what?
AND max(category id from previous page = token?)
ORDER BY id LIMIT 20;

1 Ответ

1 голос
/ 23 марта 2020

Во-первых, вам нужно понять, с чем вы здесь работаете. Каждая реализация имеет своего рода ограничение или неэффективность. Например, использование таких токенов страниц полезно только для страниц с бесконечной прокруткой. Вы не можете перейти на любую конкретную c страницу. Так что, если мой браузер зависает, и я нахожусь на странице 100, я должен снова пролистать 100 страниц. Это точно для больших массивов данных, но имеет ли это значение, если вам нужен доступ ко всем страницам? Или если вы ограничите возврат для начала? Например, получить только первые 30 страниц?

В основном решите это: Вам нужны только первые несколько страниц, потому что поиск / сортировка всегда используются? (как пользователь, никогда не использующий больше, чем первые 1-5 страниц Google) и большой ли этот набор данных? Тогда отличный вариант использования. Выберет ли пользователь «все элементы за последние 6 месяцев» и действительно ли они понадобятся, или сортировка / поиск будут слабыми? Или вы вернете все страницы и не ограничите максимальный возврат 30 страниц? Или скорость разработки важнее, чем увеличение скорости на 0,1-3 секунды (зависит от размера данных)? Затем go со встроенными объектами JPA Page.

Я использовал объекты Page в записях 700k с изменением скорости менее чем за секунду по сравнению с записями 70k. Исходя из этого, я не вижу удаления смещения, добавляющего тонну значения, если вы не планируете огромный набор данных. Я только что протестировал новую систему, которую я создаю, с pageable, она возвратила 10 элементов на странице 1 за 84 миллисекунды без ограничения страницы для 27k записей по vpn в мою рабочую сеть из моего дома. Таблица с более чем 500 тысячами записей заняла 131 миллисекунду. Это довольно быстро. Хотите сделать это быстрее? Принудительная максимальная отдача 30 страниц и максимум 100 результатов на страницу, потому что обычно им не нужны все данные в этой таблице. Они хотят что-то еще? Уточни поиск. Разница в скорости между этой страницей и поиском по типу поиска / ключа меньше секунды. Это предполагает нормальную базу данных SQL тоже. Нет SQL здесь немного по-другому. Baeldung имеет массу статей о jpa-пейджинге, таких как: https://www.baeldung.com/rest-api-pagination-in-spring

JPA-пейджинг должен занять не более 30 минут для изучения и реализации, он очень прост и поставляется на JPA хранилища. Я настоятельно рекомендую использовать это вместо подкачки в стиле поиска / ключа, так как вы, вероятно, не создаете систему, подобную Google или Facebook.

Если вы абсолютно хотите go с подкачкой в ​​стиле поиска / ключа, здесь есть хорошая информационная страница: https://blog.jooq.org/2013/10/26/faster-sql-paging-with-jooq-using-the-seek-method/

В общем, что вы ищете использует JOOQ с пружиной. Пример реализации здесь: https://docs.spring.io/spring-boot/docs/1.3.5.RELEASE/reference/html/boot-features-jooq.html

По сути, создайте контекст DSL:

private final DSLContext DSL;

@Autowired
public JooqExample(DSLContext dslContext) {
    this.DSL= dslContext;
}

Затем используйте его так:

DSL.using(configuration)
   .select(PLAYERS.PLAYER_ID,
           PLAYERS.FIRST_NAME,
           PLAYERS.LAST_NAME,
           PLAYERS.SCORE)
   .from(PLAYERS)
   .where(PLAYERS.GAME_ID.eq(42))
   .orderBy(PLAYERS.SCORE.desc(),
            PLAYERS.PLAYER_ID.asc())
   .seek(949, 15) // (!)
   .limit(10)
   .fetch();

Вместо того, чтобы явно формулировать предикат поиска, просто передайте последнюю запись из предыдущего запроса, и jOOQ увидит, что все записи до и включая эту запись пропущены, учитывая предложение ORDER BY.

...