Разбиение на Cassandra Использование драйвера Datastax 3.6: Нулевое состояние подкачки и размер выборки не учитываются - PullRequest
2 голосов
/ 13 июня 2019

Мы пытаемся создать приложение, которое возвращает постраничные результаты из cassandra db для пользовательского интерфейса.

Пользовательский интерфейс будет передавать fetchSize и pagingState нашему API, и на основании этого мы будем возвращать List<MyObject> из size=fetchSize. Если передано pagingState, мы возобновим запрос с последней страницы (как упомянуто в документах cassandra: https://docs.datastax.com/en/developer/java-driver/3.6/manual/paging/)

Обратите внимание, что я использую драйвер Cassandra версии 3.6.

Но когда мы это реализовали, Cassandra всегда возвращает все записи в базе данных, игнорируя размер выборки, что, в свою очередь, приводит к значению null для ResultSet.getExecutionInfo().getPagingState(). Как мне это решить?

Я создал 16 записей в своей базе данных для MyObject и попытался передать размер выборки как 5, чтобы получить их. Все 16 записей имеют одинаковый ключ раздела ID-1.

// Util method to invoke Statement. "session" is cassandra session 

public static ResultSet execute(int pageSize, Statement statement, String pageState) { 
    if (isVoid(pageSize)) {
        pageSize=-1;
    }
    statement.setFetchSize(pageSize);
    if (!isVoid(pageState)) {
        statement.setPagingState(PagingState.fromString(pageState));
    }
    return session.execute(statement);
}

// Accesor interface method for my query that returns a Statement 
object

@Query("SELECT * FROM " + MY_TABLE + " WHERE id=:id")
Statement getAll(@Param("id") String id);

// Main Code returning list of MyObject that has an object Mapper -> 
//mapper 
Statement statement=accessor.getAll("ID1");
ResultSet rs=execute(5,statement,null );
List<MyObject> list=mapper.map(rs).all();
String pageState=rs.getExecutionInfo().getPagingState();

В приведенном выше коде я ожидал, что Cassandra вернет список из 5 MyObject объектов и будет иметь строковое значение для моей переменной pageState. Ни один из них не работал, как ожидалось.

Список имел размер 16 (в основном он выбирал все записи) и из-за вышеизложенного, pageState было null, поскольку все записи уже были получены.

Что мне здесь не хватает?

EDIT: Из наблюдения ResultSet будет учитывать fetchSize, переданный в операторе, но когда мы сопоставим его с List<MyObject>, используя метод all(), он извлекает все результаты в базе данных (размера = широкий кластер fetchSize). Поэтому, когда я вызывал Result#one метод 5 (= pageSize) раз и помещал их в список, я получил состояние подкачки, а также результаты размера страницы размера.

Пример метода Util для выше

public static <T> List<T> getPaginatedList(ResultSet resultSet, Mapper<T> mapper,int pageSize) {
    List<T> entities=new ArrayList<>();
    Result<T> result=mapper.map(resultSet);
    IntStream.range(1,pageSize).forEach(i->{
        entities.add(result.one());
    });
    return entities;
}

Как это отразится на производительности?

1 Ответ

2 голосов
/ 13 июня 2019

Как вы могли различить, причина, по которой вы получаете все результаты обратно, несмотря на то, что вы указываете setFetchSize, заключается в том, что размер выборки просто устанавливает запрашиваемый размер каждой запрашиваемой страницы. Когда вы вызываете all(), драйвер прозрачно просматривает все результаты.

Вызов one() по отдельности не окажет влияния на производительность по сравнению с all(), однако я бы порекомендовал изменить вашу логику для использования страницы, так как я ожидаю, что IntStream.range(1, pageSize) не удастся, если вы исчерпали свой набор результатов ( т.е. вы устанавливаете размер выборки на 500, но есть только 495 строк). Вместо этого вы можете использовать IntStream.range(1, resultSet.getAvailableWithoutFetching()).

Вы также можете выбирать итерацию набора результатов до тех пор, пока ResultSet.isExhausted() не вернет true, чтобы предотвратить выбор следующей страницы.

...