Cómo crear tu propio Twitter con NoSQL

Hacía tiempo que tenía ganas de escribir algo sobre NoSQL ( Not only SQL ), y algunos clientes me han pedido que les programara una red social varias veces,…desde que Twitter empezó a usar este tipo de base de datos porque MySQL ya tenía hacía un tiempo algunos problemas de latencia, debido a la gran cantidad de datos nuevos a indexar, …pensad que en un día como hoy se generan más de 12 TeraBytes de información de los twitts, es decir, aproximadamente 4 PetaBytes al año, estamos hablando del 2010 y estos datos se doblan cada año, pues multiplicad por 6…casi ná!

Me pregunté , ¿Cómo debería un programador php freelance construir una red social como Twitter o Facebook?

¿Qué hacer con semejante volumen de datos y tenerlo todo ordenado e indexado?, es una tarea colosal, ¿verdad? ,pues bien, los chicos de Twitter nos contaron en el evento Strange Loop de 2010 ( video + audio | pdf  ) que diseñaron estrategias mixtas de bases de datos con NoSQL ,donde MySQL no llegaba a ser suficiente, imagino que los cortes en el servicio de por aquellos entonces tuvieron mucho que ver con esto…normal. Estas estrategias se basan en construir un sistema o arquitectura de sistemas de información integrados…pero…Por qué llegaron a usar NoSQL en Twitter: porque necesitaban recoger todos los datos de forma eficiente de millones de usuarios, guardarlos y analizarlos, algoritmos capaces de “aprender” acerca de la información de estos datos para saber cómo tratarla y optimizarla – indexarla, análisis de grafos sociales, etc.

Luego los problemas a solucionar eran: 1. recoger datos, 2. guardar y analizar los datos, 3. aprendizaje rápido de datos masivos
Ahora comentaré un poco esta presentación:

 

1. Recoger datos masivos [logs]

Empezando por el escritor de logs, empezaron usando syslog pero no era escalable, se colgaba y se perdían datos, por lo que usaron Scribe montado sobre Apache Thrift que si es escalable y también usado por Facebook, es un framework de código abierto que escribe líneas de datos en categorías y hace mucho trabajo por nosotros, ya que colecciona datos de diferentes máquinas en un clúster funcionando de forma local y en red, de forma que se administra para no perder los datos de los nodos, es escalable, jerárquico y permite conectar salidas externas de los datos fácilmente…de modo que usar esta tecnología solucionó el primero de los problemas. Como en Twitter son muy majos, extendieron el framework opensource mejorando la escritura, compresión, monitorización y escritura en HDFS continuando el trabajo con parches de FB lo que hizo posible almacenar más de 12TB al día sin que fuera un drama.

 

2. Guardar y analizar datos masivos

Sí, el que escribe ha mencionado HDFS que viene de Hadoop, un framework para guardar los datos de forma distribuída, es decir, una técnica que permite escribir todos esos datos masivos en un clúster de máquinas, porque ,en fin, ya sabéis que no hay disco duro que pueda escribir tantos datos tan rápido, …por ahora…

Guardar los datos

Esto es algo complejo porque un sistema así necesita replicación automática y tolerancia a fallos, algo que soporta Hadoop. Hay que pensar que esta arquitectura de información funciona como un gran disco duro compartido entre diferentes nodos.

Analizar los datos

 

Además permite MapReduce una tecnología de Google ( ya sabéis que este tiene servidores de alta replicación y aplicaciones distribuidas –google app engine– ) , basado en computación paralela y el par llave-valor de amplio rango…por ejemplo Yahoo! tiene un clúster de 4000 nodos, es capaz de ordenar 1 TB de números aleatorios (índices) en 62 segundos, y además permite empaquetar fácilmente gracias a Cloudera RPM (donde está ahora el creador de Hadoop).

Ejemplo de MapReduce

Ejemplo de MapReduce

Un ejemplo del uso de MapReduce sería una consulta para saber cuántos tweets tiene un usuario, obteniendo los datos de la tabla de tweets, se le pasa una llave que es la columna y el valor es la información del tweet, el mapa de salida tiene una llave que es el id de usuario y un valor numérico, se barajan los datos ordenándolos por este id de usuario y se reducen por la misma razón, una máquina puede hacer esto fácilmente, varias máquinas nos devuelven los datos más rápido, mientras más se usen más rápidamente se devuelve el resultado, la cuestión es cómo balancear la carga…

Uno de los retos sería analizar datos de grafos sociales en relaciones entre usuarios, por ejemplo, los seguidores de alguien, es imposible hacer una consulta MySQL con un self join de una tabla con n-millones de filas…entonces se usa el clúster para hacer más fácil distribuir cálculos que se trata de la diversión que proporciona la computación paralela :D

