<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" version="2.0">

<channel>
	<title>Datasalt » Blog</title>
	
	<link>http://www.datasalt.es</link>
	<description>Big Data in the Cloud</description>
	<lastBuildDate>Tue, 30 Apr 2013 17:21:10 +0000</lastBuildDate>
	<language>es-ES</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/datasalt_es" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="datasalt_es" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Un vistazo a la API de Trident (Storm)</title>
		<link>http://www.datasalt.es/2013/04/un-vistazo-a-la-api-de-trident-storm/</link>
		<comments>http://www.datasalt.es/2013/04/un-vistazo-a-la-api-de-trident-storm/#comments</comments>
		<pubDate>Mon, 15 Apr 2013 14:38:27 +0000</pubDate>
		<dc:creator>Pere Ferrera Bertran</dc:creator>
				<category><![CDATA[Datasalt]]></category>

		<guid isPermaLink="false">http://www.datasalt.es/?p=1740</guid>
		<description><![CDATA[<p>El 10 de Abril Pere dió una &#8220;hackaton&#8221; de Trident/Storm en el Big Data Beers de Berlin. En la misma sesión hubo también una &#8220;hackaton&#8221; paralela de Disco (la dió Dave de Continuum Analytics). Es war viel spaß! La gente que fue tuvo la oportunidad de aprender lo básico de Trident en la sesión de ...</p><p>Entrada original en: <a href="http://www.datasalt.es/2013/04/un-vistazo-a-la-api-de-trident-storm/">Un vistazo a la API de Trident (Storm)</a></p>]]></description>
				<content:encoded><![CDATA[<p>El 10 de Abril Pere dió <a href="http://www.meetup.com/Big-Data-Beers/events/112226662/">una &#8220;hackaton&#8221; de Trident/Storm</a> en el <a href="http://www.meetup.com/Big-Data-Beers/">Big Data Beers</a> de Berlin. En la misma sesión hubo también una &#8220;hackaton&#8221; paralela de <a href="http://discoproject.org/">Disco</a> (la dió Dave de <a href="http://continuum.io/">Continuum Analytics</a>). <strong><em>Es war viel spaß!</em></strong> La gente que fue tuvo la oportunidad de aprender lo básico de <a href="https://github.com/nathanmarz/storm/wiki/Trident-tutorial">Trident</a> en la sesión de <a href="http://storm-project.net/">Storm</a> a la vez que lo pudo probar en el momento. En la &#8220;hackaton&#8221; se vieron los aspectos más importantes de la API, la filosofía y los casos de uso típicos de Storm e incluyó un simple ejercicio que manipulaba un flujo de tweets falsos. <strong>El proyecto, la guía de la sesión, algunos ejemplos ejecutables, así como el generador de tweets <a href="https://github.com/pereferrera/trident-hackaton/">puede encontrarse en github</a></strong>.</p>
<p><a href="http://www.datasalt.com/wp-content/uploads/2013/04/BDB4-2.jpg"><img class="aligncenter size-thumbnail wp-image-1623" alt="BDB4-2" src="http://www.datasalt.com/wp-content/uploads/2013/04/BDB4-2-150x150.jpg" width="150" height="150" /></a></p>
<p>En este post veremos<strong> un resumen de la API de Trident</strong> que podremos ir siguiendo de forma práctica con la ayuda del proyecto github anteriormente mencionado.</p>
<p><span id="more-1740"></span></p>
<h2>Storm (a modo de resumen)</h2>
<p>A modo de resumen, Storm es una herramienta para el proceso en tiempo de real de flujos de datos. Lo que lo hace diferente es que es <strong>una abstracción de más alto que nivel</strong> que el simple envío de mensajes (permite definir topologías como un grafo acíclico dirigido), tiene <strong>tolerancia a fallos para cada proceso</strong> y garantiza que cada mensaje en el sistema se va a procesar por lo menos una vez (<strong>at-least-once semantics</strong>).</p>
<p><center><img alt="Storm" src="http://storm-project.net/images/topology.png" width="200/" /></center>Un caso de uso típico es el limpiado, pre-procesado y la pre-agregación de muchos mensajes concurrentes (por ejemplo de logs, clicks, datos de sensores, etc). Una arquitectura típica de Big Data para el procesamiento en tiempo real podría ser una donde los mensajes se leen de una cola <a href="http://kafka.apache.org/">Kafka</a>, se pre-procesan y pre-agregan con Storm y se persisten a una NoSQL como Cassandra, o al HDFS para poder procesar la información con Hadoop con posterioridad.</p>
<h2>Trident (a modo de resumen)</h2>
<p>Trident es una abstracción interesante por encima de Storm. Además de proveer <strong>métodos de más alto nivel</strong> tipo los de Cascading, provée &#8220;mini-batches&#8221; de tuplas para 1) <strong>hacer más fácil el construir la lógica de procesamiento</strong> y 2) <strong>favorecer la persistencia eficiente de los datos</strong>, incluso con la ayuda de una API que puede dar seguridad total en este aspecto (&#8220;exactly-once&#8221; semantics).</p>
<p>Hay que recordar y tener en cuenta que almacenar estado en memoria en los Bolts de Storm no es totalmente tolerante a fallos: si un nodo muere, el proceso se reasignará, pero el estado no se podrá recuperar. <a href="https://github.com/nathanmarz/storm/issues/204">Hay un ticket en github</a> para ésto, pero mientrastanto lo más sensato es usar Storm para <strong>persistir cualquier estado a una base de datos</strong>, y para eso Trident es especialmente útil. Ya que si estamos manejando grandes cantidades de datos, necesitamos hacer algún tipo de encolado para no tener que actualizar la base de datos para cada uno de los mensajes que procesamos. Los &#8220;mini-batches&#8221; a los que nos hemos referido nos ayudan precisamente a ello, y Trident nos proporciona una API de agregación para ellos que nos permite persistir el resultado en cualquier base de datos.</p>
<h2>Comenzando: each()</h2>
<p>El punto de entrada de nuestro tutorial es la clase <a href="https://github.com/pereferrera/trident-hackaton/blob/master/src/main/java/com/datasalt/trident/Skeleton.java">Skeleton</a>. Aquí vemos el uso de la clase <a href="https://github.com/pereferrera/trident-hackaton/blob/master/src/main/java/com/datasalt/trident/FakeTweetsBatchSpout.java">FakeTweetsBatchSpout</a> que es el Spout que nos va a generar el stream de tweets falsos. Podemos cambiar el tamaño de cada batch por constructor. La primera operación que veremos es each(), que nos <strong>permite manipular cada tupla del batch ya sea filtrándola o aplicándole alguna función</strong>. Podemos implementar un filtro que filtre los tweets escritos por un cierto actor:</p>
<pre class="brush: java; title: ; notranslate">
public static class PerActorTweetsFilter extends BaseFilter {
  String actor;

  public PerActorTweetsFilter(String actor) {
    this.actor = actor;
  }
  @Override
  public boolean isKeep(TridentTuple tuple) {
    return tuple.getString(0).equals(actor);
  }
}
</pre>
<p>Podemos añadir el filtro previo a la definición de la topología:</p>
<pre class="brush: java; title: ; notranslate">
topology.newStream(&quot;spout&quot;, spout)
  .each(new Fields(&quot;actor&quot;, &quot;text&quot;), new PerActorTweetsFilter(&quot;dave&quot;))
  .each(new Fields(&quot;actor&quot;, &quot;text&quot;), new Utils.PrintFilter());
</pre>
<p>Observad cómo en el selector de campos (Fields) hemos seleccionado &#8220;actor&#8221; y &#8220;text&#8221;. Las tuplas que entren en cada método each() puede que tengan muchos campos, pero éste selector nos permite seleccionar sólo un subconjunto de interés. Por lo tanto la tupla que entre en el filtro será un array de dos campos con el actor en posición 0 y el texto del tweet en posición 1. También hemos añadido otro filtro que sólo imprime por pantalla cada tupla que pasa por él. El comportamiento de esta topología es bastante predecible: filtrará todo tweet que no fue escrito por &#8220;dave&#8221;.</p>
<p>Veamos ahora una función ejemplo:</p>
<pre class="brush: java; title: ; notranslate">
public static class UppercaseFunction extends BaseFunction {
  @Override
  public void execute(TridentTuple tuple, TridentCollector collector) {
    collector.emit(new Values(tuple.getString(0).toUpperCase()));
  }
}
</pre>
<p>Esta función simplemente emite toda cadena de texto en posición 0 de la tupla y la imprime en mayúsculas. Podemos añadir esta función a la definición de la topología, por ejemplo:</p>
<pre class="brush: java; title: ; notranslate">
topology.newStream(&quot;spout&quot;, spout)
  .each(new Fields(&quot;actor&quot;, &quot;text&quot;), new PerActorTweetsFilter(&quot;dave&quot;))
  .each(new Fields(&quot;text&quot;, &quot;actor&quot;), new UppercaseFunction(), new Fields(&quot;uppercased_text&quot;))
  .each(new Fields(&quot;actor&quot;, &quot;text&quot;, &quot;uppercased_text&quot;), new Utils.PrintFilter());
</pre>
<p>Veamos dos cosas. La primera es que el selector de campos correspondiente a la llamada de la función lo hemos invertido con respecto al de la llamada del primer filtro, ya que la función convertirá a mayúsculas la cadena que haya en la posición 0. La segunda cosa es que para la llamada de la función tenemos un descriptor de campos de salida. Siempre hemos de describir los campos que emite una función (en este caso, &#8220;uppercased_text&#8221;). Las tuplas que salgan de la función<strong> tendrán todos los campos de la tupla de entrada más los que hayamos emitido como resultado de la función</strong> (así que no podemos llamar a un campo de salida igual que uno de entrada). El código de arriba pasará a mayúsculas todos los tweets escritos por &#8220;dave&#8221; e imprimirá tanto el texto original como el texto en mayúsculas.</p>
<p><em>Como curiosidad, decir que cada llamada a each() nos permite hacer una &#8220;proyección&#8221; implícita de las tuplas seleccionando un subconjunto de sus campos, pero si por algún motivo necesitáramos hacer una proyección explícita podemos usar el método<strong> project()</strong>.</em></p>
<h2>Haciendo las cosas más interesantes: parallelismHint() y partitionBy()</h2>
<p>Volvamos al ejemplo del filtro simple. ¿Qué pasa si definimos la topología de la siguiente manera?</p>
<pre class="brush: java; title: ; notranslate">
topology.newStream(&quot;spout&quot;, spout)
  .each(new Fields(&quot;actor&quot;, &quot;text&quot;), new PerActorTweetsFilter(&quot;dave&quot;))
  .parallelismHit(5)
  .each(new Fields(&quot;actor&quot;, &quot;text&quot;), new Utils.PrintFilter());
</pre>
<p><strong>parallelismHint()</strong> configurará la topología hasta donde lo hayamos puesto para ser ejecutada con un cierto nivel de paralelismo. Esto no es 100% verdad, pero por ahora es una definición suficientemente buena. Para visualizar ésto mejor, podemos modificar el filtro PerActorTweetsFilter:</p>
<pre class="brush: java; title: ; notranslate">
public static class PerActorTweetsFilter extends BaseFilter {

  private int partitionIndex;
  private String actor;

  public PerActorTweetsFilter(String actor) {
    this.actor = actor;
  }
  @Override
  public void prepare(Map conf, TridentOperationContext context) {
    this.partitionIndex = context.getPartitionIndex();
  }
  @Override
  public boolean isKeep(TridentTuple tuple) {
    boolean filter = tuple.getString(0).equals(actor);
    if(filter) {
      System.err.println(&quot;I am partition [&quot; + partitionIndex + &quot;] and I have kept a tweet by: &quot; + actor);
    }
    return filter;
  }
}
</pre>
<p>Si ahora ejecutamos la topología obtendremos resultados como:</p>
<pre>I am partition [4] and I have kept a tweet by: dave
I am partition [3] and I have kept a tweet by: dave
I am partition [0] and I have kept a tweet by: dave
I am partition [2] and I have kept a tweet by: dave
I am partition [1] and I have kept a tweet by: dave</pre>
<p>Ésto nos dice claramente que el filtro está siendo ejecutado en paralelo por 5 procesos diferentes. También tenemos 5 Spouts generadores de tuplas (si buscamos la cadena &#8220;Open Spout instance&#8221; en los logs nos daremos cuenta de ello). ¿Qué pasa si sólo queremos 2 Spouts y 5 procesos de filtrado?</p>
<pre class="brush: java; title: ; notranslate">
topology.newStream(&quot;spout&quot;, spout)
  .parallelismHint(2)
  .shuffle()
  .each(new Fields(&quot;actor&quot;, &quot;text&quot;), new PerActorTweetsFilter(&quot;dave&quot;))
  .parallelismHint(5)
  .each(new Fields(&quot;actor&quot;, &quot;text&quot;), new Utils.PrintFilter());
</pre>
<p>El método <strong>shuffle()</strong> es <strong>una operación de reparticionado</strong>. Hay otras operaciones como <strong>partitionBy()</strong> o<strong> global()</strong> que también son de reparticionado. El reparticionado nos permite especificar cómo se han de enrutar las tuplas al siguiente nivel de procesamiento, así como hacer que cada nivel de procesamiento se ejecute con diferentes niveles de paralelismo. Shuffle() hace un reparticionado alteatorio mientras que partitionBy() hace un enrutado basado en &#8220;consistent hashing&#8221; sobre los campos que se han especificado. <em>Dicho ésto, ahora ya podemos clarificar la anterior definición de parallelismHint(): ésta función aplica un cierto nivel de paralelismo a todas las operaciones anteriores a donde la hemos especificado, hasta que haya una operación de reparticionado de algún tipo.</em></p>
<p>Cambiemos shuffle() por <strong>partitionBy(new Fields(&#8220;actor&#8221;))</strong>. ¿Qué creeis que pasará?</p>
<pre>I am partition [2] and I have kept a tweet by: dave
I am partition [2] and I have kept a tweet by: dave
I am partition [2] and I have kept a tweet by: dave
I am partition [2] and I have kept a tweet by: dave</pre>
<p>Como hemos usado partitionBy(new Fields(&#8220;actor&#8221;)) estamos diciendo que todas las tuplas del mismo actor tienen que ir forzosamente al mismo proceso, así que no es de extrañar que ahora sólo haya un proceso ejecutando el filtrado a pesar de que la capa de procesamiento tiene paralelismo 5.</p>
<h2>Agregación</h2>
<p>Hemos dicho antes que Trident nos permite procesar &#8220;mini-batches&#8221; de tuplas. Una operación &#8220;batch&#8221;, por lotes, que nos viene de forma natural a la cabeza es la <strong>agregación</strong>. Trident nos provée primitivas para hacer agregaciones sobre los batches. Veamos un ejemplo:</p>
<pre class="brush: java; title: ; notranslate">
public static class LocationAggregator extends BaseAggregator&lt;Map&lt;String, Integer&gt;&gt; {

  @Override
  public Map&lt;String, Integer&gt; init(Object batchId, TridentCollector collector) {
    return new HashMap&lt;String, Integer&gt;();
  }

  @Override
  public void aggregate(Map&lt;String, Integer&gt; val, TridentTuple tuple, TridentCollector collector) {
    String location = tuple.getString(0);
    val.put(location, MapUtils.getInteger(val, location, 0) + 1);
  }

  @Override
  public void complete(Map&lt;String, Integer&gt; val, TridentCollector collector) {
    collector.emit(new Values(val));
  }
}
</pre>
<p>Este agregador es muy simple: la idea es procesar cada batch de tuplas para obtener un mapa que cuente por localización. A través de este ejemplo vemos la interfaz &#8220;Aggregator&#8221;, observemos cómo Trident llamará al método init() al principio de cada batch, al método aggregate() para cada tupla dentro del batch y al método complete() al final de cada batch. Podemos usar la instancia &#8220;collector&#8221; en cualquier momento de este ciclo, pero en este ejemplo sólo lo usaríamos al final del batch por eficiencia: podríamos usar el resultado del agregador para actualizar una base de datos, por ejemplo.</p>
<p>Podemos testear ésto usando el método <strong>aggregate()</strong> de Trident. El método aggregate() <strong>es también una operación de reparticionado</strong>. Agregará todas las tuplas de un batch en un único proceso, escogido al azar. Para minimizar los datos enviados por red, y siempre que sea posible, podríamos usar la interfaz CombinerAggregator. Pero por ahora sigamos en la interfaz de más bajo nivel y probémosla:</p>
<pre class="brush: java; title: ; notranslate">
TridentTopology topology = new TridentTopology();
topology.newStream(&quot;spout&quot;, spout)
  .aggregate(new Fields(&quot;location&quot;), new LocationAggregator(), new Fields(&quot;location_counts&quot;))
  .each(new Fields(&quot;location_counts&quot;), new Utils.PrintFilter());
</pre>
<p>Obtenemos resultados como los siguientes:</p>
<pre>[{USA=3, Spain=1, UK=1}]
[{USA=3, Spain=2}]
[{France=1, USA=4}]
[{USA=4, Spain=1}]
[{USA=5}]</pre>
<p>Fijaros como la suma de las cuentas es siempre 5. Ésto es porque el tamaño de batch por defecto es de 5.</p>
<p>Pero incrementémoslo ahora a 100:</p>
<pre class="brush: java; title: ; notranslate">
FakeTweetsBatchSpout spout = new FakeTweetsBatchSpout(100);
</pre>
<p>Ahora modifiquemos un poco la topología y tratemos de adivinar lo que pasará:</p>
<pre class="brush: java; title: ; notranslate">
TridentTopology topology = new TridentTopology();
topology.newStream(&quot;spout&quot;, spout)
  .partitionBy(new Fields(&quot;location&quot;))
  .partitionAggregate(new Fields(&quot;location&quot;), new LocationAggregator(), new Fields(&quot;location_counts&quot;))
  .parallelismHint(3)
  .each(new Fields(&quot;location_counts&quot;), new Utils.PrintFilter());
</pre>
<p>Ahora obtenemos resultados como los siguientes:</p>
<pre>[{France=10, Spain=5}]
[{USA=63}]
[{UK=22}]</pre>
<p>En efecto, <strong>partitionAggregate()</strong> no es una operación de reparticionado. En vez de reparticionar, ejecuta un agregador con los datos locales de cada partición. Como hemos particionado por localización, y como tenemos 3 particiones y sólo 4 localizaciones en nuestro conjunto de datos, el particionado está asignando &#8220;France&#8221; y &#8220;Spain&#8221; a una partición, &#8220;USA&#8221; a otra y &#8220;UK&#8221; a otra.</p>
<p>Todo ésto es un poco complicado de enteder a primera vista, pero este tipo de experimentos son los que hacen que de verdad dominemos y entendamos una herramienta, así que hay que tener paciencia. Lo que veremos a continuación es bastante más intuitivo.</p>
<h2>groupBy</h2>
<p>El siguiente código nos parecerá bastante intuitivo:</p>
<pre class="brush: java; title: ; notranslate">
topology.newStream(&quot;spout&quot;, spout)
  .groupBy(new Fields(&quot;location&quot;))
  .aggregate(new Fields(&quot;location&quot;), new Count(), new Fields(&quot;count&quot;))
  .each(new Fields(&quot;location&quot;, &quot;count&quot;), new Utils.PrintFilter());
</pre>
<p>Pero, ¿Qué hace ésto, en realidad?</p>
<pre>...
[France, 25]
[UK, 2]
[USA, 25]
[Spain, 44]
[France, 26]
[UK, 3]
...</pre>
<p>Este código nos produce cuentas para cada localización independiente, sin haber especificado paralelismo de ningún tipo. De hecho, estamos usando un agregador muy sencillo (Count()), que simplemente cuenta el número de tuplas.<strong> groupBy()</strong> lo que hace es crear un flujo de datos agrupado lógicamente por algunos campos. Esta agrupación lógica modifica el comportamiento de las operaciones aggregate(). En vez de agregar todas las tuplas de un batch, que es lo que conocíamos, ahora se nos agrega sólo las tuplas que pertenecen a cada uno de los grupos lógicos, de forma independiente. Así que es como si tuviésemos tantos flujos como grupos diferentes hay, si es que pensarlo así ayuda.</p>
<p>Tengamos en cuenta, por tanto, que groupBy() <strong>en sí mismo no es una operación de reparticionado</strong>. groupBy() seguido de aggregate() sí lo es, pero groupBy() seguido de partitionAggregate() no. Como deberes, pensad en ello y experimentad con todo ésto.</p>
<h2>Conclusión</h2>
<p>Hasta aquí hemos visto unas cuantas primitivas fundamentales de Trident. Hay bastantes más cosas de las que no hemos hablado todavía, como la API de estado. Sin embargo, esperamos que los conceptos se hayan introducido de forma clara y eficiente.</p>
<p>Podéis jugar con <a href="https://github.com/pereferrera/trident-hackaton/">el proyecto de github</a> e implementar varios ejemplos como:</p>
<ul>
<li>Cuentas por cada hashtag.</li>
<li>Los últimos tres tweets para cada actor.</li>
<li>Las palabras más usadas para cada actor.</li>
<li>Las palabras más usadas, en general.</li>
<li>Los hashtags populares en una cierta ventana temporal.</li>
</ul>
<p>Algunos de éstos ejemplos involucran guardar estado de algún tipo. La <a href="https://github.com/nathanmarz/storm/wiki/Trident-state">API de estado de Trident</a> es una opción para ello (quizás hablamos de ésto en otro post). Otra opción sería simplemente conectar con una base de datos en un agregador o función. Y otra opción sería mantener estado en memoria en los mismos procesos, pero teniendo en cuenta que ésta última opción no es verdaderamente tolerante a fallos y que no la aconsejamos para ninguna aplicación seria.</p>
<p>Entrada original en: <a href="http://www.datasalt.es/2013/04/un-vistazo-a-la-api-de-trident-storm/">Un vistazo a la API de Trident (Storm)</a></p>]]></content:encoded>
			<wfw:commentRss>http://www.datasalt.es/2013/04/un-vistazo-a-la-api-de-trident-storm/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Presentando Splout Cloud: Un servicio de consultas SQL de baja latencia en la nube.</title>
		<link>http://www.datasalt.es/2013/04/presentando-splout-cloud/</link>
		<comments>http://www.datasalt.es/2013/04/presentando-splout-cloud/#comments</comments>
		<pubDate>Fri, 05 Apr 2013 14:56:50 +0000</pubDate>
		<dc:creator>Pere Ferrera Bertran</dc:creator>
				<category><![CDATA[Datasalt]]></category>

		<guid isPermaLink="false">http://www.datasalt.es/?p=1734</guid>
		<description><![CDATA[<p>Hemos creado Splout Cloud, un servicio en la nube de baja latencia que corre sobre Amazon AWS. A modo de resumen, Splout Cloud permite convertir cualquier conjunto de ficheros &#8211; independientemente de su tamaño &#8211; en una base de datos escalable y particionada SQL. Al contrario que otros sistemas para analítica &#8220;offline&#8221;, ofrece un alto ...</p><p>Entrada original en: <a href="http://www.datasalt.es/2013/04/presentando-splout-cloud/">Presentando Splout Cloud: Un servicio de consultas SQL de baja latencia en la nube.</a></p>]]></description>
				<content:encoded><![CDATA[<p>Hemos creado <a href="http://sploutcloud.com/">Splout Cloud</a>, un servicio en la nube de baja latencia que corre sobre Amazon AWS. A modo de resumen, Splout Cloud permite convertir cualquier conjunto de ficheros &#8211; independientemente de su tamaño &#8211; en una base de datos escalable y particionada SQL. Al contrario que otros sistemas para analítica &#8220;offline&#8221;, ofrece un alto rendimiento y es suficientemente rápido como para poder proveer queries por debajo del segundo con agregaciones en tiempo real, y ser así el motor de cualquier aplicación web o móvil.</p>
<p><a href="http://www.datasalt.com/products/sploutcloud-logo/" rel="attachment wp-att-1542"><img class="aligncenter size-full wp-image-1542" alt="sploutcloud-logo" src="http://www.datasalt.com/wp-content/uploads/2012/04/sploutcloud-logo.png" width="460" height="260" /></a></p>
<p>Splout Cloud está basado en <a href="http://sploutsql.com/">Splout SQL</a>, una base de datos SQL libre para Hadoop.</p>
<p><span id="more-1734"></span></p>
<h2>Motivación</h2>
<p>El Big Data está presente en mucho sitios, pero sobretodo lo encontramos en forma de grandes ficheros de datos que se recolectan y se guardan en cualquier lugar. Es un gran reto poder hacer toda ésta información consultable, y sobretodo que las consultas se ejecuten realmente rápido. La solución típica conlleva volcar todos los datos a una base de datos. Pero hay muchos tipos de bases de datos, ¿Cuál deberíamos elegir? ¿Quién se va a ocupar del mantenimiento de la base de datos? ¿Y cómo serán los procesos de ETL que muevan los datos y los actualicen?</p>
<p>¿No sería maravilloso que nuestros ficheros simplemente se volvieran consultables? Splout Cloud te permite dejar todos tus datos en un bucket S3 y éstos datos son sincronizados periódicamente con un sistema escalable de consultas basado en Splout SQL.</p>
<p><a href="http://www.datasalt.com/2013/04/presenting-splout-cloud-a-managed-web-latency-sql-querying-engine-in-the-cloud/files-to-database/" rel="attachment wp-att-1604"><img class="aligncenter size-full wp-image-1604" alt="files-to-database" src="http://www.datasalt.com/wp-content/uploads/2013/04/files-to-database.png" width="250" height="122" /></a></p>
<h2>Cómo funciona</h2>
<p>Así es como Splout Cloud funciona:</p>
<ul>
<li>El usuario sincroniza sus datos con un bucket S3. Por ejemplo, subiendo ficheros nuevos cada día.</li>
<li>Un clúster Splout Cloud se instancia dentro de la cuenta AWS del usuario. Dependiendo de la aplicación y de las necesidades, se ajusta el tamaño del clúster.</li>
<li>Se define una política de particionado. Por ejemplo, particionar las ventas de los clientes por ID de cliente.</li>
<li>Splout Cloud sincroniza transparentemente el bucket S3 periódicamente. El usuario puede consultar el clúster a través de una interfaz REST y construir sus propias aplicaciones por encima.</li>
</ul>
<p>Splout Cloud no es adecuado para actualizaciones de los datos en tiempo real (cada pocos segundos). Splout Cloud se orienta a aplicaciones con grandes volúmenes de datos donde actualizar los datos unas cuantas veces al día es suficiente.</p>
<h2>¡Aplica para la beta!</h2>
<p>Animamos a cualquiera a que pruebe Splout Cloud con su caso de uso. Para eso puedes <a href="http://sploutcloud.com/">aplicar para la beta</a>. Si tu conjunto de datos está por debajo de los 100GB podrás probar el servicio de forma gratuita.</p>
<p>Entrada original en: <a href="http://www.datasalt.es/2013/04/presentando-splout-cloud/">Presentando Splout Cloud: Un servicio de consultas SQL de baja latencia en la nube.</a></p>]]></content:encoded>
			<wfw:commentRss>http://www.datasalt.es/2013/04/presentando-splout-cloud/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Pig + Splout SQL para un sistema de cupones promocionales: Un romance Big Data</title>
		<link>http://www.datasalt.es/2013/04/pig-splout-sql-para-un-sistema-de-cupones-promocionales-un-romance-big-data/</link>
		<comments>http://www.datasalt.es/2013/04/pig-splout-sql-para-un-sistema-de-cupones-promocionales-un-romance-big-data/#comments</comments>
		<pubDate>Thu, 04 Apr 2013 15:26:12 +0000</pubDate>
		<dc:creator>Pere Ferrera Bertran</dc:creator>
				<category><![CDATA[Datasalt]]></category>

		<guid isPermaLink="false">http://www.datasalt.es/?p=1723</guid>
		<description><![CDATA[<p>(Éste es el último post de una serie de tres posts presentando la integración nativa de Splout SQL 0.2.2 con las principales herramientas de procesamiento por encima de Hadoop: Cascading, Hive y Pig). En este post presentaremos un caso de uso Big Data para una gran tienda de alimentos. Haremos un sumario de las compras ...</p><p>Entrada original en: <a href="http://www.datasalt.es/2013/04/pig-splout-sql-para-un-sistema-de-cupones-promocionales-un-romance-big-data/">Pig + Splout SQL para un sistema de cupones promocionales: Un romance Big Data</a></p>]]></description>
				<content:encoded><![CDATA[<p><em>(Éste es el último post de una serie de tres posts presentando la integración nativa de Splout SQL 0.2.2 con las principales herramientas de procesamiento por encima de Hadoop: <a href="http://www.datasalt.es/2013/03/1671/">Cascading</a>, <a href="http://www.datasalt.es/2013/03/hive-splout-sql-para-social-media-reporting-un-romance-big-data/">Hive</a> y Pig).</em></p>
<p>En este post presentaremos un caso de uso Big Data para <strong>una gran tienda de alimentos</strong>. Haremos un sumario de las compras individuales de cada cliente usando <strong><a href="http://pig.apache.org/">Apache Pig</a></strong> y volcaremos éste análisis a <strong><a href="http://sploutsql.com/">Splout SQL</a></strong> para poder ser capaces de lanzar consultas en tiempo real sobre él. Así, podremos combinar la información histórica de cada cliente con una lista de productos a promocionar para poder<strong> sugerir descuentos personalizados</strong>. Esta información se podría usar fácilmente por un sistema de impresión de cupones<strong> para fidelización de los clientes</strong>.</p>
<p>Combinar una herramienta de desarollo ágil Big Data como Pig con un sistema de consultas flexible y de baja latencia como Splout SQL nos provée una solución simple y efectiva a éste problema, que podremos simular a través de este post apenas sin esfuerzo.</p>
<p><span id="more-1723"></span></p>
<h2>Requerimientos</h2>
<p>Para poder seguir las instrucciones de éste post necesitamos:</p>
<ul>
<li>Tener <strong>Hadoop</strong> y <strong>Apache Pig</strong> instalados. Hemos probado éste ejemplo con Hadoop CDH3 y Pig 0.9.2.</li>
<li>Tener <strong>Python</strong> instalado. Los scripts de generación de datos están escritos en Python.</li>
<li>Descargar el <strong>JAR pangool-core</strong> versión 0.6.2 o superior. Este JAR puede ser descargado desde <a href="http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22pangool-core%22">Maven central</a>. Lo usaremos en Pig para llamar a una &#8220;StoreFunc&#8221; propia.</li>
<li>Tener<strong> Splout SQL</strong> versión 0.2.2 o superior. Para usar Splout SQL sólo es necesario descargarse la última release, descomprimirla y arrancar los servicios QNode y DNode. Se puede encontrar más información en &#8220;<a href="http://sploutsql.com/gettingstarted.html">Getting started</a>&#8220;, en la página oficial.</li>
</ul>
<h2>Preparando los datos de entrada</h2>
<p>Habrá dos ficheros como datos de entrada:</p>
<ul>
<li>Una lista de productos a promocionar. Hay que ofrecer descuentos de éstos productos a los clientes.</li>
<li>La base de datos histórica de los pagos de los clientes en la tienda. Ésta es la parte &#8220;Big Data&#8221; del sistema. Para un &#8220;retail&#8221; grande, ésta base de datos puede ser enorme. Nosotros generaremos sólo unos cuantos pagos ejemplo.</li>
</ul>
<p>Para generar los datos de entrada usaremos la herramienta retail_data_generator que hemos creado para éste post. Este archivo contiene dos scripts python y un fichero JSON. El fichero JSON describe las categorías y sub-categorías que se venden en la tienda. Los scripts python generan cada uno de los ficheros de entrada. Tras descomprimir el archivo, podemos ejecutar los siguientes comandos:</p>
<pre>python gen_prod_list.py &gt; promotional_products.txt
python gen_tickets.py &gt; tickets_sample.txt</pre>
<p>(Se pueden cambiar los parámetros de generación de cada uno de los scripts modificando las variables internas. Los valores por defecto deberían ser suficientemente ilustrativos.)</p>
<p>Podemos ahora subir los ficheros generados al HDFS de Hadoop:</p>
<pre>hadoop fs -put promotional_products.txt promotional_products.txt
hadoop fs -put tickets_sample.txt tickets_sample.txt</pre>
<h2>Sumarización de las compras de los clientes en Pig</h2>
<p>Como ejemplo sencillo, calcularemos el sumario de todas las compras de cada cliente para poder obtener las categorías de alimentos que más compra cada uno. Obtendremos el &#8220;top categorías&#8221; y el &#8220;top sub-categorías&#8221;, ya que ambas dimensiones nos permitirán entender mejor el comportamiento de cada cliente. El código en Pig Latin para el sumario es el siguiente:</p>
<pre>a = LOAD 'tickets_sample.txt' USING PigStorage('\t') AS (date, client_id, category, sub_category);
b = GROUP a BY (client_id, sub_category);
c = FOREACH b GENERATE FLATTEN(group) AS (client_id, sub_category), COUNT(a) AS count;
d = FOREACH c GENERATE (chararray)client_id, (chararray)sub_category, count;
top_subcategories = ORDER d BY client_id, count DESC;

e = GROUP a BY (client_id, category);
f = FOREACH e GENERATE FLATTEN(group) AS (client_id, category), COUNT(a) AS count;
g = FOREACH f GENERATE (chararray)client_id, (chararray)category, count;
top_categories = ORDER g BY client_id, count DESC;</pre>
<p>Podemos ahora usar el comando útil &#8220;illustrate&#8221; de Pig para ver si lo que hemos introducido es realmente lo que queremos o no. El comando ILLUSTRATE muestrea el conjunto de datos de entrada y aplica el &#8220;flow&#8221; rápidamente sobre los datos muestreados:</p>
<pre>ILLUSTRATE top_categories;
ILLUSTRATE top_subcategories;</pre>
<p>Finalmente, para ejecutar el &#8220;flow&#8221; de verdad, podemos usar el comando STORE, y para eso tenemos que cargar antes el JAR pangool-core (sustituyendo la ruta como sea necesario):</p>
<pre>REGISTER /home/.../pangool/pangool-core-0.60.2.jar;</pre>
<p>Los comandos STORE:</p>
<pre>STORE top_subcategories INTO 'retail_top_subcategories' USING com.datasalt.pangool.pig.PangoolStoreFunc('retail_top_subcategories', 'client_id', 'sub_category', 'count');
STORE top_categories INTO 'retail_top_categories' USING com.datasalt.pangool.pig.PangoolStoreFunc('retail_top_categories', 'client_id', 'category', 'count');</pre>
<p>Hemos usado una función Pangool propia llamada &#8220;PangoolStoreFunc&#8221;. Esta función nos permite guardar el output de un proceso Pig en un fichero binario que tiene un esquema definido. Este fichero puede ser entonces procesado fácilmente por Splout SQL sin necesidad de redefinir su schema. El primer argumento de esta función es el nombre de la tabla, y los siguientes argumentos son el nombre de cada columna. Las tablas SQL de Splout se llamarán igual.</p>
<h2>Desplegando el análisis a Splout SQL</h2>
<p>Ahora que ya hemos ejecutado el sumario de cada cliente, podemos desplegar las tablas resultantes junto con los productos a promocionar a Splout SQL. De esta manera, podremos ejecutar queries SQL sobre las tres tablas en tiempo real. Para ello crearemos un descriptor JSON en el directorio donde hemos instalado Splout SQL llamado <strong>&#8220;retail_tablespace.json&#8221;</strong>:</p>
<pre>{
        "name": "retail_example",
        "nPartitions": 2,
        "partitionedTables": [{
                "name": "retail_top_categories",
                "partitionFields": "client_id",
                "tableInputs": [{
                        "inputType": "TUPLE",
                        "paths": [ "retail_top_categories" ]
                }]
         },{
                "name": "retail_top_subcategories",
                "partitionFields": "client_id",
                "tableInputs": [{
                        "inputType": "TUPLE",
                        "paths": [ "retail_top_subcategories" ]
                }]
        }],
        "replicateAllTables": [{
                "name": "promotional_products",
                "schema": "category:string, sub_category:string, product:string",
                "tableInputs": [{
                        "paths": [ "promotional_products.txt" ]
                }]
        }]
}</pre>
<p>Hemos especificado <strong>dos tablas a ser particionadas</strong> (retail_top_categories, retail_top_subcategories) y <strong>una para ser replicada en cada partición</strong> (promotional_products). Las primeras dos tablas vienen de Pig y son potencialmente Big Data. Splout SQL usa particionamiento de datos para poder escalar, así que necesitamos definir una estrategia de particionamiento. Como sólo estamos interesados en consultas concretas sobre cada cliente, podemos <strong>particionar fácilmente por &#8220;client_id&#8221;</strong>. Aquí hemos fijado dos particiones, pero para poder escalar en un clúster real tendríamos que incrementar este número. Por otro lado, la tercera tabla es un fichero relativamente pequeño que puede replicarse en cada partición, y así podemos ejecutar joins para cada cliente con ella.</p>
<p>Las tablas que exportamos de Pig se importan con el tipo &#8220;TUPLE&#8221;, dado que las hemos guardado en formato binario Pangool. Para la tercera tabla hemos omitido algunos valores por defecto. El tipo por defecto es &#8220;TEXT&#8221; y se importa usando tabulación como separador, que es exactamente lo que queríamos para este caso.</p>
<p>Ahora podemos invocar los comandos apropiados de generación y despliegue en Splout SQL:</p>
<pre>hadoop jar splout-*-hadoop.jar generate -tf file:///`pwd`/retail_tablespace.json -o out-retail-example
hadoop jar splout-hadoop-*-hadoop.jar deploy -root out-retail-example -ts retail_example -q http://localhost:4412</pre>
<p>El primer comando crea los ficheros binarios SQLite que después serán desplegados a Splout SQL a través del segundo comando.</p>
<h2>Implementando el sistema de generación de cupones</h2>
<p>Para ofrecer cupones a los clientes podemos ejecutar un join como el siguiente:</p>
<pre class="brush: sql; title: ; notranslate">
SELECT product FROM promotional_products, retail_top_categories WHERE client_id = 0 AND retail_top_categories.category = promotional_products.category ORDER BY count DESC LIMIT 5;
</pre>
<p>Esta query seleccionará 5 productos de la lista de productos promocionales basados en las compras históricas del cliente. El join está basado en la categoría del producto, pero podríamos haber usado también la sub-categoría:</p>
<pre class="brush: sql; title: ; notranslate">
SELECT product FROM promotional_products, retail_top_subcategories WHERE client_id = 0 AND retail_top_subcategories.sub_category = promotional_products.sub_category ORDER BY count DESC LIMIT 5;
</pre>
<p>Generalmente, ambas queries devolverán resultados diferentes. Ver el consumo histórico de un cliente basado en la categoría de los alimentos que consume o en la sub-categoría nos ofrece diferentes puntos de vista. Podemos probar ambas queries SQL en la webapp de administración de Splout (en localhost:4412).</p>
<p>En el siguiente HTML adjunto hemos implementado una herramienta ilustrativa simple Javascript que imprime cupones haciendo queries a Splout SQL.</p>
<p><a href="http://www.datasalt.com/2013/04/pig-splout-sql-for-a-food-retail-coupons-generator-a-big-data-love-story/screenshot/" rel="attachment wp-att-1593"><img class="aligncenter size-full wp-image-1593" alt="Screenshot" src="http://www.datasalt.com/wp-content/uploads/2013/04/Screenshot.png" width="525" height="739" /></a></p>
<h2>Conclusión</h2>
<p>Combinando Pig con Splout SQL hemos podido implementar un sistema <strong>simple de generación de cupones casi sin esfuerzo</strong>. Este sistema puede <strong>escalar a grandes cantidades de datos de entrada</strong>. Para muchísimo clientes comprando productos durante largos periodos de tiempo podemos analizar nuestros datos de forma escalable usando Hadoop (Pig) y además ser capaces de consultar este análisis en tiempo real con Splout SQL. El ejemplo que hemos implementado es muy sencillo, pero no es difícil imaginar variantes más complejas como la implementación de aplicaciones móviles para los clientes que les permitan consultar el consumo histórico y la evolución en el tiempo de su consumo.</p>
<p>Entrada original en: <a href="http://www.datasalt.es/2013/04/pig-splout-sql-para-un-sistema-de-cupones-promocionales-un-romance-big-data/">Pig + Splout SQL para un sistema de cupones promocionales: Un romance Big Data</a></p>]]></content:encoded>
			<wfw:commentRss>http://www.datasalt.es/2013/04/pig-splout-sql-para-un-sistema-de-cupones-promocionales-un-romance-big-data/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hive + Splout SQL para analítica sobre Twitter: Un romance Big Data</title>
		<link>http://www.datasalt.es/2013/03/hive-splout-sql-para-social-media-reporting-un-romance-big-data/</link>
		<comments>http://www.datasalt.es/2013/03/hive-splout-sql-para-social-media-reporting-un-romance-big-data/#comments</comments>
		<pubDate>Mon, 18 Mar 2013 18:54:41 +0000</pubDate>
		<dc:creator>Pere Ferrera Bertran</dc:creator>
				<category><![CDATA[Datasalt]]></category>

		<guid isPermaLink="false">http://www.datasalt.es/?p=1683</guid>
		<description><![CDATA[<p>(Éste es el segundo post de una serie de tres posts presentando la integración nativa de Splout SQL 0.2.2 con Cascading, Hive y Pig). En éste post presentaremos un ejemplo de aplicación Big Data para analizar tweets y mostrar informes consolidados, estadísticas relevantes a usuarios de Twitter a través de una webapp interactiva de baja ...</p><p>Entrada original en: <a href="http://www.datasalt.es/2013/03/hive-splout-sql-para-social-media-reporting-un-romance-big-data/">Hive + Splout SQL para analítica sobre Twitter: Un romance Big Data</a></p>]]></description>
				<content:encoded><![CDATA[<p><em>(Éste es el segundo post de una serie de tres posts presentando la integración nativa de Splout SQL 0.2.2 con Cascading, Hive y Pig).</em></p>
<p>En éste post presentaremos un ejemplo de aplicación Big Data para <strong>analizar tweets</strong> y mostrar informes consolidados, estadísticas relevantes a usuarios de Twitter a través de una <strong>webapp interactiva</strong> de baja latencia. Para eso juntaremos <a href="http://hive.apache.org/"><strong>Hive</strong></a> (una solución open-source de &#8220;warehousing&#8221; que permite procesos analíticos fáciles sobre Hadoop) con<a href="http://sploutsql.com/"><strong> Splout SQL</strong></a>, una base de datos SQL particionada de baja latencia para Hadoop. Construiremos un simple aunque potente y escalable panel tipo el de &#8220;<a href="http://www.tweetarchivist.com/">Tweet archivist</a>&#8221; y lo haremos <strong>sin escribir ni una sola línea de código</strong>. La herramienta proveerá menciones históricas, hashtags y tweets populares para cada actor en el dataset de entrada analizado.</p>
<p><span id="more-1683"></span></p>
<h2>Los datos de Twitter</h2>
<p><center><img alt="" src="https://abs.twimg.com/a/1363070662/images/resources/twitter-bird-callout.png" /></center>Los datos de Twitter son hoy en día un ejemplo representativo y de moda de Big Data. Hay varias compañías analizándolos y extrayendo significado de ellos: desde sitios de reputación social como <a href="http://klout.com/home">Klout</a> o <a href="http://www.peerindex.com/?two=1">PeerIndex</a> hasta sitios de analítica social como <a href="http://topsy.com/">Topsy</a> o Sprinkl. Algunos de ellos como <a href="http://gnip.com/">Gnip</a> y <a href="http://datasift.com/">DataSift</a> tienen acceso a todos los tweets (lo que se conoce como la &#8220;Twitter firehouse&#8221;) y pueden revenderlos.</p>
<p>Construir herramientas que sean capaces de<strong> analizar tal cantidad de datos es todo un reto</strong>. En este post enseñaremos cómo usar una herramienta de <strong>procesamiento escalable</strong> (Hive) y una <strong>base de datos escalable de baja latencia</strong> (Splout SQL), y veremos<strong> lo bien que se integran la una con la otra</strong>.</p>
<h2>Requerimientos</h2>
<p>Para poder seguir de forma práctica este post necesitaremos:</p>
<ul>
<li>Tener <strong>Hadoop</strong> y <strong>Hive</strong> instalados. Lo hemos probado con Hadoop CDH3 y Hive 0.10.0.</li>
<li>Tener &#8220;<strong>hive-site.xml</strong>&#8221; definido y el directorio conf/ de Hive añadido al CLASSPATH / HADOOP_CLASSPATH. &#8220;hive-default.xml&#8221; está deprecated y puede no funcionar bien.</li>
<li>Tener <strong>Splout SQL</strong>. Para usar Splout SQL sólo tenemos que descargar la última distribución, descomprimirla y arrancar los servicios QNode y DNode. Se puede encontrar más información al respecto en &#8220;<a href="http://sploutsql.com/gettingstarted.html">Getting started</a>&#8221; en la web oficial.</li>
</ul>
<h2>Preparando el conjunto de datos de entrada (tweets)</h2>
<p>Podemos descargar algunos tweets de ejemplo de la API REST de Twitter usando &#8220;<strong>curl</strong>&#8220;. Usaremos algunas cuentas populares como &#8220;BBCNews&#8221; o &#8220;Reuters&#8221;. Tenemos que convertir el array de tweets que Twitter nos devuelve en un tweet independiente por línea, y para eso usaremos &#8220;<strong>sed</strong>&#8220;:</p>
<pre>mkdir temp
cd temp
curl "http://api.twitter.com/1/statuses/user_timeline.json?screen_name=TechCrunch&amp;count=200" | sed "s/},{/}\n{/g" &gt; techcrunch_tweets.json
curl "http://api.twitter.com/1/statuses/user_timeline.json?screen_name=reuters&amp;count=200" | sed "s/},{/}\n{/g" &gt; reuters_tweets.json
curl "http://api.twitter.com/1/statuses/user_timeline.json?screen_name=BBCNews&amp;count=200" | sed "s/},{/}\n{/g" &gt; bbcnews_tweets.json
curl "http://api.twitter.com/1/statuses/user_timeline.json?screen_name=barackobama&amp;count=200" | sed "s/},{/}\n{/g" &gt; barackobama_tweets.json
curl "http://api.twitter.com/1/statuses/user_timeline.json?screen_name=ladygaga&amp;count=200" | sed "s/},{/}\n{/g" &gt; ladygaga_tweets.json</pre>
<p>Vamos a usar Hadoop con Hive, así que necesitamos tener ambas cosas instaladas. Una vez tenemos Hadoop funcionando, podemos crear un directorio en el HDFS y subir todos los ficheros JSON que nos hemos descargado:</p>
<pre>hadoop fs -mkdir tweets
hadoop fs -put *.json tweets/</pre>
<p>Finalmente, abrimos Hive y creamos una tabla externa apuntando a éste &#8220;contenedor de tweets&#8221; (con cuidado de sustituir &#8220;myuser&#8221; por el usuario que sea):</p>
<pre class="brush: sql; title: ; notranslate">
  CREATE EXTERNAL TABLE tweets
    (jsonData STRING)
  ROW FORMAT DELIMITED FIELDS
    TERMINATED BY '\n'
    LOCATION '/user/myuser/tweets';
</pre>
<h2>JSON + Hive</h2>
<p><center><img alt="" src="http://www.h-online.com/imgs/43/5/9/1/1/7/7/hive_logo200-16422e15407f1988.png" width="200" /></center>Hay varias maneras de usar datos JSON en Hive. La que vamos a usar aquí es la más flexible: simplemente creamos una tabla con una única columna (jsonData) y navegamos los JSON bajo demanda dependiendo del tipo de query que queramos ejecutar. Para hacerlo usaremos la función nativa de Hive <strong>json_tuple</strong>. Pero antes que nada, tenemos que añadir el JAR contrib al classpath (con cuidado de sustituír  %HIVE_HOME% y %HIVE_VERSION% por lo que toque):</p>
<pre class="brush: sql; title: ; notranslate">
ADD JAR %HIVE_HOME%/lib/hive-contrib-%HIVE_VERSION%.jar;
</pre>
<p>La siguiente query parseará el campo &#8220;text&#8221; en cada JSON::</p>
<pre class="brush: sql; title: ; notranslate">
  SELECT
    a.text
  FROM tweets
    LATERAL VIEW json_tuple(tweets.jsonData, 'text') a AS text;
</pre>
<p>La siguiente query extrae la primera mención de cada tweet que tenga menciones:</p>
<pre class="brush: sql; title: ; notranslate">
  SELECT
    regexp_extract(a.text, &quot;(@[^ ]*)&quot;, 1)
  FROM tweets
    LATERAL VIEW json_tuple(tweets.jsonData, 'text') a AS text;
</pre>
<h2>Creando vistas con Hive</h2>
<p>Crearemos tres vistas: la de menciones, la de retweets y la de hashtags. En la de menciones tendremos <strong>toda interacción entre dos usuarios de Twitter</strong> y la fecha en que ocurrió esa interacción. En la de retweets tendremos <strong>todos los tweets populares</strong> (&#8220;retweet_count&#8221; &gt; 0) y en la de hashtags <strong>el número de veces que cada usuario usa un cierto hashtag</strong>. Crear todas estás vistas es tan fácil como ejecutar una query Hive para cada una de ellas.</p>
<p>La vista de menciones puede ser creada con la siguiente query:</p>
<pre class="brush: sql; title: ; notranslate">
  CREATE TABLE mentions AS
    SELECT
      foo.screenname as mentioner,
      substr(wordTable.word, 2) as mentioned,
      to_date(from_unixtime(unix_timestamp(substr(foo.ttime, 5), 'MMM dd hh:mm:ss ZZZZZ yyyy'))) as daydate
    FROM (
      SELECT
        c.screenname,
        a.ttime,
        split(a.text, '[^a-zA-Z_0-9@#]') AS wordarray
      FROM tweets
        LATERAL VIEW json_tuple(jsonData, 'created_at', 'text') a AS ttime, text
        LATERAL VIEW json_tuple(jsonData, 'user') b AS user
        LATERAL VIEW json_tuple(b.user, 'screen_name') c AS screenname
      ) foo
      LATERAL VIEW explode(foo.wordarray) wordTable AS word
    WHERE wordTable.word LIKE '@%';
</pre>
<p>Si hacemos una query tipo SELECT &#8230; LIMIT 10 veremos cómo es la tabla creada:</p>
<table>
<tbody>
<tr>
<th>Mentioner</th>
<th>Mentioned</th>
<th>Daydate</th>
</tr>
<tr>
<td>BarackObama</td>
<td>OFA</td>
<td>2013-03-13</td>
</tr>
<tr>
<td>BarackObama</td>
<td>FLOTUS</td>
<td>2013-03-13</td>
</tr>
<tr>
<td>BarackObama</td>
<td>PressSec</td>
<td>2013-03-12</td>
</tr>
</tbody>
</table>
<p>Tenemos un &#8220;mentioner&#8221; que mencionó a alguien (&#8220;mentioned&#8221;) y la fecha en que la mención sucedió.</p>
<p>La tabla de retweets es muy simple de generar y puede ser creada con la siguiente query:</p>
<pre class="brush: sql; title: ; notranslate">
CREATE TABLE retweets AS
  SELECT
    c.screenname as user,
    a.text as tweet,
    to_date(from_unixtime(unix_timestamp(substr(a.time, 5), 'MMM dd hh:mm:ss ZZZZZ yyyy'))) as daydate,
    a.retweetcount as retweetcount
  FROM tweets
    LATERAL VIEW json_tuple(jsonData, 'created_at', 'text', 'retweet_count') a AS time, text, retweetcount
    LATERAL VIEW json_tuple(jsonData, 'user') b AS user
    LATERAL VIEW json_tuple(b.user, 'screen_name') c AS screenname
  WHERE a.retweetcount &gt; 0;
</pre>
<p>Esta tabla tiene un usuario (&#8220;user&#8221;, el autor del tweet), el texto del tweet (&#8220;text&#8221;), la fecha en fue posteado y el número de veces que fue retwiteado:</p>
<table>
<tbody>
<tr>
<th>User</th>
<th>Tweet</th>
<th>Daydate</th>
<th>Retweetcount</th>
</tr>
<tr>
<td>BarackObama</td>
<td>Follow @OFA today for live updates from the founders&#8217; summit of Organizing for Action.</td>
<td>2013-03-13</td>
<td>194</td>
</tr>
<tr>
<td>BarackObama</td>
<td>Obama needs your help to pass the policies Americans voted for last fall. Say you&#8217;re in: &#8230;</td>
<td>2013-03-13</td>
<td>508</td>
</tr>
</tbody>
</table>
<p>Por último, la tabla de hashtags:</p>
<pre class="brush: sql; title: ; notranslate">
CREATE TABLE tophashtags AS
  SELECT
    foo2.screenname AS user,
    foo2.word AS word,
    COUNT(*) as count
  FROM (
    SELECT
      foo.screenname as screenname,
      wordTable.word as word FROM (
        SELECT
          c.screenname,
          a.time,
          split(a.text, &quot;[^a-zA-Z_0-9@#]+&quot;) AS wordarray
        FROM tweets
          LATERAL VIEW json_tuple(jsonData, 'created_at', 'text') a AS time, text
          LATERAL VIEW json_tuple(jsonData, 'user') b AS user
          LATERAL VIEW json_tuple(b.user, 'screen_name') c AS screenname
      ) foo
      LATERAL VIEW explode(foo.wordarray) wordTable AS word
    WHERE wordTable.word LIKE '#%'
  ) foo2
  GROUP BY foo2.screenname, foo2.word;
</pre>
<p>Ésta tabla simplemente tiene el usuario, el hashtag usado y el número de veces que éste usuario usó éste hashtag.</p>
<table>
<tbody>
<tr>
<th>User</th>
<th>Word</th>
<th>Count</th>
</tr>
<tr>
<td>BarackObama</td>
<td>#WeDemandAVote</td>
<td>29</td>
</tr>
<tr>
<td>BarackObama</td>
<td>#JobsNotCuts</td>
<td>28</td>
</tr>
</tbody>
</table>
<h2>Volcando vistas Hive a Splout SQL</h2>
<p>De nada sirve tener toda esta información generada si no podemos hacer queries rápidas contra ella desde una aplicación web. Queremos <strong>poder renderizar un panel para cada usuario</strong> donde éste navegará por todas sus estadísticas, y queremos hacer ésto <strong>de manera escalable, óptima y flexible</strong>. En vez de precomputar todo el panel para volcarlo a una base de datos llave / valor, simplemente volcaremos las tablas generadas en Hive a Splout SQL, que será la que alimentará el frontend.</p>
<p><center><img alt="" src="http://sploutsql.com/img/sploutsql-logo-caption.png" width="400" /></center>Para desplegar las vistas generadas en Hive crearemos un descriptor en un fichero JSON llamado &#8220;<strong>hive_splout_example.json</strong>&#8220;. Crearemos este fichero en el sistema de ficheros local, en el directorio mismo de instalación de Splout SQL:</p>
<pre class="brush: jscript; title: ; notranslate">
{
	&quot;name&quot;: &quot;hive_splout_example&quot;,
	&quot;nPartitions&quot;: 2,
	&quot;partitionedTables&quot;: [{
		&quot;name&quot;: &quot;retweets&quot;,
		&quot;partitionFields&quot;: &quot;user&quot;,
	    	&quot;tableInputs&quot;: [{
			&quot;inputType&quot;: &quot;HIVE&quot;,
			&quot;hiveTableName&quot;: &quot;retweets&quot;,
			&quot;hiveDbName&quot;: &quot;default&quot;
		}]
	},{
		&quot;name&quot;: &quot;mentions_of_me&quot;,
		&quot;partitionFields&quot;: &quot;mentioned&quot;,
	    	&quot;tableInputs&quot;: [{
			&quot;inputType&quot;: &quot;HIVE&quot;,
			&quot;hiveTableName&quot;: &quot;mentions&quot;,
			&quot;hiveDbName&quot;: &quot;default&quot;
		}]
	},{
		&quot;name&quot;: &quot;mentions_by_me&quot;,
		&quot;partitionFields&quot;: &quot;mentioner&quot;,
	    	&quot;tableInputs&quot;: [{
			&quot;inputType&quot;: &quot;HIVE&quot;,
			&quot;hiveTableName&quot;: &quot;mentions&quot;,
			&quot;hiveDbName&quot;: &quot;default&quot;
		}]
	},{
		&quot;name&quot;: &quot;tophashtags&quot;,
		&quot;partitionFields&quot;: &quot;user&quot;,
	    	&quot;tableInputs&quot;: [{
			&quot;inputType&quot;: &quot;HIVE&quot;,
			&quot;hiveTableName&quot;: &quot;tophashtags&quot;,
			&quot;hiveDbName&quot;: &quot;default&quot;
		}]
	}]
}
</pre>
<p>En éste fichero JSON estamos describiendo el &#8220;tablespace&#8221; que desplegaremos en Splout SQL, que estará compuesto de cuatro tablas. Fijaros que <strong>particionamos por el usuario</strong>, y que importamos la misma tabla &#8220;mentions&#8221; dos veces. Ésto es porque estamos interesados tanto en las menciones de un usuario a otro como en las menciones que un usuario recibe de otros. Dado que debemos particionar el conjunto de datos, tenemos pues que importar doblemente la tabla, primero particionada por el que menciona y luego por el que es mencionado.</p>
<p>Para desplegar el &#8220;tablespace&#8221; a Splout SQL podemos usar la siguiente línea de comandos, ejecutada desde el directorio de instalación de Splout SQL:</p>
<pre>hadoop jar splout-*-hadoop.jar generate -tf file:///`pwd`/hive_splout_example.json -o out-hive_splout_example
hadoop jar splout-hadoop-*-hadoop.jar deploy -q http://localhost:4412 -root out-hive_splout_example -ts hive_splout_example</pre>
<h2>Obteniendo los resultados finales</h2>
<p>Podemos ir al panel de administración de Splout SQL para ver que el &#8220;tablespace&#8221; se ha desplegado correctamente, y ejecutar algunas &#8220;queries&#8221; de prueba. Por ejemplo, podemos obtener los hashtags más usado por &#8220;BarackObama&#8221; como ilustra la siguiente imagen:</p>
<p><a href="http://www.datasalt.com/2013/03/hive-splout-sql-for-a-social-media-reporting-webapp-a-big-data-love-story/obamahashtagsquery/" rel="attachment wp-att-1513"><img class="aligncenter size-full wp-image-1513" alt="ObamaHashtagsQuery" src="http://www.datasalt.com/wp-content/uploads/2013/03/ObamaHashtagsQuery.png" width="523" height="234" /></a></p>
<p>Y para usar ésta información en una webapp podemos usar la API REST de Splout SQL: <a href="http://localhost:4412/api/query/hive_splout_example?sql=SELECT%20*%20FROM%20tophashtags%20WHERE%20user%20=%20">http://localhost:4412/api/query/hive_splout_example?sql=SELECT * FROM tophashtags WHERE user = &#8216;BarackObama&#8217; ORDER BY count DESC;&amp;key=BarackObama</a></p>
<p>La cual devolverá una respuesta JSON:</p>
<pre class="brush: jscript; title: ; notranslate">
{
  millis: 10,
  error: null,
  result: [
  {
    count: 29,
    word: &quot;#WeDemandAVote&quot;,
    user: &quot;BarackObama&quot;
  },
  {
    count: 28,
    ...
  }]
}
</pre>
<p>La siguiente tabla muestra las queries que podemos hacer a Splout SQL para poder mostrar un panel de información para cada usuario:</p>
<table>
<tbody>
<tr>
<th>Qué</th>
<th>Cómo (SQL)</th>
</tr>
<tr>
<td>Top personas que me mencionan</td>
<td>SELECT mentioner, COUNT(*) as mentions FROM mentions_of_me WHERE mentioned = &#8220;BarackObama&#8221; GROUP BY mentioner ORDER BY mentions DESC LIMIT 10;</td>
</tr>
<tr>
<td>Top personas a las que menciono</td>
<td>SELECT mentioned, COUNT(*) as mentions FROM mentions_by_me WHERE mentioner = &#8220;BarackObama&#8221; GROUP BY mentioned ORDER BY mentions DESC LIMIT 10;</td>
</tr>
<tr>
<td>Top hashtags que uso</td>
<td>SELECT * FROM tophashtags WHERE user = &#8220;BarackObama&#8221; ORDER BY count DESC LIMIT 10;</td>
</tr>
<tr>
<td>Tweets míos más retwiteados</td>
<td>SELECT * FROM retweets WHERE user = &#8220;BarackObama&#8221; ORDER BY retweetcount DESC LIMIT 10;</td>
</tr>
</tbody>
</table>
<p>Pero también podríamos hacer cosas más complejas como gráficas de evolución temporal de menciones, ya que tenemos la fecha en cada mención. Así como agregados parciales por periodos temporales (mes, semana, año, &#8230;), y un largo etcétera.</p>
<h2>Conclusión</h2>
<p>Hemos podido construir una aplicación de <strong>analítica sobre Twitter totalmente escalabl</strong>e, ¡Y lo hemos hecho <strong>sin escribir una sola línea de código</strong>! Ésto ha sido posible por la <strong>integración entre Hive y Splout SQL</strong>. Hive provée una forma fácil e interactiva de generar &#8220;vistas Big Data&#8221; con datos en Hadoop, mientras que Splout SQL puede importar esas vistas directamente e indexarlas para que los usuarios puedan hacer queries rápidas sobre ellas. Teniendo SQL tanto en el backend como en el frontend podemos ser muy flexibles y ágiles. ¡No dudes en probar éste ejemplo y darnos tu feedback!</p>
<p>Entrada original en: <a href="http://www.datasalt.es/2013/03/hive-splout-sql-para-social-media-reporting-un-romance-big-data/">Hive + Splout SQL para analítica sobre Twitter: Un romance Big Data</a></p>]]></content:encoded>
			<wfw:commentRss>http://www.datasalt.es/2013/03/hive-splout-sql-para-social-media-reporting-un-romance-big-data/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cascading + Splout SQL para analizar y servir logs: Un romance Big Data</title>
		<link>http://www.datasalt.es/2013/03/1671/</link>
		<comments>http://www.datasalt.es/2013/03/1671/#comments</comments>
		<pubDate>Fri, 15 Mar 2013 16:37:41 +0000</pubDate>
		<dc:creator>Pere Ferrera Bertran</dc:creator>
				<category><![CDATA[Datasalt]]></category>

		<guid isPermaLink="false">http://www.datasalt.es/?p=1671</guid>
		<description><![CDATA[<p>(Éste es el primer post de una serie de tres posts presentando Splout SQL 0.2.2 y su integración nativa con Cascading, Hive y Pig). En éste post veremos un caso de uso Big Data en el que analizaremos e indexaremos una gran cantidad de logs Apache de un supuesto website e-Commerce. Queremos ser capaces de ...</p><p>Entrada original en: <a href="http://www.datasalt.es/2013/03/1671/">Cascading + Splout SQL para analizar y servir logs: Un romance Big Data</a></p>]]></description>
				<content:encoded><![CDATA[<p><em>(Éste es el primer post de una serie de tres posts presentando Splout SQL 0.2.2 y su integración nativa con Cascading, Hive y Pig).<br />
</em><br />
En éste post veremos un caso de uso Big Data en el que <strong>analizaremos e indexaremos</strong> una gran cantidad de <strong>logs</strong> Apache de un supuesto website e-Commerce. Queremos ser capaces de servirlos en una <strong>aplicación web</strong> de baja latencia que necesita información detallada de grano fino para cada usuario, para poder hacer <strong>campañas de fidelización y asistencia al usuario</strong>. Para ésta aplicación juntaremos <a href="http://www.cascading.org/">Cascading</a>, un framework Java de alto nivel para Hadoop con <a href="http://sploutsql.com/">Splout SQL</a>, una base de datos particionada SQL de alto rendimiento para Hadoop. Veremos cómo desarrollar una solución totalmente <strong>escalable tanto en el procesamiento como en el servicio</strong> de los datos, y la haremos en menos de 200 líneas de código. También proveeremos un frontend sencillo JavaScript que usará la API REST de Splout SQL vía jQuery.</p>
<p><span id="more-1671"></span></p>
<h2>Cascading</h2>
<p>Cascading es un framework que permite a programadores Java <strong>construir fácilmente flujos complejos</strong> Hadoop, abstrayéndoles de Map/Reduce. Nos gusta Cascading porque nos permite prototipar rápidamente. Hay otras herramientas que no son Java por encima de <a href="http://www.cascading.org/">Cascading</a> que se usan comúnmente como <a href="https://github.com/nathanmarz/cascalog">Cascalog</a> o <a href="https://github.com/twitter/scalding">Scalding</a>. A través de este ejemplo veremos unas cuantas primitivas Cascading y cómo se interconectan entre ellas.</p>
<h2>Splout SQL</h2>
<p>Ya hemos <a href="http://www.datasalt.es/2013/01/presentando-splout-sql-un-conector-sql-de-muy-baja-latencia-para-hadoop/">presentado Splout SQL</a> y visto un ejemplo de <a href="http://www.datasalt.es/2013/01/un-ejemplo-de-arquitectura-lambda-para-el-analisis-en-tiempo-real-de-hashtags-usando-trident-hadoop-y-splout-sql/">arquitectura lambda</a> con él. <a href="http://sploutsql.com/">Splout SQL</a> permite servir Big Data a bajas latencias y alta carga como cualquier otra NoSQL &#8211; pero con la obvia diferencia de que es SQL. A diferencia de los sistemas tipo Dremel que sirven para hacer queries exploratorias ad-hoc, análisis offline, etc, Splout SQL está pensado para ser usado en una <strong>web</strong>, ya que proveé un <strong>rendimiento</strong> predecible y consistente ante escenarios <strong>concurrentes</strong>. Y además, como veremos en éste ejemplo, permite <strong>desplegar datos desde Hadoop muy fácilmente</strong>.</p>
<h2>La webapp &#8220;back office&#8221; de un portal e-Commerce</h2>
<p>Éste imaginario portal e-Commerce tiene muchos usuarios y muchas categorías de productos. La categoría está siempre presente en la URL de cada producto. Hay un departmento de atención al usuario que se encarga de<strong> atender posibles problemas, contestar llamadas y planear campañas de fidelización</strong>. Necesitamos construir el backend de una aplicación web que se usará en este departmento y cuyos requerimientos son:</p>
<ul>
<li>Para cualquier usuario, obtener la <strong>secuencia de eventos</strong> que éste ha hecho en la web, en<strong> cualquier intervalo de tiempo</strong>. (Ésto nos ayudará a detectar y analizar posibles problemas, y es una información muy buena para el departamento técnico, para poder arreglar bugs fácilmente).</li>
</ul>
<p><img alt="" src="https://raw.github.com/pereferrera/splout-cascading-logs-example/master/raw-logs.png" width="600" /></p>
<ul>
<li>Para cualquier usuario, poder visualizar un<strong> resumen de su actividad</strong> en las diferentes categorías, y así poder llevar a cabo campañas de fidelización eficaces. (Por ejemplo, conocer las cinco categorías en las que el usuario interactúa más nos puede permitir ofrecer descuentos u otros productos promocionales interesantes para cada usuario).</li>
</ul>
<p><center><img alt="" src="https://raw.github.com/pereferrera/splout-cascading-logs-example/master/pie-chart.png" width="300/" /></center>Necesitamos una solución que sea:</p>
<ul>
<li><strong>Escalable</strong> tanto en el procesamiento como en el servicio.<strong> La cantidad de datos a ser servidos es igual de grande que la cantidad de datos a ser analizados</strong>.</li>
<li><strong>Sencilla</strong> de implementar.</li>
<li><strong>Flexible</strong> &#8211; para que podamos añadir y cambiar estadísticas fácilmente, cambiar toda la lógica de negocio y poder recalcularlo todo sin problema.</li>
<li>Con un coste razonable.</li>
</ul>
<h2>La solución</h2>
<p>En la solución &#8211; que se puede <a href="https://github.com/pereferrera/splout-cascading-logs-example">ver en github</a> &#8211; los logs Apache son parseados y analizados con Cascading, que produce dos ficheros de salida: uno con los logs parseados tal cual y otro con estadísticas consolidadas a partir de ellos (un agrupado por usuario, categoría y fecha). Ambos ficheros de salida pueden ser entonces transformados en tablas SQL para Splout SQL y consultados en tiempo real desde la aplicación web.</p>
<p>Usar <strong>Cascading para el procesamiento</strong> nos permite desarrollar e iterar rápidamente. Usar <strong>Splout SQL para el servicio</strong> nos permite ejecutar queries flexibles SQL sobre los datasets analizados y escalar horizontalmente sin tener que tener un sistema complejo y caro por debajo.</p>
<p>Explicaremos cada parte de la solución a continuación.</p>
<h2>Procesamiento de logs</h2>
<p>En primer lugar, los logs que se producen en el portal han de ser guardados en el HDFS para que los procese Hadoop. En ésta parte no vamos a incidir mucho &#8211; pero si la solución sencilla de subir periódicamente ficheros de logs parciales al HDFS no fuera suficiente, hay herramientas que pueden ayudarnos como Flume, Scribe, Kafka o Storm.</p>
<p>Una vez en el HDFS, los ficheros pueden ser analizados usando Cascading muy fácilmente. Sólo tenemos que parsearlos y emitirlos, junto con una agregación diaria por usuario y categoría. Éste es todo el código Java que necesitamos para implementar la lógica de negocio:</p>
<pre class="brush: java; title: ; notranslate">
	public void indexLogs(String inputPath, String outputPathLogs, String outputPathAnalytics) {
		// define what the input file looks like, &quot;offset&quot; is bytes from beginning
		TextLine scheme = new TextLine(new Fields(&quot;offset&quot;, &quot;line&quot;));

		// create SOURCE tap to read a resource from the local file system, if input is not an URL
		Tap logTap = inputPath.matches(&quot;^[^:]+://.*&quot;) ? new Hfs(scheme, inputPath) : new Lfs(scheme,
		    inputPath);

		// declare the field names we will parse out of the log file
		Fields apacheFields = new Fields(&quot;ip&quot;, &quot;user&quot;, &quot;time&quot;, &quot;method&quot;, &quot;category&quot;, &quot;page&quot;, &quot;code&quot;, &quot;size&quot;);

		// define the regular expression to parse the log file with
		String apacheRegex = &quot;^([^ ]*) +[^ ]* +([^ ]*) +\\[([^]]*)\\] +\\\&quot;([^ ]*) /([^/]*)/([^ ]*) [^ ]*\\\&quot; ([^ ]*) ([^ ]*).*$&quot;;

		// declare the groups from the above regex we want to keep. each regex group will be given
		// a field name from 'apacheFields', above, respectively
		int[] allGroups = { 1, 2, 3, 4, 5, 6, 7, 8 };

		// create the parser
		RegexParser parser = new RegexParser(apacheFields, apacheRegex, allGroups);

		// create the input analysis Pipe
		Pipe parsePipe = new Each(&quot;logs&quot;, new Fields(&quot;line&quot;), parser, Fields.RESULTS);

		// parse the date and split it into day + month + year
		parsePipe = new Each(parsePipe, new Fields(&quot;time&quot;), new DateParser(
		    new Fields(&quot;day&quot;, &quot;month&quot;, &quot;year&quot;), new int[] { Calendar.DAY_OF_MONTH, Calendar.MONTH,
		        Calendar.YEAR }, &quot;dd/MMM/yyyy:HH:mm:ss&quot;), Fields.ALL);

        // aggregate by date, user and category
		Pipe analyzePipe = new GroupBy(&quot;analyze&quot;, parsePipe, new Fields(&quot;day&quot;, &quot;month&quot;, &quot;year&quot;, &quot;user&quot;,
		    &quot;category&quot;));
        // count each aggregation
		analyzePipe = new Every(analyzePipe, new Count());

		// create a SINK tap to write to the default filesystem
		// To use the output in Splout, save it in binary (SequenceFile).
		// In this way integration is both efficient and easy (no need to re-parse the file again).
		Tap remoteLogTap = new Hfs(new SequenceFile(Fields.ALL), outputPathLogs, SinkMode.REPLACE);
		Tap remoteAnalyticsTap = new Hfs(new SequenceFile(Fields.ALL), outputPathAnalytics, SinkMode.REPLACE);

		// set the current job jar
		Properties properties = new Properties();
		AppProps.setApplicationJarClass(properties, LogIndexer.class);

		Map&lt;String, Tap&gt; sinks = new HashMap&lt;String, Tap&gt;();
		sinks.put(&quot;logs&quot;, remoteLogTap);
		sinks.put(&quot;analyze&quot;, remoteAnalyticsTap);

		// connect the assembly to the SOURCE and SINK taps
		Flow parsedLogFlow = new HadoopFlowConnector(properties).connect(logTap, sinks, parsePipe,
		    analyzePipe);

		// start execution of the flow (either locally or on a cluster)
		parsedLogFlow.start();

		// block until the flow completes
		parsedLogFlow.complete();
	}
</pre>
<p>La variable &#8220;parsePipe&#8221; es la responsable de parsear los logs, y &#8220;analyzePipe&#8221; ejecuta la agregación sobre ellos. Usamos ambas variables como outputs del flow (sinks). Vemos que parsear los logs es muy fácil usando la función RegexParser.</p>
<p>Fijaros en lo fácil que es razonar sobre el flujo de datos con las operaciones Each, GroupBy y Every. Ésto es similar a lo que vimos <a href="http://www.datasalt.com/2013/01/an-example-lambda-architecture-using-trident-hadoop-and-splout-sql/">con Trident en éste post previo</a>. De alguna manera, <strong>Trident es al procesamiento tiempo-real lo que Cascading es al procesamiento por lotes</strong>.</p>
<h2>Indexado y servicio de los logs</h2>
<p>Para poder servir eficientemente toda la información estructurada que hemos sacado de Cascading necesitamos una base de datos escalable, rápida y consistente. Usando Splout SQL podemos también acceder a la expresividad SQL sobre los datos de manera que<strong> no tenemos que precomputarlo todo con antelación</strong>. Podemos implementar gráficas de evolución temporal tipo las de Google Analytics sin apenas coste.</p>
<p>Por otro lado, para poder usar Splout SQL<strong> debemos particionar los datos</strong>. Pero en nuestro caso ésto no es un problema ya que queremos proveer un panel individualizado para cada usuario, así que podemos particionar fácilmente por usuario.</p>
<p><center><img alt="" src="https://raw.github.com/pereferrera/splout-cascading-logs-example/master/timeline.png" width="520/" /></center>Para hacer ésto usaremos la API &#8220;splout-hadoop&#8221;. Podemos usar el proyecto <a href="https://github.com/datasalt/splout-hadoop-starter">splout-starter</a> como punto de partida. Así, el código para indexar y desplegar los datos es el siguiente:</p>
<pre class="brush: java; title: ; notranslate">
	public void deployToSplout(String outputPathLogs, String outputPathAnalytics, String qNode,
	    int nPartitions) throws Exception {
		// add sqlite native libs to DistributedCache
		if(!FileSystem.getLocal(conf).equals(FileSystem.get(conf))) {
			SploutHadoopConfiguration.addSQLite4JavaNativeLibsToDC(conf);
		}

		// delete tablespace-generated files if they already exist
		FileSystem outputPathFileSystem = new Path(outputPath).getFileSystem(conf);
		Path outputToGenerator = new Path(outputPath + &quot;-generated&quot;);
		if(outputPathFileSystem.exists(outputToGenerator)) {
			outputPathFileSystem.delete(outputToGenerator, true);
		}

		TablespaceBuilder builder = new TablespaceBuilder();
		// build a Table instance of each table using the builder
		TableBuilder logsTable = new TableBuilder(&quot;logs&quot;, getConf());
		String[] logsColumns = new String[] { &quot;ip&quot;, &quot;user&quot;, &quot;time&quot;, &quot;method&quot;, &quot;category&quot;, &quot;page&quot;, &quot;code&quot;, &quot;size&quot;, &quot;day&quot;, &quot;month&quot;, &quot;year&quot; };
		logsTable.addCascadingTable(new Path(outputPathLogs), logsColumns, conf);
		logsTable.partitionBy(&quot;user&quot;);

		TableBuilder analyticsTable = new TableBuilder(&quot;analytics&quot;, getConf());
		String[] analyticsColumns = new String[] { &quot;day&quot;, &quot;month&quot;, &quot;year&quot;, &quot;user&quot;, &quot;category&quot;, &quot;count&quot; };
		analyticsTable.addCascadingTable(new Path(outputPathAnalytics), analyticsColumns, conf);
		analyticsTable.partitionBy(&quot;user&quot;);

		builder.add(logsTable.build());
		builder.add(analyticsTable.build());
		// define number of partitions
		builder.setNPartitions(nPartitions);

		// instantiate and call the TablespaceGenerator with the output fo the TablespaceBuilder
		TablespaceGenerator viewGenerator = new TablespaceGenerator(builder.build(), outputToGenerator,
		    this.getClass());
		viewGenerator.generateView(conf, SamplingType.DEFAULT, new DefaultSamplingOptions());

		// finally, deploy the generated files
		StoreDeployerTool deployer = new StoreDeployerTool(qNode, conf);
		List specs = new ArrayList();
		specs.add(new TablespaceDepSpec(&quot;cascading_splout_logs_example&quot;, outputToGenerator.toString(), 1, null));

		deployer.deploy(specs);
	}
</pre>
<p>Fijaros cómo usamos el método <strong>addCascadingTable</strong> en TableBuilder para poder indexar ficheros binarios Cascading directamente. Ésta manera es la más eficiente de exportar la salida de un proceso Cascading ya que así nos ahorramos tener que exportarlo a texto y reparsearlo después.</p>
<p>En éste ejemplo hemos usado la API Java para exportar a Splout SQL, pero bien <strong>podríamos haberlo hecho con línea de comandos sin programar nada</strong>. Para hacer lo mismo que en el código de arriba sin programar, podríamos ejecutar los siguientes comandos:</p>
<pre>  hadoop jar splout-*-hadoop.jar generate -tf file:///`pwd`/cascading-export.json -o out-cascading-export
  hadoop jar splout-*-hadoop.jar deploy -root out-cascading-export -ts cascading_splout_logs_example -q http://localhost:4412</pre>
<p>Teniendo en cuenta que el fichero &#8220;cascading-export.json&#8221; sería algo como:</p>
<pre>{
	"name": "cascading_splout_logs_example",
	"nPartitions": 2,
	"partitionedTables": [{
		"name": "logs",
		"partitionFields": "user",
		"tableInputs": [{
			"inputType": "CASCADING",
			"cascadingColumns": "ip,user,time,method,category,page,code,size,day,month,year",
			"paths": [ "out-clogs-logs" ]
		}]
	},{
		"name": "analytics",
		"partitionFields": "user",
		"tableInputs": [{
			"inputType": "CASCADING",
			"cascadingColumns": "day,month,year,user,category,count",
			"paths": [ "out-clogs-analytics" ]
		}]
	}]
}</pre>
<h2>Pruébalo!</h2>
<p>En ésta aplicación web para un portal e-Commerce hemos ilustrado la integración fácil entre Splout SQL y herramientas Hadoop como Cascading. En los siguientes posts haremos lo mismo para Hive y Pig. El <a href="https://github.com/pereferrera/splout-cascading-logs-example">proyecto y las instrucciones detalladas para probarlo están en github</a>, así que prúebalo!</p>
<p>Entrada original en: <a href="http://www.datasalt.es/2013/03/1671/">Cascading + Splout SQL para analizar y servir logs: Un romance Big Data</a></p>]]></content:encoded>
			<wfw:commentRss>http://www.datasalt.es/2013/03/1671/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Un ejemplo de “arquitectura lambda” para el análisis en tiempo real de hashtags usando Trident, Hadoop y Splout SQL</title>
		<link>http://www.datasalt.es/2013/01/un-ejemplo-de-arquitectura-lambda-para-el-analisis-en-tiempo-real-de-hashtags-usando-trident-hadoop-y-splout-sql/</link>
		<comments>http://www.datasalt.es/2013/01/un-ejemplo-de-arquitectura-lambda-para-el-analisis-en-tiempo-real-de-hashtags-usando-trident-hadoop-y-splout-sql/#comments</comments>
		<pubDate>Fri, 25 Jan 2013 11:58:19 +0000</pubDate>
		<dc:creator>Pere Ferrera Bertran</dc:creator>
				<category><![CDATA[Datasalt]]></category>

		<guid isPermaLink="false">http://www.datasalt.es/?p=1643</guid>
		<description><![CDATA[<p>En este post mostraremos cómo usar Trident, Hadoop y Splout SQL para construir un ejemplo de &#8220;arquitectura lambda&#8220;. Aprenderemos cosas básicas de Trident, una API de alto nivel por encima de Storm. También veremos Splout SQL, una base de datos de sólo lectura SQL para Hadoop. La arquitectura ejemplo está alojada en éste proyecto github. ...</p><p>Entrada original en: <a href="http://www.datasalt.es/2013/01/un-ejemplo-de-arquitectura-lambda-para-el-analisis-en-tiempo-real-de-hashtags-usando-trident-hadoop-y-splout-sql/">Un ejemplo de &#8220;arquitectura lambda&#8221; para el análisis en tiempo real de hashtags usando Trident, Hadoop y Splout SQL</a></p>]]></description>
				<content:encoded><![CDATA[<p>En este post mostraremos cómo usar <a href="https://github.com/nathanmarz/storm/wiki/Trident-tutorial" target="_blank">Trident</a>, <a href="http://hadoop.apache.org/" target="_blank">Hadoop</a> y <a href="http://sploutsql.com/" target="_blank">Splout SQL</a> para construir un ejemplo de &#8220;<a href="http://www.dzone.com/links/r/big_data_lambda_architecture.html" target="_blank">arquitectura lambda</a>&#8220;. Aprenderemos cosas básicas de Trident, una API de alto nivel por encima de Storm. También veremos Splout SQL, una base de datos de sólo lectura SQL para Hadoop. La arquitectura ejemplo está <a href="https://github.com/pereferrera/trident-lambda-splout" target="_blank">alojada en éste proyecto github</a>. Lo que haremos será contar el número de apariciones de un hashtag en tweets, agrupado por fecha. El fin último es resolver este simple problema de una manera totalmente escalable, y proveer de un servicio de baja latencia para obtener la evolución de un hashtag a través del tiempo, incluyendo tanto datos en tiempo real como datos consolidados.</p>
<p>Así que para cualquier hashtag queremos ser capaces de hacer una query a un servicio remoto y obtener una evolución temporal parecida a:</p>
<pre>
{
  "20091022":115,
  "20091023":115,
  "20091024":158,
  "20091025":19
}
</pre>
<p><span id="more-1643"></span></p>
<h2>Arquitectura lambda</h2>
<p>La &#8220;<a href="http://www.dzone.com/links/r/big_data_lambda_architecture.html" target="_blank">arquitectura lambda</a>&#8221; es un concepto acuñado por Nathan Marz. A nosotros nos gusta porque es un modelo que escala y que tiene tanto las ventajas del procesamiento en lotes (batch) como la frescura del proceso de datos en tiempo real, con actualización de los datos en segundos. No hemos encontrado ejemplos prácticos de éste tipo de arquitectura en Internet así que hemos pensado que sería buena idea desarrollar uno y <a href="https://github.com/pereferrera/trident-lambda-splout" target="_blank">compartirlo</a>.</p>
<h2>Trident</h2>
<p><a href="https://github.com/nathanmarz/storm/wiki/Trident-tutorial" target="_blank">Trident</a> es una API por encima de Storm. Ya hemos hablado antes de <a href="https://github.com/nathanmarz/storm" target="_blank">Storm</a> y hemos enseñado un ejemplo de uso sencillo <a href="http://www.datasalt.es/2012/01/arquitectura-de-feeds-tiempo-real-con-storm/" target="_blank">en éste post</a>. Trident provée primitivas de alto-nivel por encima de Storm, parecidas a las que provée <a href="http://cascading.org" target="_blank">Cascading</a> para Hadoop (each(), groupBy()). También provée &#8220;wrappers&#8221; y primitivas para <a href="https://github.com/nathanmarz/storm/wiki/Trident-state" target="_blank">poder guardar o consultar estado</a> en una topología, ya sea en memoria o en una base de datos persistente.</p>
<h2>Splout SQL</h2>
<p><a href="http://sploutsql.com/" target="_blank">Splout SQL</a> es una base de datos desarrollada por nosotros que puede desplegar datos de Hadoop de forma muy eficiente. Sería como <a href="https://github.com/nathanmarz/elephantdb" target="_blank">ElephantDB</a> pero con SQL. Es una base de datos SQL particionada, de sólo lectura y con un alto rendimiento, que puede trabajar con conjuntos de datos generados por Hadoop. Ya la hemos presentado antes <a href="http://www.datasalt.es/2013/01/presentando-splout-sql-un-conector-sql-de-muy-baja-latencia-para-hadoop/">en éste post</a>.</p>
<h2>Juntando todas las piezas para formar &#8220;una lambda&#8221;</h2>
<p>Los tweets son introducidos en el sistema (1), por ejemplo a través de una cola (Storm tiene conectores para <a href="https://github.com/nathanmarz/storm-contrib/tree/master/storm-kafka" target="_blank">Kafka</a>, <a href="https://github.com/nathanmarz/storm-contrib/tree/master/storm-jms" target="_blank">JMS</a> y <a href="https://github.com/nathanmarz/storm-kestrel" target="_blank">Kestrel</a>, pero también puedes programarte tú mismo uno fácilmente). Un &#8220;stream&#8221; de Trident (2) guarda los tweets en Hadoop (en el HDFS) y además los procesa en tiempo real para crear un estado en memoria que almacenará las apariciones agrupadas por fecha. En Hadoop (3), donde tendremos todo el histórico de los tweets, podemos ejecutar un proceso &#8220;batch&#8221; que agregue los tweets por hashtag y fecha y genere un gran fichero como salida. Después de eso, podemos usar Splout SQL para indexar ese fichero y desplegarlo a un clúster Splout SQL (4), el cual será capaz de servir todas las estadísticas de forma altamente eficiente. Entonces, un segundo &#8220;stream&#8221; de Trident (DRPC) puede ser usado para servir las queries (5), y éste hará una query tanto al resultado de la capa &#8220;batch&#8221; (a través de Splout SQL) como a la capa de tiempo real (a través del estado en memoria del primer &#8220;stream&#8221;), y juntar los resultados en una única respuesta. Veremos cada una de éstas cosas en más detalle.</p>
<p><img src="https://raw.github.com/pereferrera/trident-lambda-splout/master/TridentSploutArch-medium-numbered.png" alt="" /></p>
<h2>La capa &#8220;batch&#8221;</h2>
<p>La capa &#8220;batch&#8221; es la más sencilla. Sólo tenemos que almacenar todos los tweets en el HDFS y ejecutar un trabajo periódico que los agregue por hashtag y fecha. No hemos desarrollado esta parte, en vez de ello hemos usado un pequeño conjunto de datos de ejemplo de <a href="http://www.infochimps.com/" target="_blank">Infochimps</a>. A continuación mostramos un ejemplo de cómo son éstos datos (que también podeis <a href="https://github.com/pereferrera/trident-lambda-splout/blob/master/sample-hashtags/small_sample_hashtags.txt" target="_blank">ver en éste link</a>):</p>
<pre>
hashtag	2009081313	1	calirfonia
hashtag	2009101713	1	caliroadtrip
hashtag	2009101815	2	caliroadtrip
hashtag	2009080813	1	caliroots
hashtag	2009092807	1	caliroots
</pre>
<p>Hay un montón de información en Internet sobre cómo hacer tareas sencillas de agregación con herramientas como (de más bajo nivel a menos): <a href="http://pangool.net/" target="_blank">Pangool</a>, <a href="http://www.cascading.org/" target="_blank">Cascading</a>, <a href="http://pig.apache.org/" target="_blank">Pig</a> o <a href="http://hive.apache.org/" target="_blank">Hive</a>. La idea es que la salida del proceso de la capa &#8220;batch&#8221; debería ser algo como lo que hemos mostrado: un fichero tabulado con las cuentas para cada hashtag y fecha. Dado que guardamos todos los tweets en el HDFS, podemos ejecutar un proceso &#8220;batch&#8221; que calcule muchas cosas, y ejecutarlo tantas veces queramos y recalcularlo todo cada vez. Tenemos absoluta libertad y tolerancia a fallos en ésta capa.</p>
<h2>La capa &#8220;de servicio&#8221;</h2>
<p>Uno de los retos de ésta arquitectura ejemplo es ser capaces de servir queries a muy baja latencia y a muy alto rendimiento (con muchos usuarios concurrentes) para un conjunto de datos que puede ser de múltiples GBytes o incluso TBytes. Dado que la mayor parte de los datos vienen de Hadoop (menos la parte de tiempo real), necesitamos algún tipo de puente entre Hadoop y una base de datos rápida. No podemos hacer queries directamente sobre ficheros Hadoop. Cosas como <a href="http://blog.cloudera.com/blog/2012/10/cloudera-impala-real-time-queries-in-apache-hadoop-for-real/" target="_blank">Impala</a> o <a href="http://wiki.apache.org/incubator/DrillProposal" target="_blank">Drill</a> nos permitirían cierto tipo de queries exploratorias, pero no podemos usarlas delante de un servidor web y esperar servir millones de queries con ellas. Necesitamos índices, B-Trees que hagan las queries verdaderamente eficientes.</p>
<p>Podríamos volcar las estadísticas a una base de datos llave/valor como <a href="http://www.project-voldemort.com/voldemort/" target="_blank">Voldemort</a> o <a href="https://github.com/nathanmarz/elephantdb" target="_blank">ElephantDB</a>, donde la llave sería el hashtag. Pero, ¿Qué pasa si queremos ser capaces de proveer estadísticas diarias, semanales y mensuales? ¿Y si queremos mostrar un agrupado por hora para ver en qué horas se menciona más un hashtag? Al usar una base de datos llave/valor nos vemos forzados a precalcularlo todo en Hadoop, lo cual no es siempre muy satisfactorio que digamos. Por eso <a href="http://sploutsql.com/" target="_blank">Splout SQL</a> es más conveniente para este tipo de tareas, ya que nos permite usar SQL para ejecutar queries más flexibles sobre los datos pre-agregados.</p>
<p>En el <a href="https://github.com/pereferrera/trident-lambda-splout" target="_blank">ejemplo que tenemos en github</a> encontrareis las instrucciones (en inglés) para descargar Splout SQL rápidamente y cargar el conjunto de datos de ejemplo. Los comandos que hay que ejecutar son algo así:</p>
<pre>
hadoop jar splout-hadoop-*-hadoop.jar simple-generate -i sample-hashtags -o out-hashtags -pby hashtag -p 2 -s "label:string,date:string,count:int,hashtag:string" --index "hashtag,date" -t hashtags -tb hashtags
hadoop jar splout-hadoop-*-hadoop.jar deploy -q http://localhost:4412 -root out-hashtags -ts hashtags
</pre>
<p>El primer comando genera las estructuras de datos indexadas (ficheros SQL) para poder servir las queries de forma eficiente, y el segundo comando lanza una tarea de despliegue de los datos al clúster Splout SQL.</p>
<p>Como Splout es una SQL particionada, necesitamos especificar un esquema y campos de particionado, así como el número de particiones que queremos generar. Podemos especificar cosas como los índices a generar, ya que sabemos qué tipo de queries vamos a hacer. En este caso hemos creado un índice compuesto por &#8220;hashtag&#8221; y fecha (&#8220;date&#8221;) ya que así podríamos extender la aplicación, pudiendo hacer consultas entre periodos arbitrarios de fechas.</p>
<p>Pero para poder usar Splout SQL con Trident necesitamos programar un conector (<a href="https://github.com/pereferrera/trident-lambda-splout/blob/master/src/main/java/com/datasalt/trident/SploutState.java" target="_blank">SploutState</a>). Éste conector extiende &#8220;ReadOnlyState&#8221; y provée una &#8220;StateFactory&#8221;, que es lo que nos requiere la API de Trident:</p>
<pre class="brush: java; title: ; notranslate">
public class SploutState extends ReadOnlyState {
  // The Splout Java client
  private SploutClient sploutClient;
  ...
  public static class Factory implements StateFactory {
    ...
  }
}
</pre>
<p>Entonces implementa un método que puede recibir múltiples queries y ejecutarlas usando el cliente Java de Splout:</p>
<pre class="brush: java; title: ; notranslate">
public List&lt;Object&gt; querySplout(String tablespace, List&lt;String&gt; sql, List&lt;String&gt; keys) {
  ...
}
</pre>
<p>(Fijaros que cada query está asociada con una llave (&#8220;keys&#8221;). Ésto es necesario porque Splout hace una query a una única partición, y la llave le dice cuál es esa partición.)<br />
(¿Por qué múltiples queries a la vez? Porque Trident agrupará varias tuplas en pequeños lotes que entonces se ejecutarán de golpe de forma más eficiente que una a una.)</p>
<p>Otra cosa que tenemos que hacer es implementar un BaseQueryFunction (<a href="https://github.com/pereferrera/trident-lambda-splout/blob/master/src/main/java/com/datasalt/trident/HashTagsSploutQuery.java" target="_blank">HashTagsSploutQuery</a>) que usaremos junto al SploutState para definir la lógica del &#8220;stream&#8221; DRPC. Esta función contendrá la lógica de negocio involucrada en hacer la query a Splout para éste ejemplo de uso. Así que podríamos reusar SploutState con cualquier otro BaseQueryFunction. En este caso, la función es tal que:</p>
<pre class="brush: java; title: ; notranslate">
public class HashTagsSploutQuery extends BaseQueryFunction&lt;SploutState, Object&gt; {

  public List&lt;Object&gt; batchRetrieve(SploutState state, List&lt;TridentTuple&gt; args) {
    List&lt;String&gt; sqls = new ArrayList&lt;String&gt;();
    List&lt;String&gt; partitionKeys = new ArrayList&lt;String&gt;();
    // fill the data
    for(TridentTuple arg: args) {
      String hashTag = arg.getString(0);
      sqls.add(&quot;SELECT SUM(count), substr(date, 0, 9) as day FROM hashtags WHERE hashtag = '&quot; + hashTag + &quot;' GROUP BY day;&quot;);
      partitionKeys.add(hashTag);
    }
    return state.querySplout(TABLESPACE, sqls, partitionKeys);
  }

  public void execute(TridentTuple tuple, Object result, TridentCollector collector) {
    collector.emit(new Values(result));
  }
}
</pre>
<p>El primer método, batchRetrieve(), es llamado por Trident con un conjunto de tuplas. Entonces llamamos a SploutState para resolver tantas queries SQL como tuplas hemos recibido, particionando por hashtag. El segundo método, execute(), es llamado por Trident para obtener los datos que se añadirán a la tupla del &#8220;stream&#8221;. En este caso añadiremos un campo nuevo con el resultado de la query.</p>
<p>Más adelante veremos cómo se conecta esta parte con el resto del sistema.</p>
<h2>La capa de &#8220;tiempo real&#8221;</h2>
<p>La capa de tiempo real la hemos implementado usando un &#8220;stream&#8221; Trident que guarda cierto estado en un mapa en memoria. El código puede ser visto en la clase que define la topología (<a href="https://github.com/pereferrera/trident-lambda-splout/blob/master/src/main/java/com/datasalt/trident/LambdaHashTagsTopology.java" target="_blank">LambdaHashTagsTopology</a>) y es algo así:</p>
<pre class="brush: java; title: ; notranslate">
TridentState hashTagCounts = topology
  .newStream(&quot;spout1&quot;, spout)
  .each(new Fields(&quot;tweet&quot;, &quot;date&quot;), new Split(), new Fields(&quot;word&quot;))
  .each(new Fields(&quot;word&quot;, &quot;date&quot;), new HashTagFilter(), new Fields(&quot;hashtag&quot;))
  .groupBy(new Fields(&quot;hashtag&quot;))
  .persistentAggregate(mapState, new Fields(&quot;hashtag&quot;, &quot;date&quot;), new CountByDate(), new Fields(&quot;datecount&quot;));
</pre>
<p>Cuando desarrollamos &#8220;streams&#8221; Trident tenemos que tener ciertas cosas claras. La primera es la forma en que las tuplas mutan a través del &#8220;stream&#8221;. Las funciones each() procesan un conjunto de campos de entrada y emiten una tupla con éstos mismos campos junto con los campos de salida que hemos declarado. Por otro lado, las funciones aggregate() sólo emiten los campos que declaramos de salida. Y si queremos emitir un subconjunto de campos tras un each(), podemos usar project(). Por otro lado, y como consecuencia de ésto, no podemos declarar un campo de salida que se llama igual que uno de entrada: colisionaría en la tupla de salida.</p>
<p>Desarrollar &#8220;streams&#8221; Trident sigue el mismo patrón de programación que desarrollar Cascading. Hay que crear funciones o filtros propios que ejecuten cierta lógica de negocio que luego inyectaremos en la declaración del &#8220;stream&#8221;. Para este caso, hemos creado &#8220;HashTagFilter&#8221; que procesa como input una palabra y sólo la emite si es un hashtag (#), en cuyo caso emite todos los caracteres de la palabra menos el primero:</p>
<pre class="brush: java; title: ; notranslate">
public static class HashTagFilter extends BaseFunction {
  public void execute(TridentTuple tuple, TridentCollector collector) {
    String word = tuple.getString(0);
    if(word.startsWith(&quot;#&quot;)) {
      collector.emit(new Values(word.substring(1, word.length())));
    }
  }
}
</pre>
<p>También hemos creado un agregador que se llama &#8220;CountByDate&#8221; y que se ejecuta antes de persistir las tuplas que agregamos por hashtag. Como queremos mostrar una evolución temporal, necesitamos agrupar las cuentas por fecha. Por simplicidad lo hemos hecho por día, pero también lo podríamos haber hecho por hora. Guardaremos un mapa de (fecha -> cuenta) en un mapa en memoria cuya llave será el &#8220;hashtag&#8221;. Como todo ésto se ejecuta en paralelo y de forma incremental, tenemos que poder mezclar dos mapas potencialmente diferentes en un momento dado (una operación de &#8220;combine&#8221; como las de Hadoop). Fijaros especialmente en la operación combine():</p>
<pre class="brush: java; title: ; notranslate">
public static class CountByDate implements CombinerAggregator&lt;Map&lt;String, Long&gt;&gt; {

  public Map&lt;String, Long&gt; init(TridentTuple tuple) {
    Map&lt;String, Long&gt; map = zero();
    map.put(tuple.getString(1), 1L);
    return map;
  }

  public Map&lt;String, Long&gt; combine(Map&lt;String, Long&gt; val1, Map&lt;String, Long&gt; val2) {
    for(Map.Entry&lt;String, Long&gt; entry : val2.entrySet()) {
      val2.put(entry.getKey(), MapUtils.getLong(val1, entry.getKey(), 0L) + entry.getValue());
    }
    for(Map.Entry&lt;String, Long&gt; entry : val1.entrySet()) {
      if(val2.containsKey(entry.getKey())) {
        continue;
      }
      val2.put(entry.getKey(), entry.getValue());
    }
    return val2;
  }

  public Map&lt;String, Long&gt; zero() {
    return new HashMap&lt;String, Long&gt;();
  }
}
</pre>
<p>Ahora veremos cómo la capa de servicio y la de tiempo real se interconectan en el servicio DRPC.</p>
<h2>El servicio DRPC</h2>
<p>Una de las cosas buenas de Storm es que puede ejecutar llamadas RPC de forma distribuída. Podemos usar ésto para crear un servicio que estará detrás de un website y que mostrará evoluciones temporales para &#8220;hashtags&#8221;. Ahora que tenemos una capa &#8220;batch&#8221; que computa todo el histórico de las estadísticas y las vuelca a Splout SQL, y una capa de &#8220;tiempo real&#8221; que puede calcular la evolución en tiempo real de un &#8220;hashtag&#8221;, ¿Cómo juntamos todo ésto?</p>
<p>Vamos a añadir un servicio DRPC a la topología Storm:</p>
<pre class="brush: java; title: ; notranslate">
topology
  .newDRPCStream(&quot;hashtags&quot;, drpc)
  .each(new Fields(&quot;args&quot;), new Split(), new Fields(&quot;hashtag&quot;))
  .groupBy(new Fields(&quot;hashtag&quot;))
  .stateQuery(hashTagCounts, new Fields(&quot;hashtag&quot;), new MapGet(), new Fields(&quot;resultrt&quot;))
  .stateQuery(sploutState, new Fields(&quot;hashtag&quot;, &quot;resultrt&quot;), new HashTagsSploutQuery(), new Fields(&quot;resultbatch&quot;))
  .each(new Fields(&quot;hashtag&quot;, &quot;resultrt&quot;, &quot;resultbatch&quot;), new LambdaMerge(), new Fields(&quot;result&quot;))
  .project(new Fields(&quot;result&quot;));
</pre>
<p>Las queries RPC se paralelizan por &#8220;hashtag&#8221;. Para cada una de ellas, dos queries se ejecutan en secuencia: una a la capa &#8220;tiempo real&#8221; (hashTagCounts) y la otra a la capa de &#8220;servicio&#8221; con los datos de la capa &#8220;batch&#8221;: (sploutState). Fijaros cómo usamos la función Trident MapGet() para poder obtener los resultados de la capa &#8220;tiempo real&#8221; y la función que hemos programado antes HashTagsSploutQuery() para obtener los datos de Splout SQL. Fijaros que la tupla al final tiene tres campos: el hashtag, el resultado &#8220;batch&#8221; y el resultado &#8220;tiempo real&#8221;. Al final, usamos una función llamada LambdaMerge() que mezcla el resultado de ambas capas para devolver una respuesta unificada al usuario del servicio DRPC.</p>
<p>La lógica de negocio para mezclar los resultados de ambas capas es muy sencilla. Simplemente asumimos que si un resultado viene de la capa &#8220;batch&#8221; ese resultado tiene prioridad (por lo tanto, &#8220;machaca&#8221; cualquier posible resultado de la capa &#8220;tiempo real&#8221;). Además, devolvemos un mapa ordenado por la llave:</p>
<pre class="brush: java; title: ; notranslate">
public static class LambdaMerge extends BaseFunction {

  public void execute(TridentTuple tuple, TridentCollector collector) {
    Map&lt;String, Long&gt; resultRealTime = (Map&lt;String, Long&gt;) tuple.get(1);
    QueryStatus resultBatch = (QueryStatus) tuple.get(2);
    TreeMap&lt;String, Long&gt; consolidatedResult;

    if(resultRealTime != null) {
      consolidatedResult = new TreeMap&lt;String, Long&gt;(resultRealTime);
    } else {
      consolidatedResult = new TreeMap&lt;String, Long&gt;();
    }
    if(resultBatch != null) {
      if(resultBatch.getResult() != null) {
        for(Object rowBatch : resultBatch.getResult()) {
          Map&lt;String, Object&gt; mapRow = (Map&lt;String, Object&gt;) rowBatch;
          String day = (String) mapRow.get(&quot;day&quot;);
          Long count = Long.parseLong(mapRow.get(&quot;SUM(count)&quot;).toString());
          consolidatedResult.put(day, count);
        }
      }
    }
    collector.emit(new Values(consolidatedResult));
  }
}
</pre>
<h2>Probarlo</h2>
<p>Podeis seguir <a href="https://github.com/pereferrera/trident-lambda-splout" target="_blank">las instrucciones en github (en inglés)</a> para probar este sencillo ejemplo. El ejemplo usa una sucesión infinita de dos falsos tweets en tiempo real (&#8220;#california is cool&#8221;, &#8220;I like #california&#8221;) y hace queries a Splout SQL donde se debería haber cargado el conjunto de datos de ejemplo &#8211; que también contienen el hashtag &#8220;california&#8221;. Así que después de ejecutarlo todo se debería ver algo como:</p>
<pre>
...
Result for hashtag 'california' -> [[{"20091022":115,"20091023":115,"20091024":158,"20091025":19}]]
Result for hashtag 'california' -> [[{"20091022":115,"20091023":115,"20091024":158,"20091025":19,"20130123":76}]]
Result for hashtag 'california' -> [[{"20091022":115,"20091023":115,"20091024":158,"20091025":19,"20130123":136}]]
Result for hashtag 'california' -> [[{"20091022":115,"20091023":115,"20091024":158,"20091025":19,"20130123":192}]]
Result for hashtag 'california' -> [[{"20091022":115,"20091023":115,"20091024":158,"20091025":19,"20130123":232}]]
Result for hashtag 'california' -> [[{"20091022":115,"20091023":115,"20091024":158,"20091025":19,"20130123":286}]]
...
</pre>
<p>Como se vé, la última fecha (que debería coincidir con la fecha de hoy) se incrementa en tiempo real mientras las otras fechas históricas no evolucionan &#8211; se han añadido a la respuesta a través de los resultados de la capa &#8220;batch&#8221; provistos por Splout SQL.</p>
<h2>Conclusiones</h2>
<p>A través de este ejemplo hemos visto Trident, una API interesant de alto nivel por encima de Storm, y Splout SQL, una base de datos SQL raṕida, particionada y de sólo lectura para Hadoop. Hemos visto un ejemplo real de una &#8220;arquitectura lambda&#8221;, omitiendo ciertas partes que no eran tan interesantes para éste ejemplo.</p>
<p>Pero no podemos acabar sin mencionar algo que nos hemos dejado: hablar de un &#8220;coordinador&#8221;. Debería haber un coordinador que lanzara el proceso &#8220;batch&#8221; periódicamente y además asegurar que la capa &#8220;batch&#8221; sólo procesa datos completos. Con datos completos nos referimos a que si la agrupación mínima es por hora, la capa &#8220;batch&#8221; no debería procesar horas incompletas (éstas quedarían sólo para la capa &#8220;tiempo real&#8221;). De esta manera, se cumpliría la propiedad de que cualquier estadística calculada por la capa &#8220;batch&#8221; puede &#8220;machacar&#8221; la estadística correspondiente en la capa &#8220;tiempo real&#8221;. Por otro lado, para que la capa &#8220;tiempo real&#8221; sea eficiente, debería expirar datos antiguos periódicamente. Pero hay que tener cuidado, ya que si se expiran los datos antes de que la capa &#8220;batch&#8221; haya calculado lo correspondiente, se corre el riesgo de tener &#8220;agujeros&#8221; en los resultados.</p>
<p>Como hemos dicho varios veces, <a href="https://github.com/pereferrera/trident-lambda-splout" target="_blank">aquí teneis el código completo con comentarios en inglés</a>.</p>
<p>Entrada original en: <a href="http://www.datasalt.es/2013/01/un-ejemplo-de-arquitectura-lambda-para-el-analisis-en-tiempo-real-de-hashtags-usando-trident-hadoop-y-splout-sql/">Un ejemplo de &#8220;arquitectura lambda&#8221; para el análisis en tiempo real de hashtags usando Trident, Hadoop y Splout SQL</a></p>]]></content:encoded>
			<wfw:commentRss>http://www.datasalt.es/2013/01/un-ejemplo-de-arquitectura-lambda-para-el-analisis-en-tiempo-real-de-hashtags-usando-trident-hadoop-y-splout-sql/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Presentando Splout SQL: Un conector SQL de muy baja latencia para Hadoop</title>
		<link>http://www.datasalt.es/2013/01/presentando-splout-sql-un-conector-sql-de-muy-baja-latencia-para-hadoop/</link>
		<comments>http://www.datasalt.es/2013/01/presentando-splout-sql-un-conector-sql-de-muy-baja-latencia-para-hadoop/#comments</comments>
		<pubDate>Thu, 17 Jan 2013 11:55:22 +0000</pubDate>
		<dc:creator>Pere Ferrera Bertran</dc:creator>
				<category><![CDATA[Datasalt]]></category>

		<guid isPermaLink="false">http://www.datasalt.es/?p=1634</guid>
		<description><![CDATA[<p>Hemos estado trabajando duro los últimos meses preparando el lanzamiento de lo que pensamos es una solución nueva para servir grandes candidades de datos. Hemos cogido ideas de proyectos como Voldemort o ElephantDB para devolver SQL al mundo del servicio Big Data de baja latencia. Motivación La motivación para haber creado Splout SQL está bien ...</p><p>Entrada original en: <a href="http://www.datasalt.es/2013/01/presentando-splout-sql-un-conector-sql-de-muy-baja-latencia-para-hadoop/">Presentando Splout SQL: Un conector SQL de muy baja latencia para Hadoop</a></p>]]></description>
				<content:encoded><![CDATA[<p>Hemos estado trabajando duro los últimos meses preparando el lanzamiento de lo que pensamos es una solución nueva para servir grandes candidades de datos. Hemos cogido ideas de proyectos como <a href="http://www.project-voldemort.com/voldemort/" target="_blank">Voldemort</a> o <a href="https://github.com/nathanmarz/elephantdb" target="_blank">ElephantDB</a> para devolver SQL al mundo del servicio Big Data de baja latencia.</p>
<h2>Motivación</h2>
<p>La motivación para haber creado Splout SQL está <a href="http://www.datasalt.es/2012/10/una-nueva-caneria-para-servir-grandes-cantidades-de-datos/" target="_blank">bien explicada en este post</a>.</p>
<h2>Los principios de Splout SQL</h2>
<p>Splout SQL es una base de datos <strong>escalable, tolerante a fallos, de sólo lectura, particionado, RESTful y SQL</strong> que se integra muy bien con <strong>Hadoop</strong>. Splout SQL se puede usar para ejecutar queries sobre datasets generados por Hadoop bajo alta carga, en tiempos de respuesta muy bajos. Ésto significa que Splout SQL es adecuado para escenarios como aplicaciones web o móviles que requieren un alto rendimiento. Por ejemplo, hemos usado Splout para servir 350GB de datos de los &#8220;<a title="Wikipedia Pagecounts" href="http://dumps.wikimedia.org/other/pagecounts-raw/" target="_blank">Wikipedia Pagecounts</a>&#8220;, ejecutando agrupaciones arbitrarias en tiempo real sobre ellos (<a title="Splout SQL's performance" href="http://sploutsql.com/performance.html" target="_blank">ver el benchmark para más detalle</a>).</p>
<p><center><img alt="" src="http://sploutsql.com/img/bench_4_time.png" width="499" /></center></p>
<p>La integración con Hadoop sigue los mismos principios de diseño que la de Elephant DB (que están muy bien explicados en <a title="Elephant DB slides" href="http://www.slideshare.net/nathanmarz/elephantdb" target="_blank">éstas transparencias</a>). A modo de resumen, los datos son <strong>indexados y particionados</strong> &#8220;offline&#8221; en un clúster Hadoop. Las estructuras de datos generadas son entonces movidas a un <strong>clúster de servicio de sólo lectura</strong>, que es el que atiende las queries de los usuarios.</p>
<p><span id="more-1634"></span></p>
<p>Elephant DB hace algo parecido. Voldemort <a href="http://static.usenix.org/events/fast12/tech/full_papers/Sumbaly.pdf" target="_blank">también</a>. Inspirados por ellos, hemos recopilado conceptos como &#8220;hot-swapping&#8221;, &#8220;rollback&#8221;, versiones (&#8220;domains&#8221; / &#8220;stores&#8221; / &#8220;tablespaces&#8221;) en una <strong>API sencilla y fácil de usar</strong> para desplegar datos de servicio en modo de sólo lectura.</p>
<p>Pero Splout puede crear<strong> tablas arbitrarias con B-Trees</strong>, ofreciendo una vista <strong>SQL</strong> real sobre el dataset final. Por lo tanto Splout SQL es una extensión más rica y potente que las bases de datos &#8220;llave / valor&#8221; que hemos mencionado antes, ya que permite <strong>agregaciones SQL en tiempo real arbitrarias</strong> sobre las vistas generadas.</p>
<h2>Cómo funciona</h2>
<p>Las estructuras de datos necesarias para contestar queries son generadas usando los métodos y programas de &#8220;splout-hadoop&#8221;. Ésta API usa <a title="Pangool" href="http://pangool.net/" target="_blank">Pangool</a> para ejecutar un proceso batch que calcula la distribución de los datos y los indexa. Los ficheros de datos generados no son más que <a title="SQLite" href="http://www.sqlite.org/" target="_blank">ficheros binarios SQLite</a> y se guardan en el HDFS o cualquier otro sistema de ficheros compatible con Hadoop (por ejemplo S3). Éstos ficheros entonces son descargados desde un clúster diferente, el de servicio, que ejecuta los servicios de Splout SQL, bajo una petición de &#8220;deploy&#8221;. Éste deploy distribuído y asíncrono es coordinado por <a href="http://hazelcast.com/">Hazelcast</a> hasta que triunfa o falla.</p>
<p>En el lado del servicio, las queries de los usuarios son enrutadas a través de un servicio llamado &#8220;QNode&#8221;, que conoce la distribución de los datasets que sirve. Los servicios &#8220;DNode&#8221; son los que tienen los ficheros SQL, contestan las queries y mandan el resultado hacia arriba. El resultado de la query es finalmente devuelto al usuario como un JSON a través de una interfaz HTTP.</p>
<p><center><img alt="" src="http://sploutsql.com/img/Splout_SQL.jpg" width="357" /></center></p>
<p>Éstas son algunas de las peculiaridades del sistema:</p>
<ul>
<li>El sistema es capaz de distribuír los datos de forma equitativa a sus &#8220;shards&#8221; usando técnicas de sampleo (como la que se usa en el <a href="http://hadoop.apache.org/docs/current/api/org/apache/hadoop/examples/terasort/package-summary.html" target="_blank">TeraSort</a> o bien algoritmos más sofisticados como <a href="http://en.wikipedia.org/wiki/Reservoir_sampling" target="_blank">Reservoir Sampling</a>).</li>
<li>Para poder samplear y distribuír los datos debe haber algún tipo de &#8220;<strong>llave de particionamiento</strong>&#8220;. En Splout, los datasets pueden ser particionados por <b>cualquier función aplicable a una fila de datos</b>. Normalmente ésto será una o varias columnas del conjunto de datos. Esta función permite al proceso de sampleo determinar el histograma de los datos y <strong>distribuírlos equitativamente sobre el número de particiones deseado</strong>.</li>
<li>Las queries siempre van a una única partición, así que el usuario debe proveer la &#8220;llave de particionamiento&#8221; para cada query. Esta llave debe ser, por supuesto, consistente con la función de particionado provista anteriormente. (Esto es lo mismo que dar una &#8220;llave&#8221; para obtener un &#8220;valor&#8221; en una base de datos &#8220;llave / valor&#8221;, sólo que en este caso obtenemos el resultado de una query SQL como valor).</li>
<li>Se obtiene <strong>&#8220;fail-over&#8221;</strong> en el sistema a través de un mecanismo sencillo de replicación: cada partición se copia a múltiples DNodes para que así, si uno de ellos cae, los otros pueden todavía servir esa partición.</li>
<li>El usuario puede crear cualquier número de <strong>tablas</strong> dentro de <strong>&#8220;tablespaces&#8221;</strong>, y desplegar un número arbitrario de tablespaces a la vez. Las tablas pueden ser <strong>particionadas</strong> o <strong>replicadas a todas las particiones</strong> (por ejemplo, tablas pequeñas que pueden ser replicadas en cada partición para así poder ejecutar joins con ellas).</li>
<li>Los &#8220;deploys&#8221; son <strong>atómicos y no afectan el servicio de las queries</strong>, así que el sistema como conjunto es bastante robusto, y a la vez sencillo y flexible. Además, el usuario puede volver a versiones anteriores de los datos desplegados de forma atómica también (&#8220;rollback&#8221;).</li>
</ul>
<h2>Splout SQL en el espacio &#8220;Big Data&#8221;</h2>
<p>Hemos diseñado Splout SQL para cubrir un hueco en el espacio &#8220;Big Data&#8221;. Pensamos que Splout es el mejor candidato a ser la &#8220;Batch Layer&#8221; de la &#8220;<a href="http://www.dzone.com/links/r/big_data_lambda_architecture.html" target="_blank">Lambda architecture</a>&#8220;.</p>
<p>Splout SQL se integra bien con Hadoop, puede contestar queries a muy baja latencia y está preparado para servir datos que exceden en mucho la memoria RAM disponible, como Voldemort o Elephant DB, pero ofrece agregaciones SQL en tiempo real en vez de ser una simple base de datos &#8220;llave / valor&#8221;.</p>
<p>Por otro lado, las bases de datos NoSQL como <a href="http://www.mongodb.org/" target="_blank">MongoDB</a>, <a href="http://cassandra.apache.org/" target="_blank">Cassandra</a> y <a href="http://hbase.apache.org/" target="_blank">HBase</a>, a pesar de no ser SQL, ofrecen un gran abanico de &#8220;features&#8221;, pueden ser usadas junto con Hadoop y parecería que comparten muchos de los objetivos de Splout SQL. Sin embargo, son sistemas mucho más complicados de manejar y usar. Y que sepamos, en el momento en que escribimos este documento, ninguno de ellos provée un puente con Hadoop que sea 1) fácil de usar y manejar 2) que no afecte el servicio de los datos 3) que sea atómico y ofrezca la posibilidad de &#8220;rollback&#8221;.</p>
<p>Finalmente, hay un conjunto de sistemas de &#8220;analítica rápida&#8221; que están surgiendo por encima de Hadoop que son capaces de contestar queries SQL (<a href="http://blog.cloudera.com/blog/2012/10/cloudera-impala-real-time-queries-in-apache-hadoop-for-real/" target="_blank">Impala</a>, <a href="http://wiki.apache.org/incubator/DrillProposal" target="_blank">Apache Drill</a>). Pero, que sepamos, han sido concebidos para ser usados &#8220;offline&#8221;, en aplicaciones de analítica. No han sido pensados para soportar entornos con alta carga, mucho tráfico, ni para devolver queries en muy bajas latencias (por debajo del segundo siempre). Lo que hacen es que aprovechan técnicas como el almacenamiento columnar para poder escanear muchos datos muy rápidamente (en el orden de los segundos), pero no tienen estructuras de datos como B-Trees para poder acceder a cualquier parte del dataset muy rápidamente (en el orden de los milisegundos). Así que, en general, son adecuados para unas cuantas queries que analizan todo el conjunto de datos, mientras que Splout es más bien adecuado para muchas queries que impactan porciones muy pequeñas del conjunto de datos.</p>
<h2>Pruébalo!</h2>
<p>Splout todavía no es 1.0 pero nos gustaría que lo probaras y nos dieras feedback, así que ¡<a href="http://sploutsql.com" target="_blank">dale</a>!</p>
<p>Entrada original en: <a href="http://www.datasalt.es/2013/01/presentando-splout-sql-un-conector-sql-de-muy-baja-latencia-para-hadoop/">Presentando Splout SQL: Un conector SQL de muy baja latencia para Hadoop</a></p>]]></content:encoded>
			<wfw:commentRss>http://www.datasalt.es/2013/01/presentando-splout-sql-un-conector-sql-de-muy-baja-latencia-para-hadoop/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tuple MapReduce en el IEEE ICDM 2014</title>
		<link>http://www.datasalt.es/2012/12/tuple-mapreduce-en-el-ieee-icdm-2014/</link>
		<comments>http://www.datasalt.es/2012/12/tuple-mapreduce-en-el-ieee-icdm-2014/#comments</comments>
		<pubDate>Tue, 18 Dec 2012 18:53:45 +0000</pubDate>
		<dc:creator>Iván de Prado Alonso</dc:creator>
				<category><![CDATA[Datasalt]]></category>

		<guid isPermaLink="false">http://www.datasalt.es/?p=1629</guid>
		<description><![CDATA[<p>Datasalt estuvo presentando el documento de investigación Tuple MapReduce, beyond classic MapReduce en la Conferencia Internacional de Data Mining del IEEE en diciembre. Es un placer para nosotros el compartir las siguiente presentación usada en las conferencias: Tuple map reduce: beyond classic mapreduce from datasalt</p><p>Entrada original en: <a href="http://www.datasalt.es/2012/12/tuple-mapreduce-en-el-ieee-icdm-2014/">Tuple MapReduce en el IEEE ICDM 2014</a></p>]]></description>
				<content:encoded><![CDATA[<p>Datasalt estuvo presentando el documento de investigación <a href="http://pangool.net/TupleMapReduce.pdf">Tuple MapReduce, beyond classic MapReduce</a> en la <a href="http://icdm2012.ua.ac.be/">Conferencia Internacional de Data Mining del IEEE</a> en diciembre. </p>
<p>Es un placer para nosotros el compartir las siguiente presentación usada en las conferencias:</p>
<p><iframe src="http://www.slideshare.net/slideshow/embed_code/15688639" width="512" height="421" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC;border-width:1px 1px 0;margin-bottom:5px" allowfullscreen webkitallowfullscreen mozallowfullscreen> </iframe>
<div style="margin-bottom:5px"> <strong> <a href="http://www.slideshare.net/datasalt/tuple-map-reduce-beyond-classic-mapreduce" title="Tuple map reduce: beyond classic mapreduce" target="_blank">Tuple map reduce: beyond classic mapreduce</a> </strong> from <strong><a href="http://www.slideshare.net/datasalt" target="_blank">datasalt</a></strong> </div>
<p>Entrada original en: <a href="http://www.datasalt.es/2012/12/tuple-mapreduce-en-el-ieee-icdm-2014/">Tuple MapReduce en el IEEE ICDM 2014</a></p>]]></content:encoded>
			<wfw:commentRss>http://www.datasalt.es/2012/12/tuple-mapreduce-en-el-ieee-icdm-2014/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Casos de uso reales de MapReduce y Hadoop</title>
		<link>http://www.datasalt.es/2012/12/casos-de-uso-reales-de-mapreduce-y-hadoop/</link>
		<comments>http://www.datasalt.es/2012/12/casos-de-uso-reales-de-mapreduce-y-hadoop/#comments</comments>
		<pubDate>Tue, 18 Dec 2012 18:53:15 +0000</pubDate>
		<dc:creator>Iván de Prado Alonso</dc:creator>
				<category><![CDATA[Datasalt]]></category>

		<guid isPermaLink="false">http://www.datasalt.es/?p=1627</guid>
		<description><![CDATA[<p>Datasalt fue invitada a dar una charla en la Universidad de Ginebra el pasado Octubre sobre MapReduce, Tuple MapReduce y casos de usos reales de MapReduce. La siguiente presentación contiene una introducción sobre el Big Data y más específicamente sobre MapReduce. Posteriormente, se describen casos de usos donde MapReduce ha demostrado su utilidad y finalmente ...</p><p>Entrada original en: <a href="http://www.datasalt.es/2012/12/casos-de-uso-reales-de-mapreduce-y-hadoop/">Casos de uso reales de MapReduce y Hadoop</a></p>]]></description>
				<content:encoded><![CDATA[<p>Datasalt fue invitada a dar una charla en la Universidad de Ginebra el pasado Octubre sobre MapReduce, <a href="http://www.datasalt.es/2012/02/tuplemapreduce/">Tuple MapReduce</a> y casos de usos reales de MapReduce.</p>
<p>La siguiente presentación contiene una introducción sobre el Big Data y más específicamente sobre MapReduce. Posteriormente, se describen casos de usos donde MapReduce ha demostrado su utilidad y finalmente se presenta el nuevo paradigma Tuple MapReduce y su implementación en Hadoop: <a href="http://pangool.net">Pangool</a></p>
<p>Los casos de uso reales de MapReduce son los siguientes:</p>
<ul>
<li>Data analytics</li>
<li>Crawling</li>
<li>Full-text indexing</li>
<li>Reputation systems</li>
<li>Data mining</li>
</ul>
<p><iframe src="http://www.slideshare.net/slideshow/embed_code/15688558" width="512" height="421" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC;border-width:1px 1px 0;margin-bottom:5px" allowfullscreen webkitallowfullscreen mozallowfullscreen> </iframe>
<div style="margin-bottom:5px"> <strong> <a href="http://www.slideshare.net/datasalt/big-data-map-reduce-and-beyond" title="Big data, map reduce and beyond" target="_blank">Big data, map reduce and beyond</a> </strong> from <strong><a href="http://www.slideshare.net/datasalt" target="_blank">datasalt</a></strong> </div>
<p>Entrada original en: <a href="http://www.datasalt.es/2012/12/casos-de-uso-reales-de-mapreduce-y-hadoop/">Casos de uso reales de MapReduce y Hadoop</a></p>]]></content:encoded>
			<wfw:commentRss>http://www.datasalt.es/2012/12/casos-de-uso-reales-de-mapreduce-y-hadoop/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Extracción de valor de transacciones con tarjeta de crédito</title>
		<link>http://www.datasalt.es/2012/12/extraccion-de-valor-de-transacciones-con-tarjeta-de-credito/</link>
		<comments>http://www.datasalt.es/2012/12/extraccion-de-valor-de-transacciones-con-tarjeta-de-credito/#comments</comments>
		<pubDate>Tue, 04 Dec 2012 18:21:14 +0000</pubDate>
		<dc:creator>Iván de Prado Alonso</dc:creator>
				<category><![CDATA[Datasalt]]></category>

		<guid isPermaLink="false">http://www.datasalt.es/?p=1620</guid>
		<description><![CDATA[<p>Ya está colgado el vídeo con la presentación que hicimos en Big Data Spain sobre como extraer valor de transacciones con tarjeta de crédito usando Hadoop y sus tecnologías. Aquí tenéis las transparencias disponibles para que lo veáis con más detalle.</p><p>Entrada original en: <a href="http://www.datasalt.es/2012/12/extraccion-de-valor-de-transacciones-con-tarjeta-de-credito/">Extracción de valor de transacciones con tarjeta de crédito</a></p>]]></description>
				<content:encoded><![CDATA[<p>Ya está colgado el vídeo con la presentación que hicimos en <a href="http://www.bigdataspain.org/">Big Data Spain</a> sobre como extraer valor de transacciones con tarjeta de crédito usando Hadoop y sus tecnologías.</p>
<p><iframe width="560" height="315" src="http://www.youtube.com/embed/-YSmJabKO5g" frameborder="0" allowfullscreen></iframe></p>
<p><a href="http://www.datasalt.es/clientes/bbva-caso-de-estudio/">Aquí tenéis las transparencias</a> disponibles para que lo veáis con más detalle. </p>
<p>Entrada original en: <a href="http://www.datasalt.es/2012/12/extraccion-de-valor-de-transacciones-con-tarjeta-de-credito/">Extracción de valor de transacciones con tarjeta de crédito</a></p>]]></content:encoded>
			<wfw:commentRss>http://www.datasalt.es/2012/12/extraccion-de-valor-de-transacciones-con-tarjeta-de-credito/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
