Cassandra Paging Java Example

In this Article, I will show How to implement paging in Cassandra.
This is common requirement in many of projects.

Tools Uses :

1) Apache-cassandra-2.1.6
2) eclipse version Luna 4.4.1.
3) Maven 4.0.0
4) JDK 1.7

If you are completely new to Cassandra, Pl. refer Cassandra Quick Start.

Once your Cassandra Database server is up and CQL window is open.
Follow given simple steps to setup test data,

1) Create a KEYSPACE (Similar to NAMESPACE in relational database), If not exist.

cqlsh> CREATE KEYSPACE devJavaSource
WITH REPLICATION = { ‘class’ : ‘SimpleStrategy’, ‘replication_factor’ : 1 };

2) Use created key space(devJavaSource).

cqlsh> USE devJavaSource;

3) Create table name (USERS) in key space devJavaSource, with columns ID, NAME, ADDRESS.

cqlsh> CREATE TABLE USERS ( ID int PRIMARY KEY, NAME text, ADDRESS text );

4) Create data into USER table.


INSERT INTO USERS (ID, NAME, ADDRESS) VALUES (11101, ‘john’, ‘Oakland’);
INSERT INTO USERS (ID, NAME, ADDRESS) VALUES (11102, ‘smith’, ‘California’);
INSERT INTO USERS (ID, NAME, ADDRESS) VALUES (11103, ‘Joe’, ‘Nederland’);
INSERT INTO USERS (ID, NAME, ADDRESS) VALUES (11104, ‘Benny David’, ‘UK’);
INSERT INTO USERS (ID, NAME, ADDRESS) VALUES (11105, ‘Scattergood John’, ‘USA’);
INSERT INTO USERS (ID, NAME, ADDRESS) VALUES (11106, ‘Bob Ronstan’, ‘Canada’);
INSERT INTO USERS (ID, NAME, ADDRESS) VALUES (11107, ‘Stuart’, ‘UK’);
INSERT INTO USERS (ID, NAME, ADDRESS) VALUES (11108, ‘Adamson’, ‘USA’);
INSERT INTO USERS (ID, NAME, ADDRESS) VALUES (11109, ‘Mike’, ‘Canada’);
INSERT INTO USERS (ID, NAME, ADDRESS) VALUES (11110, ‘Lussi’, ‘UK’);
INSERT INTO USERS (ID, NAME, ADDRESS) VALUES (11111, ‘Meena’, ‘USA’);
INSERT INTO USERS (ID, NAME, ADDRESS) VALUES (11112, ‘Sam’, ‘Canada’);

5) Retrieve the data from USERS table.

cqlsh> SELECT * FROM USERS;

 
 id    | address    | name
-------+------------+------------------
 11106 |     Canada |      Bob Ronstan
 11107 |         UK |           Stuart
 11103 |  Nederland |              Joe
 11105 |        USA | Scattergood John
 11102 | California |            smith
 11112 |     Canada |              Sam
 11101 |    Oakland |             john
 11110 |         UK |            Lussi
 11108 |        USA |          Adamson
 11109 |     Canada |             Mike
 11104 |         UK |      Benny David
 11111 |        USA |            Meena

(12 rows)

Write a simple program to implement paging :

1) Create a maven project.

2) Add required dependencies.

3) Create a simple java program to retrieve data.

4) Start cassandra server.

5) Run and verify the out put.

Add required dependencies :

Open pom.xml file and add given dependency.

<dependency>
  <groupId>com.datastax.cassandra</groupId>
  <artifactId>cassandra-driver-core</artifactId>
  <version>2.1.6</version>
</dependency>

Create a simple java program to implement paging :

PagingState is a cassandra class that holds paging state.
We can get PagingState from ResultSet object.

ResultSet result = null;
String savingPageState = null;
savingPageState = result.getExecutionInfo()
                  .getPagingState().toString();

We can set fetch size to statement object,

Statement statement = null;
statement.setFetchSize(size);

Complete CassandraPaging class source code is Here,
CassandraPaging.java

package com.devjavasource.cassandra.PagingExample;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.datastax.driver.core.PagingState;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Row;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.Statement;

/**
 * 
 * The solution of skipping rows is that use page state rather than iterator
 * rows one by one.
 *
 */
public class CassandraPaging {

	private Session session;

	public CassandraPaging(Session session) {
		this.session = session;
	}

	/**
	 * Retrieve rows for the specified page offset.
	 * 
	 * @param statement
	 * @param start
	 *            starting row (>1), inclusive
	 * @param size
	 *            the maximum rows need to retrieve.
	 * @return List<Row>
	 */
	public List<Row> fetchRowsWithPage(Statement statement, int start, int size) {
		ResultSet result = skipRows(statement, start, size);
		return getRows(result, start, size);
	}