Hacerlo de esta forma significa que puedes contar todos los tweets, es decir, los más de 20 millones en 5 minutos aproximadamente…

 

3. Aprendizaje rápido de datos masivos

Obtener datos rápidamente de datos masivos

¿Cómo están estructurados los datos almacenados?, están los datos semi-estructurados: logs de apache, logs de consultas, logs RoR, tests A/B, etc., y luego están los datos estructurados: tweets, usuarios, bloques, teléfonos, favoritos, búsquedas guardadas, etc. , por último están los datos complejos: grafos sociales, esto último me pareció lo más interesante pues es algo que usamos todos en twitter, cuando buscamos en la red social información sobre un meta-tag o un usuario o una palabra por ejemplo (conteno, mínimo, máximo, etc.), se devuelve un resultado basado en cientos o miles de capas de información por los que viajan indagando en nuestra consulta…

En este caso, el sistema que utilizan en Twitter para hacer la indagación es conocido como Apache Pig , basado en un lenguaje de alto nivel , capaz de transformar datos de conjuntos y registros y procesarlos mediante transacciones, el lenguaje de pig es un poco diferente al SQL que conocemos…y es normal ya que cuando tienes un fichero muy grande, y que se ha transformado en un conjunto de registros, hay que especificar algunas cosas ,aunque es bastante fácil de entender, veamos un ejemplo de un script que nos propone Kevin Weil en su presentación:

scrip_pig

es un script para contar los 5 primeros tweeteros entre 18 y 25 años ordenados por mayor número de seguidores  y agrupados por urls, se hace un joint, un group y un order limitándolo a 5…esta consulta realizada en Hadoop ocuparía como 100 veces más en código lo cual es algo que nos dice lo que nos estamos ahorrando, de hecho…Pig democratiza el análisis de datos a gran escala, lo que significa usar el 5% del código y el 5% del tiempo que se tardaría normalmente además está optimizado hasta un 20% en tiempo de ejecución, pero, y siempre hay un pero xD,  depende del tipo de consulta que hagas, claro,…debido a lo importante que es ahorrar recursos se preparan muy bien las preguntas, aún así, se utilizan mecanismos automáticos de medida de latencia media, distribución geográfica, etc. que ayudan a recuperar la respuesta más eficientemente…

Aquí un ejemplo de script para buscar con Pig  una url

script_pig_url

Aprendizaje

Es precisamente saber qué consulta hacer lo que le da valor al sistema,y esto sirve para promover la innovación que necesita cada iteración ,al ingeniero, de forma que mientras mejores preguntas y más personas integren el equipo de mejora, más rápido mejorará el sistema.

Resumiendo, en el eco-sistema de Twitter tienen Cloudera: es una distribución libre que se usa desde 2010 en combinación con CDH2 y Hadoop, esto junto con Scribe y LZO, que es ideal para comprimir los datos que se escriben en el HDFS; y, MapRedude implementado en Java (HBase, Hadoop streaming, etc)

Para que las máquinas sepan relacionar mejor los datos se utilizan algoritmos probabilísticos , de covarianza e influencia, algunos criterios por ejemplo serían el uso por parte de clientes de escritorio, móviles y web, correlaciones importantes cuando hablamos de grandes volúmenes de datos.

¿Cómo se puede aprender de lo que los usuarios escriben en twitter?

Evidentemente los fallos del sitio son oportunidades únicas para aprender,

  • ¿qué es lo que fué mal al mismo tiempo?
  • ¿ qué es lo que más se utilizó por parte de los usuarios?
  • A/B testing, etc.

conociendo las preguntas, entonces se pueden buscar correcciones y sugerencias de cambios como respuestas.

Para aprender, las preguntas correctas que debemos formular serían:

  • ¿qué está diciendo un usuario?
  • ¿y sus seguidores?
  • ¿y los usuarios a los que sigue?
  • ¿qué nos dice el ratio de seguidores/seguidos?
  • ¿de qué idioma se trata?
  • ¿son reconocibles los términos utilizados?

y etc.,…estas preguntas generan un gran flujo de información que resulta, entre otras cosas, en la creación de grafos sociales y que nos dan una idea directa de información como puede ser la reputación de ese usuario, de su influencia, en definitiva lo que se aprende son datos aplicables al aprendizaje que pueden ejecutar computadoras.

Estos datos se pueden analizar para buscar patrones, por ejemplo, se puede usar el programa de la FOCA de nuestro hacker español Chema Alonso y descubrir el patrón de movimiento de un usuario gracias a los tweets con meta-información que nos permiten estar geolocalizados, de manera que en un mapa aparecerán nuestras rutas por semana y cosas por el estilo. Otro ejemplo práctico para los administradores de la red social es poder encontrar bots, este script es un ejemplo de cómo se haría:

