NoSQL (III): Java + Cassandra DB

La segunda de las demos que vamos a realizar en esta serie de artículos es la de Cassandra DB. Podéis encontrar la página del proyecto en este enlace. Cassandra DB es una base de datos hibrida entre una de “clave-valor” y una “orientada a fila”, ya veremos que es esto más adelante. De momento, no nos preocupemos. Como dato curioso comentar simplemente que, aunque ahora es un proyecto de Apache, el inicio de este desarrollo lo realizo Facebook, si los mismos de la red social.

Instalando Cassandra DB

Lo primero que tenemos que hacer es ir a la página del proyecto y descargarnos la última versión que en el momento de escribir este artículo es la 1.1.4. El fichero comprimido que nos descargamos contiene todo lo necesario para trabajar con Cassandra, en este caso no hace falta descargarse ningún Driver aparte. De nuevo, decir que estoy haciendo esto sobre Windows 7 y no sobre Linux, aunque espero que al igual que en la demo anterior, los procesos no sean muy diferentes y no tengáis problemas para seguir la demo. He mirado el directorio de ejecutables de Cassandra y los ficheros de configuración vienen preparados para Linux también.

En este caso, como ya he comentado no hay Driver de conexión propiamente dicho en la página web para descargar, o al menos yo no lo he visto. La ventaja de estar haciendo esto en Java es que Cassandra está desarrollado sobre Java, con lo cual solo vamos a necesitar las librerías que vienen en el fichero que hemos descargado. Para el resto de lenguajes, ahora mismo no tengo ni idea, de nuevo si alguien lo esta haciendo en un lenguaje distinto a Java y se anima a mandar la contribución, esta será publicada tras una breve revisión. Como único dato importante que puedo aportar sobre esto, os dejo el enlace a una de las páginas del Wiki oficial del proyecto con ejemplo de diferentes lenguajes.

Una vez descargado el fichero con la base de datos, solo tendréis que descomprimirlo donde deseéis y ya tendréis instalada la bases de datos Cassandra. En este caso, al igual que en el anterior, el directorio que había dentro del zip, lleva todos los ejecutables necesarios para poder trabajar con Cassandra. Además, tiene un directorio con ficheros de configuración y uno con las librerías.

Así que, lo primero de todo como siempre, vamos a probar la base de datos a ver si conseguimos arrancarla y verla funcionando. Lo primero que tendremos que hacer es definir dos variables globales en nuestro sistema.

  • JAVA_HOME: Ruta donde se aloja nuestra instalación de Java.
  • CASSANDRA_HOME: Ruta donde tendremos alojada la instalación de Cassandra.

Al contrario que con MongoDB que solo era una sugerencia aquí es obligatorio definirlas ya que los scripts de arranque chequean si están definidas o no. En el caso de JAVA_HOME, si no está definida nos mostrará un error, pero en el caso de CASSANDRA_HOME, tiene una definida por defecto.

Tras esto simplemente nos dirigimos a la ruta donde hayamos puesto nuestro directorio Cassandra y entramos en el directorio bin para ejecutar la base de datos.

promt> cd %CASSANDRA_HOME%\bin

promt> cassandra.bat

Con esto obtendremos un mensaje similar a este, lo que nos confirmará que el arranque ha ido bien:

Listening for thrift clients…

Ahora vamos a tratar de conectar a la base de datos con el cliente que está en la misma ruta

promt> cassandra-cli.bat

Esto ejecutará un cliente de conexión para acceder a Cassandra, en el promt que nos aparece tenemos a nuestra disposición la instrucción help que nos mostrará diferentes opciones, en nuestro caso vamos a utilizar la de connect. Remarcar que las instrucciones se ejecutan con un punto y coma al final (ej. help;) si no el promt no reaccionará al texto que hayamos introducido. Para conectar a nuestro servidor Cassandra, vamos a ejecutar la siguiente instrucción:

promt> connect localhost/9160;

Que nos mostrará algo similar a:

Connected to: “Test Cluster” on localhost/9160

En este punto os animo a que juguéis un poco con los comandos disponibles, al menos echadle un ojo a los show y daros cuenta de los create existentes.

No he encontrado, quizás la haya pero lo desconozco, que Cassandra venga con una consola de administración web como lo hacía, por ejemplo, MongoDB. Lo que si sé que hay es un proyecto alojado en Google Code con un proyecto de interfaz web. Os dejo aquí el enlace por si queréis probarlo: CassUI.

