Handling huge data with Biglistbox and Hibernate"

From Documentation
m (correct highlight (via JWB))
 
(23 intermediate revisions by 3 users not shown)
Line 1: Line 1:
{{Template:UnderConstruction}}
+
 
 
{{Template:Smalltalk_Author|
 
{{Template:Smalltalk_Author|
 
|author=Vincent Jian, Engineer, Potix Corporation
 
|author=Vincent Jian, Engineer, Potix Corporation
|date=May ?, 2012
+
|date=May 04, 2012
 
|version=ZK 6.0.1, Hibernate 3.6.8
 
|version=ZK 6.0.1, Hibernate 3.6.8
 
}}
 
}}
  
 
=Introduction=
 
=Introduction=
In this [[Small Talks/2012/March/Handling a Trillion Data Using ZK|article]], Jumper Chen introduced a new component '''''Biglistbox''''' that can handle huge data and the performance has great improvement. In this article, I will demonstrate how to present huge data from database with Hibernate.
+
In the [[Small Talks/2012/March/Handling a Trillion Data Using ZK| previous article]], Jumper Chen introduced a new component in ZK 6.0.1 called '''''Biglistbox''''' that can handle huge data with great performance. In this article, using the same Biglistbox component I will demonstrate how to present huge data from database with Hibernate.
  
 
=Huge data in Biglistbox=
 
=Huge data in Biglistbox=
In Jumper's [[Small Talks/2012/March/Handling a Trillion Data Using ZK|article]], the demo is using static data which size is one trillion. In most case, the data size is quite large beyond database server can handle. Therefore, I will use a BigTable in MySQL database with 100 columns and 22,000 data rows to create a sample project as following steps:
+
In Jumper's [[Small Talks/2012/March/Handling a Trillion Data Using ZK|article]], the demo uses static data which has a data size of one trillion. However in most of the real cases, the data size is much larger than what a database server can handle. Therefore, in this article I will create a sample, saving data into a database and retrieving such data via Hibernate instead of using the static data. The database used here is MySQL and the BigTable here used contains 100 columns and 22,000 data rows.
 
<div style="padding-left: 10px">
 
<div style="padding-left: 10px">
 
==Create a ZK project and integrate with Hibernate==
 
==Create a ZK project and integrate with Hibernate==
Please refer to the following documents to create a new project:
+
There are two ways to do so. You can either refer to the following documents to create a new project:
 
*[[ZK_Installation_Guide/Quick_Start/Create_and_Run_Your_First_ZK_Application_with_Eclipse_and_ZK_Studio|Create and Run Your First ZK Application with Eclipse and ZK_Studio]]
 
*[[ZK_Installation_Guide/Quick_Start/Create_and_Run_Your_First_ZK_Application_with_Eclipse_and_ZK_Studio|Create and Run Your First ZK Application with Eclipse and ZK_Studio]]
 
*[[ZK_Developer%27s_Reference/Integration/Hibernate|Integration with Hibernate]]
 
*[[ZK_Developer%27s_Reference/Integration/Hibernate|Integration with Hibernate]]
Or you can download demo project in Jumper's article and do some modification.
+
Or you can download the demo project in Jumper's article and modify based on that project.
 
