czwartek, 4 czerwca 2015

Introduction to Big Data with Apache Spark - Week 1

Jeśli ktoś jeszcze nie zauważył to na edx.org rozpoczął się właśnie kurs : "BerkeleyX: CS100.1x Introduction to Big Data with Apache Spark". W kursie używają głównie pythona a ja tutaj postaram się opisać jak można chociaż część ćwiczeń zrobić w scali.

W trakcie pierwszego tygodnia poza ćwiczeniami było trochę o profilach osób mieniących się "Data Scientist" jak i "Data Engineer" i cóż ci ludzie robią. Część praktyczna na razie polegała na instalacji virtualboxa i vagranta - a następnie odpaleniu kilku prostych przykładów sparka na gotowym obrazie. Na forum 90% pytań to problemy posiadaczy windowsa z instalacją obydwu wspomnianych narzędzi. Pomyślałem sobie, że to fajnie iż robię te ćwiczenia na linuxie - potem zdałem sobie sprawę, że 40 godzin w tygodniu pracuję na windowsie, usiadłem i zacząłem płakać...choć nie, nie zacząłem bo od razu przeszedłem do robienia ćwiczeń.

Najpierw teoria - Lekcja 1

Opisywanie tego co się usłyszało w celu zrelacjonowania tego dalej to dobry sposób by informacje zwyczajnie nie przeleciały przez głowę i upadły po drugiej stronie na podłogę.

Najpierw było kilka ciekawych rzeczy odnośnie interpretacji danych a konkretniej błędów przy tejże czynności popełnianych - i jest jedna fajna życiowa rzecz, która doczekała się nawet swojej strony na wiki - http://en.wikipedia.org/wiki/Correlation_does_not_imply_causation

To jest tak zabawny efekt, ze jeszcze jeden obrazek z netu :
I Dilbert - a jak jest dilbert to wiadomo, ze zaraz będzie coś o korpo :

Na kursie był wspomniany przykład badania Seven Countries Study - które zrodziło mit o powiązaniu ilość spożywanego tłuszczu z prawdopodobieństwem ataku serca. W linku można sobie poczytać o badaniu i krytyce oraz zapamiętać by ograniczyć spożycie cukrów prostych.

Są dwa zabawne przypadki o których słyszałem w kontekście tego efektu - pierwszy to pozorna zależność pomiędzy zamieszkaniem w okolicy linii wysokiego napięcia a śmiertelnością. Generalnie to działa na wyobraźnię bo prąd, magnetyzm i ciało ludzkie itd, no i liczby nie kłamią przecież - liczby nie kłamią ale ludzi ich nie rozumieją - bo co się okazało. Po dalszych badaniach wyszło na jaw, ze generalnie ludzie nie chcą mieszkać w okolicy linii wysokiego napięcia i działki są tam tańsze, i kupują je biedniejsi ludzie, którzy żyją mniej zdrowiej niż średnia populacji, i większe jest wśród nich umieralność...

Zaś drugi przykład jest związany z czymś coś co się nazywa "regresja do średniej" i tutaj dwa linki

To był dosyć ciekawy przykład z książki Thinking fast and slow albo z Black Swan. Był tam opisany przypadek Kapitana lotnictwa, który zauważył, ze zawsze gdy skuteczność pilotów spada i dostaną opierdol to się poprawia. Natomiast gdy jest dobrze i dostaną pochwałę to się pogarsza. No to przestał ich chwalić i tylko opierdalał. I coś w dłuższym okresie czasu morale siadło.

Kahneman próbował im wytłumaczyć, że skuteczność po doskonałych dniach by się pogarszała tak czy inaczej nawet bez pochwał a poprawiała bo bardzo słabych dniach nawet bez opierdolu. Nie dochodziło to do kapitana, więc zrobili pewien eksperyment. Narysowali kółko i kazali rzucać kapitanowi monetami doń tak by wycelować najbliżej środka. Zrobili dwa warianty - jeden z opierdalaniem a drugi bez - dużej różnicy nie było. To w sumie tak jakby opierdolić generator Radom.nextInt jak wygeneruje mała liczbę i pokazywać palcem, że podziałało jak wygeneruje za chwilę dużą liczbę.

Niebezpieczeństwo