Previamente a empezar a escribir el código Java, vamos a crear nuestro esquema (keyspace) en la base de datos y nuestra tabla (column family). Para ello en el promt escribiremos lo siguiente:

promt> create keyspace helloks;

promt> use helloks;

promt> create column family hcolumn;

Conectando desde Java

Para empezar, de nuevo, lo primero que tendremos que hacer es crear un proyecto Java básico, también podéis utilizar el mismo proyecto que creamos para la demo de MongoDB, simplemente cread una clase nueva y ya está.

Del mismo modo que lo hicimos para añadir el Driver en MondoDB, aquí tendremos que añadir las librerías de Cassandra a nuestro proyecto. Dichas librerías están en el directorio de Cassandra en lib (%CASSANDRA_HOME%\lib). Las librarías a añadir serán:

  • apache-cassandra-thrift-x.x.x.jar
  • libthrift-x.x.x.jar
  • sl4j-api-x.x.x.jar

Tras esto escribiremos el código de nuestro primer ejemplo. En este caso el código lo vamos a coger del wiki mencionado anteriormente ya que está bastante bien, y solo tendremos que hacerle unos pequeños cambios para adaptarlos a nuestra bases de datos:


public static void main(String[] args) throws TException,
InvalidRequestException, UnavailableException,
UnsupportedEncodingException, NotFoundException, TimedOutException {
TTransport tr = new TFramedTransport(new TSocket("localhost", 9160));
TProtocol proto = new TBinaryProtocol(tr);
Cassandra.Client client = new Cassandra.Client(proto);
tr.open();

String key_user_id = "1";

// insert data
long timestamp = System.currentTimeMillis();
client.set_keyspace("helloks");
ColumnParent parent = new ColumnParent("hcolumn");

Column nameColumn = new Column(toByteBuffer("name"));
nameColumn.setValue(toByteBuffer("svoboda"));
nameColumn.setTimestamp(timestamp);
client.insert(toByteBuffer(key_user_id), parent, nameColumn,
ConsistencyLevel.ONE);

Column ageColumn = new Column(toByteBuffer("age"));
ageColumn.setValue(toByteBuffer("99"));
ageColumn.setTimestamp(timestamp);
client.insert(toByteBuffer(key_user_id), parent, ageColumn,
ConsistencyLevel.ONE);

ColumnPath path = new ColumnPath("hcolumn");

// read single column
path.setColumn(toByteBuffer("name"));
System.out.println(client.get(toByteBuffer(key_user_id), path,
ConsistencyLevel.ONE));

// read entire row
SlicePredicate predicate = new SlicePredicate();
SliceRange sliceRange = new SliceRange(toByteBuffer(""),
toByteBuffer(""), false, 10);
predicate.setSlice_range(sliceRange);

List<ColumnOrSuperColumn> results = client.get_slice(
toByteBuffer(key_user_id), parent, predicate,
ConsistencyLevel.ONE);
for (ColumnOrSuperColumn result : results) {
Column column = result.column;
System.out.println(toString(column.name) + " -> "
+ toString(column.value));
}

tr.close();
}

public static ByteBuffer toByteBuffer(String value)
throws UnsupportedEncodingException {
return ByteBuffer.wrap(value.getBytes("UTF-8"));
}

public static String toString(ByteBuffer buffer)
throws UnsupportedEncodingException {
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
return new String(bytes, "UTF-8");
}

Tras ejecutar este pequeño programita, veremos el siguiente resultado:


ColumnOrSuperColumn(column:Column(name:80 01 00 02 00 00 00 03 67 65 74 00 00 00 04 0C 00 00 0C 00 01 0B 00 01 00 00 00 04 6E 61 6D 65, value:80 01 00 02 00 00 00 03 67 65 74 00 00 00 04 0C 00 00 0C 00 01 0B 00 01 00 00 00 04 6E 61 6D 65 0B 00 02 00 00 00 07 73 76 6F 62 6F 64 61, timestamp:1346925753115))
age -> 99
name -> svoboda

Como podéis ver, aunque quizás el resultado obtenido tras la ejecución al leer la columna completa y mostrarla no es muy intuitivo, el manejo de la base de datos y el acceso de almacenamiento y lectura de los datos concretos si lo es, y además, muy fácil. Espero que hayáis conseguido llegar hasta aquí con éxito y que os haya servido para familiarizaros con Cassandra. Nos vemos.

NoSQL (III): Java + Cassandra DB