script_encuentra_bots_pig

 

 

Y hasta aquí he hablado un poco sobre lo que dijo Kevin en 2010 pero si tenéis ganas de más, hay mucho más!, de hecho dentro de muy poco dará lugar un evento acerca del estado actual de NoSQL, en la NoSQL Now! 2013 Conference. Con ponentes de Amazon (que da soporte a Apple y su iCloud por ejemplo), GitHub, RackSpace, etc., y allí contarán las cosas que están de moda jeje

Para nosotros simples mortales con proyectos webs que no alcanzan los millones de visitas al día, ¿qué podemos utilizar?, pues bien, hay varias soluciones, entre las que cabe destacar, además de las utilizadas por Twitter ( Cassandra y Cloudera ), está MongoDB, HyperTable, etc., depende del uso que se le vaya a dar, más información acerca de las más de cien implementaciones de NoSQL en nosql-database.org , de hecho se estuvo estudiando el uso de este tipo de base de datos para WordPress pero como se requiere un grado mayor de relaciones entre entidades no sería tan eficiente y se descartó…

Si lo que queréis es usar PHP y una base de datos NoSQL hay una implementación de API’s para muchas de ellas, por ejemplo para HyperTable, CouchDB, etc., para esta última tenemos PHPillow, pero lo importante es preguntaros para qué las váis a usar, si es para guardar

  • pares de llave/valor ( Riak, Redis, memcached, BigTable etc.)
  • muchas columnas – XML – ( Cassandra, BaseX, eXist, MarkLogic Server etc.)
  • documentos (CouchDB, Jackrabbit, MongoDB, OrientDB, SimpleDB,Terrastore, etc)
  • grafos -objetos- ( AllegroGraph, DEX, Neo4j, FlockDB, Sones GraphDB etc.) , XML

cada una tiene una disponibilidad de los datos (ver teorema de CAP), consistencia y tolerancia de particiones (fallos) diferente, por ejemplo para una bd distribuida basada en pares de llave/valor como Redis se podría escribir un script como este en PHP:

$redis = new PredisClient(9;
$redis->set('miLlave', 'Un valor');
$valor = $redis->get('miLlave');

ok, pues extrapola esto y constrúyete tu propio clon twitter con Redis jaja.

Sin embargo con la aproximación por columnas se puede crear un modelo relacional a medida, tomando como base dimensiones o categorías:columnas_bd_nosqlesto se puede hacer con Cassandra, deberías usarla siempre que necesites guardar más que leer, y que los datos tengan una gran disponibilidad, además trae soporte de Hadoop como hemos visto antes. Hay diferentes implementaciones en PHP como es el caso de phpcassa.

Aquí un ejemplo del uso de los índices de columna de Cassandra escrito en PHP:

 

//Conectar con el espacio de llaves
$basedatos = new ConnectionPool('mi-bd-twitter');
 
//Crear la familia de columnas de usuarios
$usuarios    = new ColumnFamily($basedatos, 'usuarios');
 
//Crear un usuario
$usuarios->insert('6', array('name' => 'Juan Belon',
 'nick' => 'juaxix' ));
 
//Obtener usuario
$usuario = $usuarios->get('6');

 

Ok, hasta ahí para las bases de datos por columnas, como véis es bastante sencillo, de hecho hay algunas implementaciones por ejemplo para MongoDB que usan JSON para comunicarse con las API’s e incluso han creado fáciles administradores en PHP…,ahora,  para el caso de usar una base de datos distribuida orientada a almacenar documentos, sin ningún esquema, donde tienes un “cubo” de pares de llaves/valor dentro de un objeto, es uno de los casos en los que se puede usar un lenguaje más conocido por nosotros amantes del SQL, y MongoDB es lo que a los programadores PHP puede que les guste más porque se pueden escribir líneas de código tales como

$post -> where ( ‘id’  , $id ),

y cosas así, muy parecidas al modelo de datos persistentes de Google App Engine, de hecho hay bastantes implementaciones y herramientas para MongoDB ,supongo que porque es el tipo de base de datos NoSQL más divertida XD …hay un caso para usar con el framework y cms CakePHP, CodeIgniter, Symfony, etc, …veamos un ejemplo con ActiveMongo:

ActiveMongo::connect('mi-bd-twitter', 'localhost');
class Usuario extends ActiveMongo {
 public $nombre;
 public $usuario;
}
 
$usuario = new User();
$usuario->nombre = 'Juan Belon';
$usuario->usuario = 'juaxix';
 
//Insertar usuario
$usuario->save(); // XD qué fácil es ,eh
 
//Actualizar el nombre
$usuario->nombre = 'Juan Belon Perez';
$usuario->save();

así que sería fácil montar un sistema de bibliotecas para almacenar millones de entradas, en el caso de usar CouchDB, echadle un vistazo al link de herramientas de CouchDB con PHP, veréis que es muy parecido y la diferencia radica en que ésta tiene replicación bi-lateral (maestro-maestro) y una API JSON por defecto (en MongoDB es una extensión)…

En el caso en que te decidas por usar una base de datos distribuida basada en grafos (modelo de grafos construído con nodos con propiedades y relaciones ), tienes Neoj4por ejemplo que es totalmente transaccional y tiene una API muy flexible, pero es un poco más complejo de entender y puede que no la entiendas a la primera jeje pero úsala siempre que quieras establecer grafos de relaciones sociales, mapas de carreteras, topologías de red, etc. En PHP tienes NeojPHP, REST API, Thrift, etc. pero como digo, es algo más complejo y menos divertido.

¿Qué base de datos NoSQL usarás para crear tu clon de twitter ahora que sabes todo esto?

Programación de redes de redes sociales con elgg

Desde que Facebook empezó a tener éxito, los clones de redes sociales no pararon de aparecer, sobre todo webs de contactos como zoosk, badoo, linked in, …o las miles de redes más, cada una con su propósito, sin embargo las necesidades del público son tan dispares que empezaron a salir generadores online de redes sociales, no contentos con esto, ya que a nadie le interesa tener alojada una red social en las máquinas de alguien que no conoce, aparecieron generadores de redes sociales pero esta vez ,instalables en un servidor propio…una de esas opciones, de la más extendida ,es elgg…
Con elgg podemos simular un facebook, y digo simular porque no trae soporte para clústers, ni gestor de aplicaciones con APi externa, ni chat integrado, pero sí trae las herramientas para programar todas estas cosas, empezando por el muro, existe un componente llamado riverdash que lo implementa, en mi caso he estado extendiendo la funcionalidad de este plugin para un cliente y tengo que decir que el código de elgg aún tiene que madurar ,sin embargo entraña un potencial muy grande que puede aprovecharse tanto para construir una buena red social como para una aplicación de un grupo más reducido de personas que necesiten compartir información.

Podemos consultar la Wiki de Elgg aquí y descargarnos la última versión aquí.

Para añadir funcionalidades a esta red social personal se utiliza el directorio “mod” donde creamos un nuevo subdirectorio con el nombre de nuestro módulo, llamémoslo “saludo”, dentro, si creamos un fichero llamado “start.php” elgg cargará nuestro módulo, en dicho fichero se especifican las inicializaciones a realizar; lo primero después de esto es crear un subdirectorio dentro de “saludo” para las vistas, llamado “views”…aquí empieza a complicarse, tenemos varios tipos de vistas, lo normal es xhtml así que por defecto se llama al subdirectorio dentro de views , “default”, ahora, si es un widget (zona flotante que se puede colocar en cualquier lugar de las plantillas de la web) pues irá dentro del subdirectorio de default, “widgets”, y vamos a llamar al nuevo fichero “vista.php”, luego la ruta completa es
/mod/saludo/views/default/widgets/vista.php , y el código para esta vista es:

[source language=”php”]

[/source]

para que podamos gestionar el widget desde la administración iremos a /mod/saludo/start.php y lo dejaremos así:

[source language=”php”]

function iniciar_saludo() {
add_widget_type(‘saludo’, ‘Mod de Saludo’, ‘Simplemente saluda’);
}

register_elgg_event_handler(‘init’,’system’,’iniciar_saludo’);

[/source]

De forma que elgg ya sabe qué es lo que tiene que hacer con nuestro nuevo módulo…

Para complicarlo un poco más y pasarle datos a nuestro módulo usaremos una vista de elgg, creando un fichero llamado hola.php donde estaba vista.php, con el siguiente contenido:

[source language=”php”]

Tu saludo:
‘params[mensaje]’,
‘value’ => $vars[‘entity’]->mensaje,
‘class’ => ‘hola-input-text’ ) );
?>

[/source]

así, especificamos a elgg que queremos mostrar un tipo de vista basada en un input text con el nombre “mensaje” y el valor es el que tenga la propia entidad (al principio ninguno) en su atributo mensaje, la class es CSS…

Ahora, para que la vista.php muestre el saludo enviado, necesitamos cambiarla para que quede así:

[source language=”php”]

mensaje; ?>

[/source]

Para más información acerca de las vistas pinchar aquí.

La gestión de idiomas se lleva por medio de un array de valores en /mod/saludo/languages/es.php, el índice o clave de una palabra o frase a almacenar contiene el prefijo del módulo, en nuestro caso “saludo:____” , donde ___ es el resto de la llave, por ejemplo, para inicio ->

