En el anterior post traté las acciones habituales que realizamos con Cassandra: guardar, actualizar y eliminar. Sin embargo aun quedan dos acciones muy útiles por tratar: los contadores y los indices secundarios.

 

CONTADORES

Los contadores son en realidad un tipo especial de validador de Column Family.

 

CREAR UN CONTADOR 

Para crearla procedemos de la siguiente manera:

– Accedemos a Cassandra Cluster Admin:

Página principal de Cassandra Cluster Admin

– Entramos en el keyspace con el que estamos trabajando:

Detalle del keyspace my_keyspace

– Pulsamos en Create New Column Family y escribimos los siguientes datos:

Datos para crear una Column Family con contadores

– En Default Validation Class el texto completo a escribir es:

org.apache.cassandra.db.marshal.CounterColumnType

– Y pulsamos el botón Create Column Family.

Varias cosas sobre los CounterColumn:
– Para crear los CounterColumns es obligatorio indicar en Default Validation Class la clase de validador correcto. Indicado más arriba.
– Los contadores puedes tener números positivos o negativos.
– Los CounterColumns no son un sustituto de el autoincrement de las bases relacionales.

Ahora que ya está creada la Column Family es hora de programar.

 

GUARDAR Y/O ACTUALIZAR UN CONTADOR 

En nuestra clase en cassandra.php creamos el siguiente método:

 

[codesyntax lang=»php»]

<?php

  public function guardarContador($name_columnFamily, $key, $column, $value=1, $super_column=NULL){

    try {
      if (!is_null($super_column)){
        $column_family = new SuperColumnFamily($this->conexion, $name_columnFamily);
        $column_family->add($key, $super_column, $column, $value);
      }
      else{
        $column_family = new ColumnFamily($this->conexion, $name_columnFamily);
        $column_family->add($key, $column, $value);
      }
      return true;
    }
    catch(Exception $e){
      return false;
    }
  }

[/codesyntax]

 

Con este método podremos incrementar o disminuir el contador.


$name_columnFamily
: Es el nombre de la column family donde se encuentra el contador a modificar.

$key: Clave del registro donde se encuentra el contador.
$column: Nombre del contador.
$value: Valor a añadir al contador.
$super_column: Clave de la super column donde se encuentra el contador.

Añadimos el siguiente código a nuestro archivo test.php:

[codesyntax lang=»php»]

<?php

if ( $cass->guardarContador('column_family_counter', 'post', 'num_total_post', 1)){
  print "El contador se ha actualizado correctamente<br />";
}else{
  print "Error al actualizar el contador<br />";
}

$result = $cass->obtener('column_family_counter', 'post');

print_r($result);

[/codesyntax]

Como ves, para recuperar un contador se utiliza el mismo método que para obtener cualquier otro registro. El resultado de este código sería:

El contador se ha actualizado correctamente
 Array ( [num_total_post] => 1 )

 

PONER A CERO EL CONTADOR

Para poner a cero un contador hay que restarle el valor que tenga en ese momento el contador. En test.php escribiríamos lo siguiente:

[codesyntax lang=»php»]

<?php

if ( $cass->guardarContador('column_family_counter', 'post', 'num_total_post', ($result['num_total_post']*-1))){
  print "El contador se ha actualizado correctamente<br />";
}else{
  print "Error al actualizar el contador<br />";
}

$result = $cass->obtener('column_family_counter', 'post');

print_r($result);

[/codesyntax]

Y el resultado:

El contador se ha actualizado correctamente
 Array ( [num_total_post] => 0 )

 

INDICES SECUNDARIOS

Los indices secundarios son un objeto especial en Cassandra que nos permite realizar búsquedas por columnas concretas.

Estos índices solo funcionan en las column family standard, con lo que su uso se ve bastante limitado.

 

 

CREAR UN INDICE SECUNDARIO

Para ello vamos a nuestro Cassandra Cluster Admin y en la column family my_column_family_standard pulsamos en Create Secondary Index:

Detalle de la ubicación del botón Create Secondary Index

Detalle de la ubicación del botón Create Secondary Index

– Nos aparecerá el siguiente formulario:

Detalle del formulario para crear un índice secundario

Detalle del formulario para crear un índice secundario

– Para nuestro cometido vamos a crear el siguiente índice secundario:

Formulario con los datos para el ejemplo

Formulario con los datos para el ejemplo

–  Pulsamos en Add Secondary Index.

 

REALIZAR UNA CONSULTA CON UN INDICE SECUNDARIO 

Nos vamos a nuestro archivo cassandra.php y añadimos el siguiente método:

[codesyntax lang=»php»]