Jeszcze gorsze od olewania liczb jest fanatyczna w nie wiara bez uwzględniania kontekstu ludzkiego - tzw technokracja. Kolega kolegi opowiadał o przypadkach, gdzie ludzie wydawali osądy wyssanez palca na podstawie liczenia średniej ważonej z burndown charta - programiści szybko się do tego dostosowują i potrafią kosztem produktywności (i co gorsza kosztem kultury pragmatyzmu) wygenerować odpowiedni wykres dla managerów. Ci którzy starają się kulturalnie zwrócić uwagę, ze to bez sensu i ogólnie firma na tym traci a zyskuje jedynie manager dostają etykiete kłótliwych -, że tak podobno jest powiedział mi kolega kolegi od strony stryjka.

Hippo

Czyli “HiPPO”—the highest-paid person’s opinion", a "highest-paid person’s" to ta osoba od której wymagane jest zgadywanie odnośnie przyszłości - tak twierdzą autorzy kursu jakkolwiek nie używają słowa "dupy" ani "stzrelanie".

Google jako wyrocznia

Naukowcy z Princeton dokonali analizy zapytań z google i stwierdzili, ze do 2020 nikt nie będzie używał już facebooka gdyż podobny trend zdążył się w przypadku myspace. Naukowcy z facebooka dokonali analizy danych z googla i stwierdzili, ze do 2020 nie będzie Princeton - ale to nie jest najstraszniejsze. Według tej samej procedury badawczej do 2060 nie będzie na ziemi powietrza!!

I fajny link jeszcze :
Fajny Link

lesson 2

Było o tym, ze dane trzeba przygotować, przefiltrować, że rzeczywistość dookoła nam nie będzie ładnie podawać informacji ale trzeba będzie je oszlifować i bez odpowiedniej technologii się zer.. nie uda się.

Było o Data Science i, że ludzie się ogólnie do tego nie nadają - "It is human nature to make assumptions ", "Humans have biases based on prior observations"

Dobra pogadali a teraz konkrety L

PROGRAMOWANIE

Generalnie polecam "Spark in action" nawet jak to jest Meap na razie bo tam jest konkretna praktyka z instalacją i komendami na linuxie. A jak fajnie, że ja mam linuxa...chociaż zaraz...

Najpierw byłą instalacja VirtualBoxa i Vagranta - zajebisty zestaw na prowadzenie warsztatów, trzeba będzie wypadać przy okazji. I od razu nauczka - na stronie downloadu są dwie opcje "i386" i "amd64" - i wcale nie jest tak, że ta pierwsza to intel a druga amd tylko pierwsza to 32bity a druga 64bity - czasem jednak warto czytać instrukcje bo jak odinstalowałem virtualboxa 32 bitowego to było późno i chyba za dużo komend ze strony przekleiłem bo przy okazji odinstalwoałem sobie Unity i zrobiło się jeszcze później.

W każdym razie po instalacji vagranta idzie "vagrant up" - zaciąga się obraz i możemy odpalić taki notebook, w którym można pisać w pythonie. Ale przecież chcielibyśmy też popisać w scali.

Popisać w scali

Wbijamy na spark REPL :
vagrant ssh
echo $SPARK_HOME // tak dowiemy sie gdzie jest spark
///usr/local/bin/spark-1.3.1-bin-hadoop2.6
cd /usr/local/bin/spark-1.3.1-bin-hadoop2.6
bin/spark-shell

//i mamy scalę !
//Using Scala version 2.10.4 (OpenJDK Client VM, Java 1.7.0_79)

Dziś przyjmiemy inną taktykę i zamiast śmiać się z innego jezyka - zobaczymy też co ciekawego w Pythonie. Bo jakoś ponoć to język Data Scientistów.

Jest taki repl online - Python : http://www.tutorialspoint.com/ipython_terminal_online.php i tam można sobie poeksperymentować. Na razie nauczyłem się, że (xrange(10)) - to chyba to samo co (0 until 10) w scali.

Python jest bardzo podobny do scali ale nie ma tam val,var i ogólnie typów. W niektórych środowiskach pracy to może być zaleta bo programiści mogą powiedzieć "przynajmniej nasz kod się uruchamia" (to żart oczywiście (chociaż nie, znam miejsca gdzie to nie będzie żartem))

Porównanie przykładów : Python ex1
# Check that Spark is working
largeRange = sc.parallelize(xrange(100000))
reduceTest = largeRange.reduce(lambda a, b: a + b)
filterReduceTest = largeRange.filter(lambda x: x % 7 == 0).sum()

