¿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.
#
Charla realizada en SUGAR - Scala User Group Argentina el 29/06/2015
{%raw%}
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