*[[Small_Talks/2012/March/Handling_a_Trillion_Data_Using_ZK#Download|Jumper's demo project]]
 
*[[Small_Talks/2012/March/Handling_a_Trillion_Data_Using_ZK#Download|Jumper's demo project]]
  
Here I will modify the code from Jumper's demo project.
+
Here I will go with the 2nd approach - modifying Jumper's demo project.
  
 
==Prepare bean object and data access object==
 
==Prepare bean object and data access object==
In Jumper's article, the demo is using static data, therefore we need to create two class to handle data loaded from database.
+
In Jumper's article, the demo uses static data. To change it to Hibernate + DB we need to create two classes to handle data loading:
 +
 
 
The BigTable bean:
 
The BigTable bean:
 
<source lang="java">
 
<source lang="java">
Line 57: Line 58:
 
}
 
}
 
</source>
 
</source>
 +
 
==Implement ''MatrixModel'' interface==
 
==Implement ''MatrixModel'' interface==
To render the view port data dynamically, we have to load a fix data size and cache them in memory. Here is fragment code of MyMatrixModel:
+
To render the view port data dynamically, we have to load a fixed data size and cache them in the memory. Here is the code snippet of <b>MyMatrixModel</b>:
<source lang="java" high="6,7,12,19">
+
<source lang="java" highlight="6,7,12,19">
 
public class MyMatrixModel<Row extends List, Head extends List, Cell, Header>
 
public class MyMatrixModel<Row extends List, Head extends List, Cell, Header>
 
extends AbstractListModel<Row> implements MatrixModel<Row, Head, Cell, Header>, Sortable<Cell> {
 
extends AbstractListModel<Row> implements MatrixModel<Row, Head, Cell, Header>, Sortable<Cell> {
Line 72: Line 74:
 
final String key = String.valueOf(index);
 
final String key = String.valueOf(index);
 
if(_rowCache == null || index < _beginOffset || index >= _beginOffset + _cacheSize) {
 
if(_rowCache == null || index < _beginOffset || index >= _beginOffset + _cacheSize) {
_beginOffset = index;
+
_beginOffset = index - _cacheSize/2 < 0 ? 0 : index - _cacheSize/2;
setRowCache(index, index + _cacheSize);
+
setRowCache(_beginOffset, _beginOffset + _cacheSize);
 
}
 
}
 
return (Row) _rowCache.get(key);
 
return (Row) _rowCache.get(key);
Line 89: Line 91:
 
for (Iterator<BigTable> iterator = list.iterator(); iterator.hasNext();) {
 
for (Iterator<BigTable> iterator = list.iterator(); iterator.hasNext();) {
 
final BigTable bigTable = iterator.next();
 
final BigTable bigTable = iterator.next();
MyKeyList<String> cells = new MyKeyList<String>(_colSize, start, new Fun() {
+
MyKeyList<String> cells = new MyKeyList<String>(_colSize, startId, new Fun() {
 
public Object apply(int index) throws Exception {
 
public Object apply(int index) throws Exception {
 
Field field = bigTable.getClass().getDeclaredField(fieldNames.get(index));
 
Field field = bigTable.getClass().getDeclaredField(fieldNames.get(index));
Line 96: Line 98:
 
}
 
}
 
});
 
});
_rowCache.put(String.valueOf(start), cells);
+
_rowCache.put(String.valueOf(startId), cells);
start++;
+
startId++;
 
}
 
}
 
}
 
}
Line 104: Line 106:
 
}
 
}
 
</source>
 
</source>
In line 6 and 7, we define two variables, first one is <tt>_beginOffset</tt> to represent the first row index of current cached data and second one is <tt>_cacheSize</tt> to represent data size load from database where you can modify the number to reduce loading of database server. And in line 12 we can see if cache is empty or the first row index of view port is outside the cache data, we need to load data from database again by <tt>setRowCache</tt> method defined in line 19.
+
 
 +
In line 6 and 7, we define two variables, the first one is <code>_beginOffset</code> which represents the first row index of current cached data. The second one is <code>_cacheSize</code> representing the data size that is to be loaded from the database. You can modify the cache size to reduce the load of the database server. Also one thing to note is that in line 12 we can see that if the cache is empty or the first row index of view port is out of the cached data, we need to load data from database again by <code>setRowCache</code> method defined in line 19.
  
 
==Other modifications==
 
==Other modifications==
Since we do not need icons here, the implementation of MatrixRenderer is simplified as follows:
+
In Jumper's demo page, each cell contains an icon image that is rendered within <code>MatrixRenderer</code>. Since we do not need icons here, the implementation of <code>MatrixRenderer</code> is simplified as follows:
 
<source lang="java">
 
<source lang="java">
 