# If the Spark jobs don't work properly these will raise an AssertionError
assert reduceTest == 4999950000
assert filterReduceTest == 714264285
Scala Ex1
val largeRange=sc.parallelize(0L until 100000L)
// largeRange: org.apache.spark.rdd.RDD[Long]

val reduceTest=largeRange.reduce(_+_)
//reduceTest: Long = 4999950000

val filterReduceTest=largeRange.filter(_ % 7==0).sum()
//filterReduceTest: Double = 7.14264285E8
Python ex2
# Check loading data with sc.textFile
import os.path
baseDir = os.path.join('data')
inputPath = os.path.join('cs100', 'lab1', 'shakespeare.txt')
fileName = os.path.join(baseDir, inputPath)

rawData = sc.textFile(fileName)
shakespeareCount = rawData.count()

print shakespeareCount

# If the text file didn't load properly an AssertionError will be raised
assert shakespeareCount == 122395
Scala Ex2
val homeDir=System.getProperty("user.home")
val path = (s"${homeDir}/data/cs100/lab1/shakespeare.txt")
path: String = /home/vagrant/data/cs100/lab1/shakespeare.txt
val rawData=sc.textFile(path)
val shakespeareCount=rawData.count
//shakespeareCount: Long = 122395
Python Ex3
# TEST Compare lists (2b)
# This should print '1 test passed.'
unsortedList = [(5, 'b'), (5, 'a'), (4, 'c'), (3, 'a')]
Test.assertEquals(sorted(unsortedList), [(3, 'a'), (4, 'c'), (5, 'a'), (5, 'b')],
                  'unsortedList does not sort properly')
Scala Ex3
val lista=List((5,'b'),(5,'a'),(4,'c'),(3,'a'))
lista.sorted == List((3,'a'),(4,'c'),(5,'a'),(5,'b'))
res3: Boolean = true

To tyle na pierwszy tydzień odnośnie wyżej wspomnianego kursu.

BONUS

Widać, że spark jest an topie bo hortonworks rzucił też wstęp do tutoriala "Data Science i Spark". Artykuł tutaj : http://hortonworks.com/blog/introduction-to-data-science-with-apache-spark/.

Jedyne ale to to, ze kurs jest przeznaczony dla platformy hortonworks, a że jej nie ma to poniżej dostosowanie ćwiczeń do już posiadanego obrazu vagranta ze sparkiem.

Najpierw jest tam instalacja ciekawej konsolki - https://github.com/apache/incubator-zeppelin ale to an kiedy indziej. Na razie trzeba wtgenerować sobie plik z logami do analizy.

W /usr/local/bin/spark-1.3.1-bin-hadoop2.6 wbijamy do katalogu conf

sudo mv  conf/log4j.properties.template conf/log4j.properties

#wrzucić to do log4j.properties
#file
log4j.rootCategory=INFO, console, file
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.target=System.err
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss} %p %c{1}: %m%n

# Settings to quiet third party logs that are too verbose
log4j.logger.org.eclipse.jetty=WARN
log4j.logger.org.eclipse.jetty.util.component.AbstractLifeCycle=ERROR
log4j.logger.org.apache.spark.repl.SparkIMain$exprTyper=INFO
log4j.logger.org.apache.spark.repl.SparkILoop$SparkILoopInterpreter=INFO

#file
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.File=/var/log/spark.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss} %p %c{1}: %m%n


sudo touch /var/log/spark.log
sudo chown vagrant /var/log/spark.log

Odpalić konsolę sparka ze scalą i jedziemy :

val sparkLogs=sc.textFile("/var/log/spark.log")

import sqlContext.implicits._
import java.text.SimpleDateFormat
import java.sql.Date

case class Log(level:String,date:Date,content:String)
val df=new SimpleDateFormat("yy/mm/dd HH:mm:dd")


val sparkFrame=sparkLogs.map {line =>
val s=line.split(" ")
val date=df.parse(s(0) + " " + s(1))
val logLevel=s(2)
val logContent=s(3)
Log(logLevel,new Date(date.getTime()),logContent)}.toDF()
sparkFrame.registerTempTable("spark")

I tutaj przyda się trochę znajomości REPLa jednak. Do tej pory to olewałem bo były worksheety w IDE. Są dwie dobre strony :

MOTYWACJA: - jednak jak coś jest potrzebne to się tego można nauczyć - tutaj najciekawsze polecenia to : :paste, :paste -raw, :history + :edit

I wio i błąd a na błędach się uczymy:

Caused by: ERROR XBM0H: Directory /usr/local/bin/spark-1.3.1-bin-hadoop2.6/metastore_db cannot be created.
Nie wiem czy poniższe rozwiązanie jest najlepsze bo nie jestem pełnoetatowym adminem :

vagrant@sparkvm:/usr/local/bin/spark-1.3.1-bin-hadoop2.6$ cd ..
vagrant@sparkvm:/usr/local/bin$ sudo chmod 775 spark-1.3.1-bin-hadoop2.6/
sudo chown vagrant spark-1.3.1-bin-hadoop2.6/

Jak już tu jesteśmy to zobaczmy co tam w tym metastore jest :

vagrant@sparkvm:/usr/local/bin/spark-1.3.1-bin-hadoop2.6/metastore_db$ ls -l
total 28
-rw-rw-r-- 1 vagrant vagrant  608 Jun  4 13:55 README_DO_NOT_TOUCH_FILES.txt
-rw-rw-r-- 1 vagrant vagrant   38 Jun  4 13:59 db.lck
-rw-rw-r-- 1 vagrant vagrant    4 Jun  4 13:59 dbex.lck
drwxrwxr-x 2 vagrant vagrant 4096 Jun  4 13:55 log
drwxrwxr-x 2 vagrant vagrant 4096 Jun  4 13:55 seg0
-rw-rw-r-- 1 vagrant vagrant  932 Jun  4 13:55 service.properties
drwxrwxr-x 2 vagrant vagrant 4096 Jun  4 13:59 tmp
vagrant@sparkvm:/usr/local/bin/spark-1.3.1-bin-hadoop2.6/metastore_db$ cat README_DO_NOT_TOUCH_FILES.txt 

# *************************************************************************
# ***              DO NOT TOUCH FILES IN THIS DIRECTORY!                ***
# *** FILES IN THIS DIRECTORY AND SUBDIRECTORIES CONSTITUTE A DERBY     ***
# *** DATABASE, WHICH INCLUDES THE DATA (USER AND SYSTEM) AND THE       ***
# *** FILES NECESSARY FOR DATABASE RECOVERY.                            ***
# *** EDITING, ADDING, OR DELETING ANY OF THESE FILES MAY CAUSE DATA    ***
# *** CORRUPTION AND LEAVE THE DATABASE IN A NON-RECOVERABLE STATE.     ***
# *************************************************************************

Nooo dobra to tyle. Kończymy zabawę w scali.

//TO jest tak lazy , ze dopiero po "show()" się wywala !
sparkFrame.groupBy("level").count().show()

/*
level count
WARN  6    
INFO  64 
*/

sqlContext.sql("SELECT level, count(1) from spark  group by level")
//res6: org.apache.spark.sql.DataFrame = [level: string, _c1: bigint]

sqlContext.sql("SELECT level, count(1) from spark  group by level").show
/*level _c1
WARN  6  
INFO  64 */


import org.apache.spark.sql.Row
 val result = sqlContext.sql("SELECT level, count(1) from spark  group by level").map {
 case Row(level: String, count: Long) => {
      level + "\t" + count
 }
}.collect()

println("%table Log Level\tCount\n" + result.mkString("\n"))
/* %table Log Level Count
WARN 6
INFO 64*/

To jest ciekawe bo DataFrame mówi do programisty "mów mi co trzeba zrobić nie mów jak i nie kontroluj" i wychodzi to lepiej. Czasem też warto zrobić sobie przerwę bo w ferworze pisania zacząłem zmieniać konfigurację log4j tutaj w tekście na blogu i dziwiłem się, że spark nie łyka tej konfiguracji... Czasem można spojrzeć na zieleń w celu uwolnienia umysłu. W poprzedniej pracy mieliśmy kalendarz ze zdjęciem fitneski - takiej miłej i uśmiechniętej, która promowała zdrowy tryb życia. I zawsze to podnosiło kreatywność zespołu ale przyszły korpo służby i kazały zdjąć kalendarz redukując naszą efektywność o 17,3%. Generalnie pomału mam wrażenie, że niektórzy mylnie używają słowa "profesjonalista" do opisu smutnego pana w wyprasowanej smutnej koszuli siedzącego w smutnym koncie smutnego piętra z gołymi i smutnymi ścianami. Ale zresztą ja się tam nie znam.

Za tydzień - lekcje 3 i 4 - ma już się zacząć jakieś datascience to powinno być ciekawie.

Brak komentarzy:

Prześlij komentarz