Wednesday, March 19, 2014

Saving an image in Cassandra BLOB field

We had an occasion today to be able to store images in a blob field of a Cassandra tables.  More to the point I needed to extract it and send it from a java servlet to a web browser as an image.   The code for storing the image is quit easy but there is a small gotcha when retrieving it.   So, suppose we have a table that looks something like:

String CreateTweetTable = "CREATE TABLE if not exists Messages ("+
                "user varchar,"+
                " interaction_time timeuuid,"+
                " tweet varchar,"+
                " image blob," +
                " imagelength int,"+
                " PRIMARY KEY (user,interaction_time)"+
                ") WITH CLUSTERING ORDER BY (interaction_time DESC);";

Our image will be in the blob field and we also store the size of the image for reference. We can load a picture from a file on the local machines hard disk like this:

FileInputStream fis=new FileInputStream("/Users/Administrator/Desktop/mystery.png");
byte[] b= new byte[fis.available()+1];
int length=b.length;;

We now need to convert the byte array into a bytebuffer:

ByteBuffer buffer =ByteBuffer.wrap(b);

Writing the record becomes simply:

 PreparedStatement ps = session.prepare("insert into Messages ( image, user, interaction_time,imagelength) values(?,?,?,?)");
BoundStatement boundStatement = new BoundStatement(ps);
session.execute(  boundStatement.bind( buffer, "Andy",  convertor.getTimeUUID(),length));

Getting the image back is simple.  Use a Select to get the result set:

PreparedStatement ps = session.prepare("select user,image,imagelength from Messages where user =?");
BoundStatement boundStatement = new BoundStatement(ps);
ResultSet rs =session.execute ( boundStatement.bind("Andy"));

We can now loop through the result set (here we are assuming only one image comes back)

ByteBuffer bImage=null;
for (Row row : rs) {
 bImage = row.getBytes("image") ;

However to display the image we will need it as a byte array.  We can’t use bImage.get() as this reaches down in to the raw buffer (see:!searchin/java-driver-user/blob$20ByteBuffer/java-driver-user/4_KegVX0teo/2OOZ8YOwtBcJ for details )  Instead we can use :

byte image[]= new byte[length];

In the servlet we can return this image in one of 2 ways:

OutputStream out = response.getOutputStream();

Writes the image as a single lump which may use too much memory.  You might be better using a bufferedinput stream (

InputStream is = new ByteArrayInputStream(Image);
BufferedInputStream input = new BufferedInputStream(is);
byte[] buffer = new byte[8192];
for (int length = 0; (length = > 0;) {
    out.write(buffer, 0, length);