[source language=”php”]

$espanol = array ( “saludo:inicio” => “Inicio”);

$english = array(“saludo:inicio” => “Home”);

add_traslation(“es”, $espanol);

add_traslation(“en”, $english);

//Para utilizar las claves:

echo elgg_echo(“saludo:inicio”);

[/source]

En este vídeo se puede comprobar como se ha modificado elgg para añadir un motor tipo “muro” de facebook, se ha añadido la funcionalidad de mostrar comentarios, eventos, “me gusta” y “no me gusta”, enviar a redes sociales, etc.

Los encargos que he realizado están asociados a la creación de herramientas (plugins) y modificaciones del núcleo para importar y exportar contenido entre redes sociales y elgg. Desde Blogger hasta Facebook pasando por WordPress, las “tools” que he diseñado específicamente importan y exportan entradas del river-dashboard, también conocido como el famoso muro en facebook, pero adaptado para elgg.

Actualización Marzo 2011:

Crear un plugin como extensión de otro para elgg:
1.- crear directorio en /mod/nombre_plugin
2.- crear /mod/nombre_plugin/manifest.xml
[sourcecode language=”xml”]






3.- crear /mod/nombre_plugin/start.php
donde al menos registraremos una función para la carga del plugin y otra función para manejar los eventos, opcionalmente añadiremos acciones también (funciones,claro).

register_elgg_event_handler('init','system','nombre_plugin_init');
register_elgg_event_handler('pagesetup','system','nombre_plugin_pagesetup');

En el caso en que queramos permitir el uso de preferencias por usuario del plugin, usaremos en start.php -función nombre_plugin_init()-, el siguiente código:

register_plugin_hook('usersettings:save','user','nombre_plugin_user_settings_save');

La función para guardar estas preferencias debe ser algo como:

function nombre_plugin_user_settings_save(){
//sólo usuario registrado y propietario de la cuenta a editar opciones
gatekeeper();
$user = page_owner_entity();
if (!$user) {
$user = $_SESSION['user'];
}
 
$user->nombre_input =  get_input('nombre_input','valor_por_defecto');
 
}

Evidentemente tenemos que añadir las vistas como página
en la función nombre_plugin_pagesetup:

 
//Añadir los campos de configuración de usuario
extend_elgg_settings_page(
'nombre_plugin/settings/usersettings',
'usersettings/user'
);

y claro, necesitamos crear el fichero que referenciamos, en
/mod/nombre_plugin/views/default/settings/usersettings.php
donde colocaremos los (html) que necesitemos. Para obtener los valores en dicha vista de los propios inputs, usaremos

$user = page_owner_entity();

y los valores están dentro de esta clase: $user->nombre_input…
Como truquito que me gusta utilizar, para crear una lista de valores con un select, usar las funciones implode para guardar el dato y split para el dato leído e interpretarlo.

Si queremos que el plugin tenga opciones para el administrador creamos el directorio
/mod/nombre_plugin/views/settings/nombre_plugin/
y dentro colocamos el fichero edit.php. Aquí lo único que tenemos que hacer es escribir por pantalla los campos input que queramos como opciones de administración del plugin, el motor de Elgg nos guardará solito los valores al pulsar en en el botón submit “save”, para obtener el valor del input tenemos que llamar a la función get_plugin_setting(‘nombre_input’,’nombre_plugin’) que nos devuelve el valor.

Tened en cuenta que Elgg usa muchos automatismos, por ejemplo sólo con crear un fichero con el mismo nombre del plugin dentro del directorio settings de mod, ya tenéis hecho un gestor de opciones para vuestra contribución, son cosas como estas las que la comunidad agradece tanto, si echáis un vistazo a los foros veréis de lo que hablo, un saludo

PHP : MySQL o NoSQL – Digg, Facebook y Twitter hablan

Vía vivalinux, Leyendo por la red encuentro un enlace a la notica de que Twitter se cambiaba de MySQL a una arquitectura de NoSQL basada en el proyecto de Cassandra: un sistema de administración de base de datos distribuído diseñado para manejar enormes cantidades de información replicadas en varios servidores comunes y corrientes (parecido a lo que hace Tuenti con sus granjas de caché). Usa el modelo de datos del BigTable de Google ejecutado sobre una infraestructura similar a la de Dynamo usada por los servicios web de Amazon (como S3).

Pero lo más importante es que, como una solución NoSQL, Cassandra rompe con la larga historia y teoría de las bases de datos relacionales por otro modelo con un almacenamiento híbrido del tipo “clave ⇒ valor”, totalmente descentralizado y mucho más fácil de escalar que MySQL.

Por ese motivo es que ahora Digg quiere alejarse tanto como puedan de LAMP, comenzando por cambiar MySQL por Cassandra:

“Nuestra principal motivación para alejarnos de MySQL es la creciente dificultad de construir una aplicación de alto rendimiento con escrituras intensivas en un conjunto de datos que crece rápidamente, sin un final a la vista.

A medida que nuestro sistema crece, es importante abarcar múltiples data centers para redundancia y performance de la red, para agregar capacidad o reemplazar sin downtimes nodos que hayan fallado. Planeamos continuar usando hardware común y continuar asumiendo que fallará regularmente. Todo esto es crecientemente difícil con MySQL”.

Cassandra fué desarrollado por Facebook, pero ahora es de código abierto amparado bajo la licencia de Apache. Digg también prometió comenzar a contribuir sus propias mejoras y modificaciones.

En el procesamiento para cloud compiting hace falta una base de datos realmente rápida…

Si os preguntáis por qué se sigue utilizando MySQL o NoSQL en lugar Oracle que tiene un mayor rendimiento: leer más quizás el tema de las licencias responda a vuestra pregunta…

O también puede responderos a esta pregunta el que la facilidad tiene que ver mucho con HTML5 y su WebSimpleDB API

NoSQL se basa en unos patrones, además del de “tipo=>valor”, aquí teneis un tutorial…veamos un ejemplo sencillo usando la librería más simple que he encontrado en PHP: OneFile -> OneSQL:

 
// SELECT * FROM $table WHERE $property $comparator
//                    $value        AND $prop2 $comp2 $val2
function nosql_selectAllFromWhereAnd($table,$property,$comparator,
$value  ,$prop2,$comp2,$val2)
 
// UPDATE $table SET $prop=$new
//                    WHERE $searchfor=$value         AND $also=$val
function nosql_updateSetWhereEqualsAnd($table,$prop,$new,
$searchfor,$value  ,$also,$val)
 
// DELETE FROM '$table' WHERE '$property'
//                  $comparator '$value' AND  '$prop' $comp '$val'
function nosql_deleteFromWhereAnd($table,$property,
$comparator,$value,$prop,$comp,$val)

Conceptos básicos: XML + JAVA + JDOM + SOAP + PHP

Hablemos primero un poco acerca de XML Gracias a los protocolos para conectar XML como XML-RPC,SOAP o RSS, XML sobrevivió al desastre de convertirse en un lenguaje que no aportara nada nuevo a lo existente (HTML), y que combinado con WSDL, JAVA y PHP obtenemos las herramientas más utilizadas en la red hoy en día: servicios.

XML es robusto, podemos modificar el fichero fácilmente sin que pierda su significado dramáticamente; podemos construir una estructura para moldear la forma en que se comunican nuestros servicios con los clientes y aplicaciones con diversas reglas, me gustaría que mirárais la documentación sobre XML, XML-RPC,SOAP,RSS,SAX,DOM, JDOM y WSDL que he puesto aquí (de la UGR , y también en un comprido manuales_comunicacion.rar para tenerlo en local) ya que se explican conceptos fundamentales, como el standalone de xml (para decir si la estructura del árbol documento [DOM] se construye sólo con un fichero o por medio de varios, etc.), o lo nuevo de XML que son los namespace para que dentro del nombre de la etiqueta se pueda incrustar un diccionario: <dic:alumno>…</dic:alumno>, etc.; también, indicando donde está mediante <Nombre xmlns=”url_del_diccionario_nombre”>…

Sabiendo que DTD y un esquema XSD definen de la misma forma la estructura de un XML, estos últimos XSD son los más utilizados hoy en día, porque es realmente sencillo (al menos cuando estuve construyendo zenphp me costó mucho tener reglas DTD válidas para el generador de aplicaciones php a partir de un xml) hacer dichas reglas usando XML, ya que XSD se basa en un DTD ,son los diccionarios predefenidos que se van incrustando como las muñecas rusas.

El protocolo XML funciona normalmente a través del puerto HTTP (80) y dió lugar al XML-RPC, fué más famoso que SOAP porque éste había que introducirlo mediante un conjunto de reglas propias y era pesado de hacer, actualmente existen librerías que crean los envoltorios para enviar mensajes:

XML-RPC

Ver XML-RPC en los manuales

..embebiendo tipos en parámetros y estos en valores dando forma así a las peticiones y las respuestas de los servicios.

SOAP : es ligero, tiene pocas etiquetas y casi no pesan nada, es como la evolución de XML-RPC ,al fin y al cabo, es otro envoltorio para enviar mensajes por HTTP o SMTP , (Facebook lo usa)…

WSDL: además define reglas para un servicio web…mirar la documentación propuesta anteriormente para más información…

