¡Por fin llego el día! ¡Hoy toca programar!
Para ello vamos a utilizar las clases de abstracción de la base de datos PHPCassa que nos ahorrará bastante tiempo para trabajar con Cassandra. Puedes descargarlo desde https://github.com/thobbs/phpcassa.
Ubicamos PHPCassa en una carpeta dentro de nuestro servidor web y creamos dos archivos. Yo los he llamado test.php y cassandra.php. El segundo será una clase que nos ahorrará algunas lineas de código con las tareas habituales. El primero lo utilizaré para testear la clase y sus respectivos métodos.
Bien empecemos.
PRIMEROS PASOS
En primer lugar necesitamos incluir un archivo de PHPCassa en cassandra.php:
[codesyntax lang=»php»]
<?php // CLASES NECESARIAS PARA CONECTAR CON CASSANDRA require_once('phpcassa/lib/autoload.php');
[/codesyntax]
He inmediatamente llamamos a los namespace mínimos para trabajar con PHPCassa:
[codesyntax lang=»php»]
<?php use phpcassa\Connection\ConnectionPool; use phpcassa\ColumnFamily; use phpcassa\SystemManager; use phpcassa\Schema\StrategyClass;
[/codesyntax]
Justo debajo creamos la clase:
[codesyntax lang=»php»]
<?php class cassandra { }
[/codesyntax]
CONECTANDO
Para realizar la conexión a la BD, PHPCassa nos pide tan solo un dato obligatorio: el nombre del keyspace con el que vamos a trabajar. También nos permite añadir las ips de los nodos con los que queramos trabajar, aunque por defecto su valor es localhost. Por tanto podemos crear un constructor como el siguiente:
[codesyntax lang=»php»]
<?php function __construct($keyspace, $nodos = array('localhost')){ if (!empty($keyspace)){ $this->conexion = new ConnectionPool($keyspace, $nodos); }else{ print "El keyspace está vacío"; } }
[/codesyntax]
Este constructor nos permite indicarle a la clase el keyspace con el que queremos trabajar y la ip o nombre de servidor donde se encuentre nuestra instancia de Cassandra. Por defecto el puerto al que se va a conectar es el 9160. Si hubieses configurado Cassandra para escuchar en otro puerto deberás especificarlo: localhost:9160.
Este código nos crea una variable llamada conexion que será una instancia del objeto ConnectionPool, necesario para todas las consultas a la BD
GUARDANDO REGISTROS
Ahora procedemos a crear el método que guardará los registros. Para ello primero crearemos un objeto ColumnFamily al que le pasaremos el nombre de la column family en la que queremos trabajar:
[codesyntax lang=»php»]
<?php public function guardar($name_columnFamily, $key, $data = array()){ try { $column_family = new ColumnFamily($this->conexion, $name_columnFamily); $column_family->insert($key, $data); return true; }catch(Exception $e){ return false; } }
[/codesyntax]
Este método nos devolverá true si se ha guardado correctamente el registro, o false en caso de error.
Como puedes ver, al objeto ColumnFamily se le pasa como primer parámetro el objeto ConnectionPool que creamos en el constructor, después se le pasa el nombre de la column family.
Una vez creado el objeto ColumnFamily ya podemos utilizar el método insert para guardar el registro pasándole como parámetros la key y un array con las columnas y sus respectivos valores.
RECUPERANDO REGISTROS
Recuperar registros de Cassandra es algo más complejo que guardarlos:
Primero debemos añadir un nuevo namespace que nos permitirá usar una clase que nos será muy útil. El listado de namespaces nos quedaría así:
[codesyntax lang=»php» highlight_lines=»5″]
<?php use phpcassa\Connection\ConnectionPool; use phpcassa\ColumnFamily; use phpcassa\ColumnSlice; use phpcassa\SystemManager; use phpcassa\Schema\StrategyClass;
[/codesyntax]
A continuación creamos el método en nuestro archivo cassandra.php:
[codesyntax lang=»php»]
<?php public function obtener($name_columnFamily, $key, $column_names= NULL, $range_start = "", $range_end = "", $column_count = 100, $invertir_orden=false){ try{ $column_slices = new ColumnSlice($range_start, $range_end, $column_count, $invertir_orden); $column_family = new ColumnFamily($this->conexion, $name_columnFamily); $result = $column_family->get($key, $column_slices, $column_names); }catch(Exception $e){ return false; } return $result; }
[/codesyntax]
Este método tiene algunos parámetros más que al guardar, pero tienen su razón de ser:
$columnFamily: Nombre de la column family donde buscar.
$key: Clave del registro donde buscar.
$columns: Columnas a buscar. No es obligatorio. Por defecto NULL.
$range_start: Key por la que Cassandra debe empezar a recuperar registros. No es obligatorio. Por defecto «».$range_end: Key por la que Cassandra dejará de recuperar registros. No es obligatorio. Por defecto «».
$column_count: Número de registros a obtener, Por defecto 100.
$invertir_orden: Invierte el orden en el que se recuperar los registros. De mayor a menor o viceversa, de la A-Z o viceversa, etc.
Como ves tienes bastantes opciones para recuperar registros. Este método devuelve un array con los registros.
PROBANDO LA CLASE
Vamos a probar el código a ver que tal funciona. Nos vamos al archivo test.php y escribimos el siguiente código:
[codesyntax lang=»php»]
<?php include_once "cassandra.php"; $cass = new cassandra('my_keyspace', array('192.168.1.10')); $data = array( 'nombre' => 'pepito', 'ciudad' => 'Madrid', 'vehiculo' => 'coche', ); if ( $cass->guardar('my_column_family_standard', $key=1, $data)){ print "El registro se ha guardado correctamente<br />"; }else{ print "Error al guardar el registro<br />"; } $result = $cass->obtener('my_column_family_standard', $key=1); print_r($result); ?>
[/codesyntax]
Explico un poco el código anterior:
- Incluimos la clase en el archivo.
- Creamos el objeto indicándole el keyspace con el que trabajar (my_keyspace), y dentro de un array, la ip donde se encuentra en nodo de Cassandra. Si tuvieses Cassandra instalado en localhost no sería necesario indicar el segundo parámetro.
- Creamos el array que contendrá los datos a guardar.
- Creamos un condicional que guardará los datos en Cassandra y nos indicará si se han guardado correctamente o ha habido algún error.
- Guardamos en una variable ($result) los registros que recuperamos a través del método obtener del objeto $cass. A este método le indicamos la column family a buscar y la key a obtener.
- Mostramos los registros.
Si todo ha salido correctamente verás un texto como el siguiente cuando ejecutes el script:
El registro se ha guardado correctamente Array ( [ciudad] => Madrid [nombre] => pepito [vehiculo] => coche )
Si te aparecen más registros es posible que no vaciases las column family con la que trabajas. Simplemente ves a Cassandra Cluster Admin, entra en la column family y pulsa en Truncate Column Family. Así eliminarás todos los datos de la column family.
ACTUALIZAR UN REGISTRO
Ahora que ya funciona nuestra clase podemos ampliarla con nuevas características.
Aunque pienses que para actualizar un registro es necesario un nuevo método, en Cassandra no es necesario, simplemente utilizaremos el método guardar indicandole la key a modificar y el array con los datos a guardar.
Justo debajo del código que ya tenemos en el archivo test.php escribimos lo siguiente:
[codesyntax lang=»php»]
<?php $data = array( 'ciudad' => 'Barcelona', ); if ( $cass->guardar('my_column_family_standard', $key=1, $data)){ print "El registro se ha guardado correctamente<br />"; }else{ print "Error al guardar el registro<br />"; } $result = $cass->obtener('my_column_family_standard', $key=1); print_r($result);
[/codesyntax]
Como observarás el array no tiene todos los datos de la key que vamos a modificar, ya que no es necesario, tan solo pasaremos los datos que queremos actualizar. El resultado de este código es el siguiente:
El registro se ha guardado correctamente Array ( [ciudad] => Madrid [nombre] => pepito [vehiculo] => coche ) El registro se ha guardado correctamente Array ( [ciudad] => Barcelona [nombre] => pepito [vehiculo] => coche )
La columna ciudad a cambiado, el resto sigue igual, la razón está en que cuando le pasas a Cassandra una key que ya existe, lo que hace es actualizar las columnas que se correspondan con las keys del array. Si en ese array hubiera keys que no existen como columnas en el registro, Cassandra simplemente las crearía nuevas.
GUARDANDO UNA SUPER COLUMN
Aquí tampoco nos hace falta crear un nuevo método ya que nos sirve perfectamente el método guardar, pero deberemos hacerle algunas modificaciones.
En primer lugar, para trabajar con column families super es necesario añadir una llamada al namespace concreto. La lista de namespaces quedaría de la siguiente manera:
[codesyntax lang=»php» highlight_lines=»5″]
<?php use phpcassa\Connection\ConnectionPool; use phpcassa\ColumnFamily; use phpcassa\SuperColumnFamily; use phpcassa\ColumnSlice; use phpcassa\SystemManager; use phpcassa\Schema\StrategyClass;
[/codesyntax]
Ahora debemos modificar el método guardar y añadirle el parámetro $is_super_column, que nos permitirá crear un objeto SuperColumnFamily o ColumnFamily según corresponda. El método nos quedaría así:
[codesyntax lang=»php»]
<?php public function guardar($name_columnFamily, $key, $data = array(), $is_super_column = false){ try { if ($is_super_column){ $column_family = new SuperColumnFamily($this->conexion, $name_columnFamily); } else{ $column_family = new ColumnFamily($this->conexion, $name_columnFamily); } $column_family->insert($key, $data); return true; }catch(Exception $e){ return false; } }
[/codesyntax]
Como ambas clases comparten el método insert no nos hace falta incluir esa linea dentro del condicional.
A continuación modificamos el método obtener con el mismo parámetro y utilizando el mismo sistema para crear el objeto correspondiente:
[codesyntax lang=»php»]
<?php public function obtener($name_columnFamily, $key, $is_super_column=false, $column_names= NULL, $range_start = "", $range_end = "", $column_count = 100, $invertir_orden=false){ try{ if ($is_super_column){ $column_family = new SuperColumnFamily($this->conexion, $name_columnFamily); } else{ $column_family = new ColumnFamily($this->conexion, $name_columnFamily); } $column_slices = new ColumnSlice($range_start, $range_end, $column_count, $invertir_orden); $result = $column_family->get($key, $column_slices, $column_names); }catch(Exception $e){ return false; } return $result; }
[/codesyntax]
Ahora podemos añadir el siguiente código a nuestro archivo test.php:
[codesyntax lang=»php»]
<?php $data = array('vecino_1' => array( 'nombre' => 'pepito', 'ciudad' => 'Madrid', 'vehiculo' => 'coche', )); if ( $cass->guardar('my_column_family_super', $key=1, $data, $is_super_column=true)){ print "El registro se ha guardado correctamente<br />"; }else{ print "Error al guardar el registro<br />"; } $result = $cass->obtener('my_column_family_super', $key=1, $is_super_column=true); print_r($result);
[/codesyntax]
El único cambio además del nombre de la column family donde vamos a guardar el registro, se encuentra en el array con los datos. Este tiene un elemento que es la key de la super column, y como valor, el array de las columns a guardar.
Si ejecutamos el código anterior nos devolverá lo siguiente:
El registro se ha guardado correctamente Array ( [vecino_1] => Array ( [ciudad] => Madrid [nombre] => pepito [vehiculo] => coche ) )
[ci-box type=»warning»]Al probar el código, PHP me devolvió el siguiente aviso:
Strict Standards: Declaration of phpcassa\SuperColumnFamily::add() should be compatible with that of phpcassa\ColumnFamily::add() in /var/www/prueba_cassandra/phpcassa/lib/phpcassa/SuperColumnFamily.php on line 491.
No te preocupes no afecta ni a los ejemplos ni a la clase que funcionan correctamente.[/ci-box]
ACTUALIZANDO UNA SUPER COLUMN
La actualización de una super column se limita a las columnas que contienen los valores del registro no a su key. Si modificáramos la key , lo que en realidad estaríamos haciendo sería crear una nueva super column. Añadimos el siguiente código a nuestro archivo test.php:
[codesyntax lang=»php»]
<?php $data = array('vecino_1' => array( 'nombre' => 'pepito', 'ciudad' => 'Barcelona', 'vehiculo' => 'coche', )); if ( $cass->guardar('my_column_family_super', $key1, $data, $is_super_column=true)){ print "El registro se ha guardado correctamente<br />"; }else{ print "Error al guardar el registro<br />"; } $result = $cass->obtener('my_column_family_super', $key=1, $is_super_column=true); print_r($result);
[/codesyntax]
Y el resultado es:
El registro se ha guardado correctamente Array ( [vecino_1] => Array ( [ciudad] => Barcelona [nombre] => pepito [vehiculo] => coche ) )
ELIMINAR REGISTROS
Sí, aquí toca crear un nuevo método para nuestra clase en cassandra.php, aunque tampoco nos vamos a matar programando:
[codesyntax lang=»php»]
<?php public function eliminar($name_columnFamily, $key, $is_super_column = false){ try{ if ($is_super_column){ $column_family = new SuperColumnFamily($this->conexion, $name_columnFamily); } else{ $column_family = new ColumnFamily($this->conexion, $name_columnFamily); } $column_family->remove($key); return true; }catch(Exception $e){ return false; } }
[/codesyntax]
El método es bastante sencillo: se le pasan tres parámetros que ya conocemos.
Dentro del método se crea un objeto ColumnFamily y se utiliza el método remove para eliminar el registro pasándole la key correspondiente, y si fuese una super column, la key de este.
El método remove tiene un segundo parámetro que por defecto tiene un valor null, en él se pueden añadir como array los nombres de las columnas a eliminar. Como no es habitual ese proceso he creído adecuado no utilizarlo.
Una vez añadido esté método a nuestra clase modificamos el archivo test.php con el siguiente código:
[codesyntax lang=»php»]
<?php if ( $cass->eliminar('my_column_family_standard', $key=1)){ print "El registro se ha eliminado correctamente<br />"; }else{ print "Error al eliminar el registro<br />"; } $result = $cass->obtener('my_column_family_standard', $key=1); print_r($result);
[/codesyntax]
Y el resultado es:
El registro se ha eliminado correctamente
De momento con esto es suficiente, dejo en tus manos estos métodos para que juegues con ellos todo lo que quieras y te familiarices con PHPCassa.
En el próximo post trataré las Counter Columns que nos servirán para contar registros, los Secondary Index que nos permitirán realizar búsquedas por columnas concretas, y algunas cosas más.