Skip to main content

Mutable Ideas

¿Por qué cambiar de Apache Hadoop a Apache Spark?

Esta charla describe la experiencia de Socialmetrix con más de un año usando Apache Spark en producción, las razones que nos llevaron al cambio de Hadoop+Hive a Spark y los hechos que tomamos en cuenta para soportaron la toma de esta decisión.

Hadoop to Spark

# Charla realizada en SUGAR - Scala User Group Argentina el 29/06/2015

{%raw%}

{%endraw%}

Apache Spark es un framework para procesamiento distribuído diseñado para ser amigable para Data-Scientists y programadores, con soporte nativo a muchos lenguajes y diversidad de formatos de datos es extramadamente flexible. Cambiando el modelo establecido por Hadoop v1 de Map-Reduce por un grafo de ejecución (DAG) y manteniendo los pasos intermédios en RAM, Spark brinda excelente performance y una API muy expresiva.

Gustavo Arjones, CTO de Socialmetrix, va contar la experiencia que tuvieron al cambiarse de Hadoop a Spark y lo que los llevaron a este cambio. Esta charla es una introducción teorica y practica a Spark y sus distintos componentes.

## Los tópicos a discutir son:

  • Qué és Apache Spark?
  • Aspectos que hacen Spark tan atractivo para la comunidad
  • Plataforma unificada para Data Science (Batch/Core, Streaming, Machine Learning, Graph Processing)
  • Soporte a distintos lenguajes (Scala, Java, Python, R)
  • Ejecución: RDD y DAG / Task Scheduller
  • Tracción de la comunidad (# commits, # commiters)
  • Testing, etc

## Demos:

  • Spark-shell: Explicar paso a paso el WordCount
  • SQL/DataFrames: Demostrar que se puede consumir directamente JSON y hacer queries con SQL
// Start spark-shell adding the class path to MySQL Connector
// SPARK_CLASSPATH=~/.ivy2/cache/mysql/mysql-connector-java/jars/mysql-connector-java-5.1.35.jar \
// spark-shell


// Creates an instance of SQL Context with Hive Support
val sqlContext = new org.apache.spark.sql.hive.HiveContext(sc)

// Read gziped textfile (json content) from local disk
// inspecting 10% (0.1) of its content to infer the Schema
val tweets = sqlContext.read.
  format("json").
  option("samplingRatio", "0.1").
  load("data/tweets-sample.json")

// Show some data
tweets.show
// Check the Schema infered
tweets.printSchema

// Project only `screen_name` and `followers_count` from
// and return each screen_name with their maximum number
// of followers
// This is the Dataframe sintax analogous to SQL:
//
// SELECT user.screen_name, MAX(user.followers_count) AS followers
// FROM tweets
// GROUP BY user.screen_name
//
val users = tweets.
  select("user.screen_name", "user.followers_count").
  groupBy("screen_name").
  agg(max("followers_count").as("followers"))
  
// Register temporarily this data-frame as Hive table 
// (it doesn't updates Hive Metastore) so we can
// use it in a SQL statement
users.registerTempTable("users")

// Connect to a MySQL Database and obtain the vip_users table
val vip = sqlContext.load("jdbc", Map(
  "url" -> "jdbc:mysql://localhost/demo?user=root&password=",
  "dbtable" -> "demo.vip_users"))

// Register temporarily this data-frame as Hive table 
vip.registerTempTable("vip")

// Run a JOIN between these datasets
val targetUsers = sqlContext.sql("""
SELECT users.screen_name, followers
FROM users INNER JOIN vip ON users.screen_name = vip.screen_name
ORDER BY followers DESC
""")

// Print the results
targetUsers.foreach(println)

// save to parquet format
targetUsers.write.format("parquet").save("users_to_contact")

## Result

$ ls -la users_to_contact/
total 68
drwxr-xr-x 20 arjones staff  680 Jul  1 03:30 .
drwxr-xr-x 15 arjones staff  510 Jul  1 03:30 ..
-rw-r--r--  1 arjones staff    8 Jul  1 03:30 ._SUCCESS.crc
-rw-r--r--  1 arjones staff   12 Jul  1 03:30 ._common_metadata.crc
-rw-r--r--  1 arjones staff   20 Jul  1 03:30 ._metadata.crc
-rw-r--r--  1 arjones staff   16 Jul  1 03:30 .part-r-00001.gz.parquet.crc
-rw-r--r--  1 arjones staff   16 Jul  1 03:30 .part-r-00002.gz.parquet.crc
-rw-r--r--  1 arjones staff   16 Jul  1 03:30 .part-r-00003.gz.parquet.crc
-rw-r--r--  1 arjones staff   16 Jul  1 03:30 .part-r-00004.gz.parquet.crc
-rw-r--r--  1 arjones staff   16 Jul  1 03:30 .part-r-00005.gz.parquet.crc
-rw-r--r--  1 arjones staff   12 Jul  1 03:30 .part-r-00006.gz.parquet.crc
-rw-r--r--  1 arjones staff    0 Jul  1 03:30 _SUCCESS
-rw-r--r--  1 arjones staff  306 Jul  1 03:30 _common_metadata
-rw-r--r--  1 arjones staff 1231 Jul  1 03:30 _metadata
-rw-r--r--  1 arjones staff  601 Jul  1 03:30 part-r-00001.gz.parquet
-rw-r--r--  1 arjones staff  596 Jul  1 03:30 part-r-00002.gz.parquet
-rw-r--r--  1 arjones staff  590 Jul  1 03:30 part-r-00003.gz.parquet
-rw-r--r--  1 arjones staff  590 Jul  1 03:30 part-r-00004.gz.parquet
-rw-r--r--  1 arjones staff  606 Jul  1 03:30 part-r-00005.gz.parquet
-rw-r--r--  1 arjones staff  306 Jul  1 03:30 part-r-00006.gz.parquet