Para empezar, veremos como conectar Java con un WSDL y obtener resultados, siguiendo los pasos:

  1. Dispondremos primero de un editor: SOAP UI ,descargar e instalar
  2. Ahora daremos con una lista de servicios de tipo WSDL, por ejemplo los servicios de DaeHosting:
    http://webservices.daehosting.com/services/
    abrimos el servicio de fechas: http://webservices.daehosting.com/services/DatesService.wso y copiamos la dirección URL de la descripción de sus servicios ,que es el fichero WSDL [un XML] que necesitamos: http://webservices.daehosting.com/services/DatesService.wso?WSDL
  3. Abrimos SOAP UI y Vamos al menú: “File -> New soapUI Project” , insertamos la URL copiada del paso anterior en “Initial WSDL/WADL” y se pondrá automáticamente el nombre a “DatesService” pero podemos ponerle el que queramos, pinchamos en “OK” y empezará a cargar los servicios que ofrece dicho WSDL. Estos aparecerán en la pestaña “Navigator” en modo árbol, seleccionamos MonthNames y desplegamos el árbol de modo que hacemos doble click sobre “Request 1” y aparecerá una ventana con el esquema XML de la petición que se realiza al servidor, las entradas se pueden identificar por el caracter “?”
  4. Vamos a pulsar en la ventana de “Request 1″ con el segundo botón del ratón->”Validate” para validar el documento y veremos que nos aparecen mensajes para que rellenemos los datos pedidos, pero antes debemos conocer qué poner en “iLanguage”, para ello, abrimos del árbol de Servicios “DateServiceSoapBinding” el “Request1” de “MainLanguages” de forma que al ejecutarlo nos aparecerá como respuesta del servidor una lista con el formato XML del WSDL del servicio con los idiomas que soporta, copiamos el valor para el español: “LANG_SPANISH” y volvemos a la ventana del “Request 1” de la Operación “MonthNames” donde ahora sí sabemos qué valor hay que poner en el tipo de dato “iLanguage”: LANG_SPANISH.  Los otros dos parámetros :  bAbbreviated y bUse13Months son booleanos, probad vosotros mismos qué diferencias hay entre poner 0 ó 1 :)
    En cualquier caso el resultado de la ejecución correcta del servicio debe de tener una pinta como esta:
  5. Acabamos de presenciar la generación de llamadas a servicios para que devuelvan el nombre de los meses en un idioma deseado, con lo que este servicio, (por ingeniería inversa) sabemos que se trata de un traductor…
  6. Combinando los servicios podemos hacer cosas realmente interesantes…probad a usar la petición de la operación MonthName para obtener el mes de Abril en Alemán por ejemplo

Ahora que sabemos como comunicar servicios con esquemas XML veamos como utilizar Java para implementar una aplicación que haga lo que nuestro querido SOAP UI hace tan fácilmente en una serie de sencillos pasos:

  1. Descargar, descomprimir y abrir el proyecto para NetBeans: Ejemplos XML para Java: aquí.
  2. Debe aparecer un problema de referencias al cargar el proyecto, para solucionarlo descargar las librerías aquí y en las propiedades del proyecto -> Librerías -> pestaña de Compilar -> quitáis las referencias rotas y añadir los ficheros JAR (que hay que descomprimir de  librerias.rar). Entonces deben desaparecer todos los errores de compilación en NetBeans…(BuildAll…)
  3. Ahora expandimos el paquete “EscribirXML.SOAP” y abrimos el fichero ClienteSOAP.java, donde vamos a reemplazar “localhost” de la línea 17 por nuestro servidor WSDL con soporte para acciones SOAP,en este caso es RFC, para mostrar que sirve para RPC también el mismo código:
    http://www.ebi.ac.uk/Tools/webservices/wsdl/WSDbfetch.wsdl
    si el tipo de Operación es SOAP en lugar de RPC, la acción SOAP la podemos leer en el editor SOAP UI en las propiedades de la Operación seleccionada
  4. Mirando el código comprender que se realiza una conexión al servidor y se envía por el método POST una petición HTTP con los parámetros establecidos (acción SOAP si se define) y se escribe en el búfer con wout.write() nuestro esquema XML, por lo tanto copiamos el WSDL del SOAP UI de la petición “Request 1” para la Operación “getSupportedDBs” (reemplazando los valores de las interrogantes como antes si es que los hay)…
  5. Para probar el ejemplo compilamos y tras hacer click con el segundo botón del ratón sobre ClienteSOAP.java  pulsamos en “Run” (Ejecutar) o bien editamos las opciones del proyecto -> run -> Main class -> “EscribirXML.SOAP.ClienteSOAP”, sin argumentos en este caso…
    El código ha de quedar así:

    package EscribirXML.SOAP;
    import java.net.*;
    import java.io.*;
     
    /**
    *
    * @author
    */
    public class ClienteSOAP {
     
    public final static String DEFAULT_SERVER
    = "http://www.ebi.ac.uk/Tools/webservices/wsdl/WSDbfetch.wsdl";
    // = "http://www.schemaweb.info/webservices/soap/SchemaWebSoap.asmx?WSDL";
    /* public final static String SOAP_ACTION
    = "http://www.schemaweb.info/webservices/methods/GetObjects";*/
     
    public static void main(String[] args) {
    String server = DEFAULT_SERVER;
    try {
    URL u = new URL(server);
    URLConnection uc = u.openConnection();
    HttpURLConnection connection = (HttpURLConnection) uc;
     
    connection.setDoOutput(true);
    connection.setDoInput(true);
    connection.setRequestMethod("POST");
    //connection.setRequestProperty("SOAPAction", SOAP_ACTION);
     
    OutputStream out = connection.getOutputStream();
    Writer wout = new OutputStreamWriter(out);
     
    wout.write(
    "<soapenv:Envelope xmlns:xsi=\""+
    "http://www.w3.org/2001/XMLSchema-instance\" "+
    "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" "+
    "xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" "+
    "xmlns:wsd=\"http://wsdbfetch.ws.jdbfetch.ebi.ac.uk\">"+
    "<soapenv:Header/>"+
    "<soapenv:Body>"+
    "<wsd:getSupportedDBs soapenv:encodingStyle=\""+
    "http://schemas.xmlsoap.org/soap/encoding/\"/>"+
    "</soapenv:Body>"+
    "</soapenv:Envelope>");
    wout.flush();
     
    wout.close();
     
    InputStream in = connection.getInputStream();
    int c;
    System.err.println( "\n\nCONTESTACION\n\n");
    while ((c = in.read()) != -1) System.out.write(c);
    in.close();
     
    }
    catch (IOException e) {
    System.err.println("HA DADO UNA EXCEPCION");
    System.err.println(e);
    }
     
    } // end main
     
    }
  6. La salida debe ser algo como:

Por último vamos a probar un ejemplo del análisis sintáctico de un fichero XML a través del uso de un ParserDOM, abriendo el paquete DOM.Parsear y dentro el fichero “ParserDOM.java” sólo hemos de pasarle la ruta por línea de comandos del fichero y observar los resultados… (ver ejemplos con SAX del mismo proyecto de NetBeans proporcionado)…

El Modelo Objeto Documento de Java además de servir de analizador sintáctico con el método parse(), proporciona interfaces para manejar ficheros como árboles de datos, se obtiene con parsed.getDocument(), si no existen excepciones se trata, en otro caso es que el documento no ha pasado la validación, encontraremos información de prefijo, etc. dentro del árbol…

« Volver al curso de Arquitectura de Servicios en Java+PHP

Embeber clases de C++ como una extensión de PHP usando Zend

Vamos a ir un poco más lejos que la última vez cuando analizábamos la gran ventaja de usar el lenguaje C++ frente a PHP, por su potencia al estar compilado para la máquina, en lugar de interpretado como PHP, sobre todo a la hora de usar algoritmos que requieren de un tiempo de ejecución mayor, a pesar de que, su orden de ejecución no es muy elevado; al cambiar de tecnología se nota demasiado.

En este caso vamos a echar mano del framework de la empresa Zend que casualmente se utiliza en Magento como base y alguna otra tienda ( soloprecios.es ) también,… este artículo de la zona de programadores de Zend Framework, nos recomienda primero echar un vistazo al manual para escribir una extensión…, en este punto, quizás , os decantéis por olvidaros de Zend y queráis echar un vistazo a la herramienta que usan en FacebookHiHop, sinceramente os recomiendo leer  los informes de las unidades de prueba realizadas por Sebastian Bergmann primero.

En el artículo de paulosman, se explica cómo configurar el makefile (para compilar C++) para que se incluya la extensión de PECL con phpize , además es tan apañao que incluye incluso una macro para hacer la llamada a la función ZEND_GET_MODULE() que necesita el framework para asociar la clase con PHP, tras realizar estos pasos podemos usar :

 php -d"extension=nombre_de_mi_extension.so" -m

para añadir la extensión recién compilada (tras usar phpize y make) a Apache u otro servidor (con Zend) ,ahora que tenemos el esqueleto básico de dicha extensión cargada en el servidor, el sistema de construcción de PHP sabe que tiene que compilar las clases C++ (definidas e implementadas fuera de la extensión) que se sincronizarán por medio de los objetos en C++ de Zend y la función externa ZEND_GET_MODULE(nombre_de_mi_extension)

¿Alguna duda?, aquí estamos…

footer
jbelon © | sitemap.xml