<?php

  private function getIndexOperator($value){
    switch ($value){
      case '=':
        $operator = 'EQ';
        break;
      case '>=':
        $operator = 'GTE';
        break;
      case '>':
        $operator = 'GT';
        break;
      case '<=':
        $operator = 'LTE';
        break;
      case '<':
        $operator = 'LT';
        break;
      default:
        $operator = 'EQ';
        break;
    }

    return $operator;
  }

[/codesyntax]

Este método nos permitirá trabajar con operadores diferentes a la igualdad, pudiendo utilizar >,<,>=,<=.

Pero para poder trabajar con índices es necesario incluir en nuestro listado de namespaces dos nuevas clases, tal y como se muestra en el siguiente código:

[codesyntax lang=»php» highlight_lines=»9,10″]

<?php

use phpcassa\Connection\ConnectionPool;
use phpcassa\ColumnFamily;
use phpcassa\SuperColumnFamily;
use phpcassa\ColumnSlice;
use phpcassa\SystemManager;
use phpcassa\Schema\StrategyClass;
use phpcassa\Index\IndexExpression;
use phpcassa\Index\IndexClause;

[/codesyntax]

A continuación creamos el método que generará la consulta con los índices secundarios.

 

[codesyntax lang=»php»]

<?php

  public function obtenerPorIndices($name_columnFamily, $arrayColumnsValues, $range_start = "", $range_end = '', $column_count = 100, $invertir_orden = false){

    try{
      // Creamos el objeto
      $column_family = new ColumnFamily($this->conexion, $name_columnFamily);

      // Inicializamos las variables
      $index_exp = array();
      $registros = array();

      // Creamos un array de index_expression
      foreach($arrayColumnsValues as $key => $value){
        if (array_key_exists('operator', $value)){ 
          $op = $this->getIndexOperator($value['operator']); 
        }
        else{ 
          $this->getIndexOperator('='); 
        }

        $column = $value['values'];
        $key_column = key($column);

        $index_exp[] = new IndexExpression($key_column, $column[$key_column], $op);            
      }

      // Creamos la index_clause
      $index_clause = new IndexClause($index_exp, $range_start, $column_count);

      // Creamos la column_slice
      $column_slice = new ColumnSlice($range_start, $range_end, $column_count, $invertir_orden);

      // Recuperamos los registros
      $rows = $column_family->get_indexed_slices($index_clause, $column_slice);

      foreach($rows as $key => $columns){
        if (!array_key_exists($key, $registros)){ $registros[$key] = null; }
        $registros[$key] = $columns;
      }
      return $registros;
    }catch (Exception $e){
      return false;
    }
  }

[/codesyntax]

 

Con este método podremos buscar registros con varios índices secundarios.

Lo primero que hacemos en este método es crear el objeto ColumnFamily que nos proveerá de los métodos para hacer la consulta con indices secundarios. A continuación inicializamos varias variables necesarias para el método.

Dentro de un bucle creamos un array de IndexExpression(). Este objeto le indicará a Cassandra qué indices, con qué valores y qué operador se deben buscar los registros.

Seguidamente creamos la iIndexClause(), que nos permite indicarle la key desde la que comenzará a recuperar registros y el número de registros a obtener.

Por último recuperamos los registros utilizando el método get_indexed_slices().

Para probar el método vamos a crear datos de prueba en test.php y haremos la consulta:

 

[codesyntax lang=»php»]

<?php

$data[] = array(
    'title' => 'Apache Cassandra',
    'license' => 'Open Source',
    'category' => 'no-sql',
);

$data[] = array(
    'title' => 'MongoDB',
    'license' => 'Open Source',
    'category' => 'no-sql',
);

$data[] = array(
    'title' => 'MySQL',
    'license' => 'Open Source',
    'category' => 'sql',
);

foreach($data as $key => $value){
  $cass->guardar('my_column_family_standard', $key, $value);
}

$arrayColumnsValues[] = array(
    'values' => array(
      'category' => 'no-sql'
    ),
    'operator' => '='
);

$result = $cass->obtenerPorIndices('my_column_family_standard', $arrayColumnsValues);

print_r($result);

[/codesyntax]

 

Si ejecutamos el código anterior Cassandra nos devolverá:

Array ( [0] => Array ( [title] => Apache Cassandra [license] => Open Source [category] => no-sql ) [1] => Array ( [title] => MongoDB [license] => Open Source [category] => no-sql ) )

[ci-box type=»warning»]Al utilizar un operador diferente al = puede que Cassandra te devuelva un error. Para evitarlo añade otro indice secundario a la consulta pero con el operador =, siendo este la primera columna que Cassandra procese. Por alguna razón Cassandra devuelve un error si no se hace así. [/ci-box]

Con este post concluye la parte básica de PHPCassa, Cassandra y Cassandra Cluster Admin. En el próximo post y siguientes trataré varios temas que se han quedado un poco colgados o faltan por explicar como ordenar registros, cómo crear claves, mejorar el rendimiento de Cassandra, crear clusters, etc.