	private ResultSet skipRows(Statement statement, int start, int size) {
		ResultSet result = null;
		int skippingPages = getPageNumber(start, size);
		String savingPageState = null;
		statement.setFetchSize(size);
		boolean isEnd = false;
		for (int i = 0; i < skippingPages; i++) {
			if (null != savingPageState) {
				statement = statement.setPagingState(PagingState
						.fromString(savingPageState));
			}
			result = session.execute(statement);
			PagingState pagingState = result.getExecutionInfo()
					.getPagingState();
			if (null != pagingState) {
				savingPageState = result.getExecutionInfo().getPagingState()
						.toString();
			}

			if (result.isFullyFetched() && null == pagingState) {
				// if hit the end more than once, then nothing to return,
				// otherwise, mark the isEnd to 'true'
				if (true == isEnd) {
					return null;
				} else {
					isEnd = true;
				}
			}
		}
		return result;
	}

	private int getPageNumber(int start, int size) {
		if (start < 1) {
			throw new IllegalArgumentException(
					"Starting row need to be larger than 1");
		}
		int page = 1;
		if (start > size) {
			page = (start - 1) / size + 1;
		}
		return page;
	}

	private List<Row> getRows(ResultSet result, int start, int size) {
		List<Row> rows = new ArrayList<>(size);
		if (null == result) {
			return rows;
		}
		int skippingRows = (start - 1) % size;
		int index = 0;
		for (Iterator<Row> iter = result.iterator(); iter.hasNext()
				&& rows.size() < size;) {
			Row row = iter.next();
			if (index >= skippingRows) {
				rows.add(row);
			}
			index++;
		}
		return rows;
	}
}

Create a Simple class App.java to test paging,

Create a Cluster object and session objects,

Cluster cluster = null;
Session session = null;
final Cluster.Builder clusterBuilder = 
                         Cluster.builder().addContactPoint("127.0.0.1").withPort(9042)
			 .withCredentials("devjavasource", "devjavasource");
cluster = clusterBuilder.build();
session = cluster.connect("devjavasource");

Create a Statement with help of QueryBuilder class,

Statement select = QueryBuilder.select().all().from("devjavasource", "users");

Complete source code is Here,
App.java

package com.devjavasource.cassandra.PagingExample;

import java.util.List;

import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Row;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.Statement;
import com.datastax.driver.core.querybuilder.QueryBuilder;

/**
 * Hello world!
 *
 */
public class App {
	public static void main(String[] args) {		
		Cluster cluster = null;
		Session session = null;
		
		try{
			// Connect to the cluster and keyspace "devjavasource"
			final Cluster.Builder clusterBuilder = Cluster.builder()
					.addContactPoint("127.0.0.1").withPort(9042)
					.withCredentials("devjavasource", "devjavasource");
			cluster = clusterBuilder.build();
			session = cluster.connect("devjavasource");
			
			Statement select = QueryBuilder.select().all().from("devjavasource", "users");
			
			CassandraPaging cassandraPaging = new CassandraPaging(session);
			System.out.println("*************First Page1 **************");
			List<Row> firstPageRows = cassandraPaging.fetchRowsWithPage(select, 1, 3);
			printUser(firstPageRows);
			
			System.out.println("*************Second Page2 **************");
			List<Row> secondPageRows = cassandraPaging.fetchRowsWithPage(select, 4, 3);
			printUser(secondPageRows);
			
			System.out.println("*************Third Page3 **************");
			List<Row> thirdPageRows = cassandraPaging.fetchRowsWithPage(select, 4, 3);
			printUser(thirdPageRows);
			
			System.out.println("*************Fourth Page4 **************");
			List<Row> fourthPageRows = cassandraPaging.fetchRowsWithPage(select, 4, 3);
			printUser(fourthPageRows);
			
			cluster.close();
			session.close();
			
		}catch(Exception exp){
			exp.printStackTrace();
		}finally{
			cluster.close();
			session.close();
		}
	}
	
	private static void printUser(final List<Row> inRows){		
		for (Row row : inRows) {
			System.out.println("Id is:" + row.getInt("id"));
			System.out.println("Name is:" + row.getString("name"));
			System.out.println("Address is:" + row.getString("address"));
		}
	}
}

4) Start the Cassandra server :

Cassandra server should be up and running.
If the server is not running, run the server using following command.

Command to start Casandra server is,
C:\apache-cassandra-2.1.6\bin>cassandra.bat -f

5) Run Maven project :

Select and Run As -> Java Application.

Out Put :

*************First Page1 **************
Id is:11106
Name is:Bob Ronstan
Address is:Canada
Id is:11107
Name is:Stuart
Address is:UK
Id is:11103
Name is:Joe
Address is:Nederland
*************Second Page2 **************
Id is:11105
Name is:Scattergood John
Address is:USA
Id is:11102
Name is:smith
Address is:California
Id is:11112
Name is:Sam
Address is:Canada
*************Third Page3 **************
Id is:11101
Name is:john
Address is:Oakland
Id is:11110
Name is:Lussi
Address is:UK
Id is:11108
Name is:Adamson
Address is:USA
*************Fourth Page4 **************
Id is:11109
Name is:Mike
Address is:Canada
Id is:11104
Name is:Benny David
Address is:UK
Id is:11111
Name is:Meena
Address is:USA

Select the user details from cassandra database,

1

You can download complete project, Here

PagingExample

*** Venkat – Happy leaning ****