13 thoughts on “NoSQL (III): Java + Cassandra DB

  1. Thrift es tan solo el protocolo de conexión para poder utilizar Cassandra. Aunque en la extensión para PHP existen métodos para poder trabajar con cassandra, requieren bastante código por eso utilizaremos PHPCassa como abstracción de la base de datos.

    Like

    1. svoboda says:

      Gracias por la información. La verdad es que como he dicho a lo largo de los diferentes posts, no he trabajado con NoSQL con otros lenguajes que no sean Java, así que cualquier información sobre esto es bien recibida. Un saludo.

      Like

    1. svoboda says:

      Pues, aún no me he metido en nada así, todo lo que he empezado con Cassandra, lo he hecho desde cero. Pero si tiene un pequeño nivel de inglés, te dejo un par de artículos que parecen interesantes:

      http://www.divconq.com/2010/migrate-a-relational-database-structure-into-a-nosql-cassandra-structure-part-i/
      http://www.divconq.com/2010/migrate-a-relational-database-structure-into-a-nosql-cassandra-structure-part-ii-northwind-planning/
      http://www.divconq.com/2010/migrate-relational-database-cassandra-part-3-northwind-conversion/
      or
      http://java.dzone.com/articles/jumping-mysql-cassandra

      En español, no he ecnontrado mucho material, otro día buscaré y si veo que no encuentro nada, quizás te coja la idea para un post o una serie de ellos. Un saludo

      Like

    1. svoboda says:

      Pues básicamente puedes hacer un bean al que acceder desde el jsp, y que rellenes desde una clase que tenga las consultas que desees sobre cassandra. No es diferente a como harías con cualquier otra BBDD en cualquier otro tipo de proyecto.

      Like

  2. pabloE says:

    Tengo este codigo para conectar a postgres desde jsp

    public class conexion {
    Connection conexion;
    Statement sentencia;
    PreparedStatement ps;
    String usuario, password, ip, puerto, bdatos;

        public conexion()throws ClassNotFoundException, SQLException, InstantiationException, IllegalAccessException{
        this.usuario    = "postgres";
        this.password   = "postgres";
        this.ip     = "127.0.0.1";
        this.puerto     = "5432";
        this.bdatos     = "hoja";
        this.conexionPostgres();
    }
    
    private void conexionPostgres()throws ClassNotFoundException, SQLException, InstantiationException, IllegalAccessException{
                Class.forName("org.postgresql.Driver").newInstance();
                this.conexion = DriverManager.getConnection ("jdbc:postgresql://"+ip+":"+puerto+"/"+bdatos,usuario,password);
                this.sentencia = (Statement) this.conexion.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
    }
    
    public Connection getConexion() throws SQLException{
        return this.conexion;
    }
    
    public void close() throws SQLException{
        this.conexion.close();
        this.sentencia.close();
    }    
    

    }

    Para cassandra-cli que tocaria modificar?

    Like

    1. svoboda says:

      Más o menos sería así ya que no tengo lugar ahora mismo donde probarlo. Te he dejado algunas cosas comentadas (los throws):

      public class Conexion {
      TTransport tr;
      TProtocol proto;
      Cassandra.Client client;
      String usuario, password, ip, puerto, keyspace;
      Map credenciales;

      public conexion()throws ... /* Añadir excepciones que correspondan */ {
          this.usuario = “cassandra”;
          this.password = “cassandra”;
          this.ip = “127.0.0.1″;
          this.puerto = “9160″;
          this.keyspace = “yourkeyspace”;
          this.conexionCassandra();
      }
      
      private void conexionCassandra()throws  ... /* Añadir excepciones que correspondan */ {
          tr = new TFramedTransport(new TSocket(ip, puerto));
          proto = new TBinaryProtocol(tr);
          client = new Cassandra.Client(proto);
          credenciales = new HashMap();
          credenciales.put(SimpleAuthenticator.USERNAME_KEY, usuario);
          credenciales.put(SimpleAuthenticator.PASSWORD_KEY, password);
          tr.open();
          client.set_keyspace(this.keyspace);
          client.login(this.keyspace, new AuthenticationRequest(credenciales));
      }
      
      public Cassandra.Client getClient() throws ... /* Añadir excepciones que correspondan */ {
          return this.client;
      }
      
      public void close() throws ... /* Añadir excepciones que correspondan */ {
          this.tr.close();
      }
      

      }

      Espero que te sirva. Un saludo.

      Like

    1. svoboda says:

      Si no eres más concreto con el error que tienes, me temo que no te puedo ayudar. Yo no tuve ningún problema al implementar esta pequeña demo.
      ¿Has revisado tu configuración de red? Cortafuegos y esas cosas…

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.