public class MyMatrixRenderer implements MatrixRenderer<List<String>> {
 
public class MyMatrixRenderer implements MatrixRenderer<List<String>> {
Line 125: Line 128:
  
 
=Conclusion=
 
=Conclusion=
Before Biglistbox component, we can only show huge data in browser with listbox which has poor performance if the data size is large. Now, with the help of Biglistbox, we can easily present huge data to end-users with great improvement of performance.
+
With this new Biglistbox, we can easily present huge data to end-users with great performance, either using the static data or by loading data from the database.
  
 
=Download=
 
=Download=
Download Sample project [https://github.com/VincentJian/biglistbox here].
+
Download the complete sample project [https://github.com/VincentJian/biglistbox here].
  
 
{{Template:CommentedSmalltalk_Footer_new|
 
{{Template:CommentedSmalltalk_Footer_new|
 
|name=Potix Corporation
 
|name=Potix Corporation
 
}}
 
}}

Latest revision as of 04:20, 20 January 2022


DocumentationSmall Talks2012MayHandling huge data with Biglistbox and Hibernate
Handling huge data with Biglistbox and Hibernate

Author
Vincent Jian, Engineer, Potix Corporation
Date
May 04, 2012
Version
ZK 6.0.1, Hibernate 3.6.8

Introduction

In the previous article, Jumper Chen introduced a new component in ZK 6.0.1 called Biglistbox that can handle huge data with great performance. In this article, using the same Biglistbox component I will demonstrate how to present huge data from database with Hibernate.

Huge data in Biglistbox

In Jumper's article, the demo uses static data which has a data size of one trillion. However in most of the real cases, the data size is much larger than what a database server can handle. Therefore, in this article I will create a sample, saving data into a database and retrieving such data via Hibernate instead of using the static data. The database used here is MySQL and the BigTable here used contains 100 columns and 22,000 data rows.

Create a ZK project and integrate with Hibernate

There are two ways to do so. You can either refer to the following documents to create a new project:

Or you can download the demo project in Jumper's article and modify based on that project.

Here I will go with the 2nd approach - modifying Jumper's demo project.

Prepare bean object and data access object

In Jumper's article, the demo uses static data. To change it to Hibernate + DB we need to create two classes to handle data loading:

The BigTable bean:

public class BigTable implements Serializable {
    private int _id;
    private String _column1, _column2, _column3, _column4, _column5, _column6, _column7, _column8, _column9, _column10;
    // omitted other members...

    // getters and setters
}

The BigTable Data Access Object:

public class BigTableDAO {
    private static final Log log = Log.lookup(BigTableDAO.class);
    
    public List<BigTable> findBetweenIds(int startId, int endId, boolean sortDir) {
		Session session = HibernateUtil.currentSession();
		List<BigTable> list = null;
		try {
			session.beginTransaction();
			String query = "SELECT b FROM BigTable b WHERE b.id BETWEEN :start AND :end ORDER BY b.id "
					+ (sortDir ? "asc" : "desc");
			Query q = session.createQuery(query);
			q.setInteger("start", startId);
			q.setInteger("end", endId);
			list = q.list();
			session.getTransaction().commit();
		} catch (HibernateException he) {
			log.error("get failed", he);
		}
		return list;
	}
}

Implement MatrixModel interface

To render the view port data dynamically, we have to load a fixed data size and cache them in the memory. Here is the code snippet of MyMatrixModel:

public class MyMatrixModel<Row extends List, Head extends List, Cell, Header>
		extends AbstractListModel<Row> implements MatrixModel<Row, Head, Cell, Header>, Sortable<Cell> {
	
	// omitted...
	
	private int _beginOffset; //first row number in _rowCache
	private int _cacheSize = 1000; // cache data size load from database
	private Map<String, MyKeyList<String>> _rowCache; // cache data
	
	public Row getElementAt(int index) {
		final String key = String.valueOf(index);
		if(_rowCache == null || index < _beginOffset || index >= _beginOffset + _cacheSize) {
			_beginOffset = index - _cacheSize/2 < 0 ? 0 : index - _cacheSize/2;
			setRowCache(_beginOffset, _beginOffset + _cacheSize);
		}
		return (Row) _rowCache.get(key);
	}
	
	private void setRowCache(int start, int end) {
		BigTableDAO dao = new BigTableDAO();
		int startId = _sortDir ? start : (_rowSize - start),
			endId   = _sortDir ? end   : (_rowSize - end);
		
		List<BigTable> list = _sortDir ? dao.findBetweenIds(startId, endId, _sortDir) : dao.findBetweenIds(endId, startId, _sortDir);
		final List<String> fieldNames = new BigTable().getFieldsName();
		
		_rowCache = new HashMap<String, MyKeyList<String>>();
		for (Iterator<BigTable> iterator = list.iterator(); iterator.hasNext();) {
			final BigTable bigTable = iterator.next();
			MyKeyList<String> cells = new MyKeyList<String>(_colSize, startId, new Fun() {
				public Object apply(int index) throws Exception {
					Field field = bigTable.getClass().getDeclaredField(fieldNames.get(index));
					field.setAccessible(true);
					return (String) field.get(bigTable);
				}
			});
			_rowCache.put(String.valueOf(startId), cells);
			startId++;
		}
	}
	
	// omitted...
}

In line 6 and 7, we define two variables, the first one is _beginOffset which represents the first row index of current cached data. The second one is _cacheSize representing the data size that is to be loaded from the database. You can modify the cache size to reduce the load of the database server. Also one thing to note is that in line 12 we can see that if the cache is empty or the first row index of view port is out of the cached data, we need to load data from database again by setRowCache method defined in line 19.

Other modifications

In Jumper's demo page, each cell contains an icon image that is rendered within MatrixRenderer. Since we do not need icons here, the implementation of MatrixRenderer is simplified as follows:

public class MyMatrixRenderer implements MatrixRenderer<List<String>> {

	public String renderCell(Component owner, List<String> data, int rowIndex, int colIndex) throws Exception {
		return data.get(colIndex);
	}

	public String renderHeader(Component owner, List<String> data, int rowIndex, int colIndex) throws Exception {
		return data.get(colIndex);
	}
}

Now, you should be able to run the project to see the result.

Conclusion

With this new Biglistbox, we can easily present huge data to end-users with great performance, either using the static data or by loading data from the database.

Download

Download the complete sample project here.


Comments



Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.