Professional Documents
Culture Documents
Grbavac, Oliver
2021
Repository / Repozitorij:
Oliver Grbavac
DIPLOMSKI RAD
Varaždin, 2021.
SVEUČILIŠTE U ZAGREBU
VARAŽDIN
Oliver Grbavac
DIPLOMSKI RAD
Mentor/Mentorica:
Izjava o izvornosti
Izjavljujem da je moj završni/diplomski rad izvorni rezultat mojeg rada te da se u izradi istoga
nisam koristio drugim izvorima osim onima koji su u njemu navedeni. Za izradu rada su
korištene etički prikladne i prihvatljive metode i tehnike rada.
_______________________________________________________________________
Sažetak
Ključne riječi: Big Data, razvojni okviri, analiza, Apache Spark, Apache Flink
Sadržaj
1. Uvod ......................................................................................................................... 1
2. Veliki podaci (Big Data) ............................................................................................. 2
2.1. Analiza podataka u realnom vremenu ........................................................................... 2
2.2. Povijesni razvoj okvira za analizu podataka ................................................................... 3
3. Apache Spark ............................................................................................................ 4
3.1. Osnovni koncepti i arhitektura...................................................................................... 4
3.1.1. Spark klaster i sustav upravljanja resursima ................................................................................... 4
3.1.2. Spark aplikacija ................................................................................................................................ 5
3.1.3. Spark driver i izvršitelj ..................................................................................................................... 5
3.1.3.1. Hadoop distribuirani datotečni sustav (HDFS) i MapReduce ................................................. 6
3.1.4. Spark elementi ................................................................................................................................ 6
3.2. Otporni distribuirani skup podataka ............................................................................. 8
3.3. Primjer: Algoritam za prikaz i predikciju broja zaraženih i umrlih od koronavirusa u RH .. 9
3.3.1. Instalacija i konfiguracija Apache Spark-a ....................................................................................... 9
3.3.2. Određivanje putanje i kreiranje Spark konteksta .......................................................................... 13
3.3.3. Kreiranje SQL konteksta, učitavanje podataka .............................................................................. 14
3.3.4. Grafički prikaz umrlih, zaraženih i aktivnih slučajeva u RH ........................................................... 17
3.3.5. „Machine Learning“ algoritmi u Apache Sparku ........................................................................... 23
3.3.5.1. Linearna regresija ................................................................................................................ 24
3.3.5.2. Predikcija broja umrlih u RH pomoću linearne regresije ..................................................... 26
Iako u današnje vrijeme imamo tehnologiju koja može spremati velike količine podataka
te imamo već poznate algoritme za analizu i obradu podataka, međutim i dalje se javlja
problem skladištenja velike količine podataka, prijenosa podataka u realnom vremenu i
nestrukturiranosti podataka. Upravo iz navedenih razloga došlo je razvoja nove znanosti o
podacima (engl. Data science) kojoj je cilj iz velike sume podataka izvući korisne informacije i
znanje uz pomoću poznatih algoritama i drugih znanosti kao što su matematika, statistika,
strojno učenje, baze podataka i sl.
U ovom radu će biti opisana dva razvojna okruženja za analizu podataka Apache Spark
i Apache Flink. Prvo će teorijski biti objašnjeno kako funkcioniraju i od čega se sastoje ovih
razvojni alati, potom će kroz primjere biti objašnjen način rada navedenih razvojnih alata. Kroz
Apache Spark će biti objašnjen algoritam za strojno učenje, dok će kroz Apache Flink biti
prikazan algoritam za analizu podataka u realnom vremenu.
1
2. Veliki podaci (Big Data)
Pojam „Big Data“ teško je precizno i točno definirati, možemo reći da je to pojam koji
se odnosi na podatke i tehnologije za njihovu obradu. Glavne karakteristike koje posjeduju
veliki podaci se mogu opisati sa pojmom 3V (engl. Volume, Velocit, Varienty).
• Volumen – količina podataka je nemjerljiva, svaki dan kreira se novih 2,3 triliona
gigabajta, stoga, donja granica za volumen nije strogo definirana.
• Brzina – kako podaci pristižu velikom brzinom, tehnologije za rad s velikim
podacima moraju podržavati pohranu podataka i prikazivati rezultate u realnom
vremenu.
• Raznolikost – razlikujemo nekoliko tipova podataka, podaci mogu biti
strukturirani i nestrukturirani, te mogu nastati iz komunikacije čovjeka sa strojem
ili stroja sa strojem. („General Networks“, 2015.).
2
Slika 1. Količina podataka na društvenim mrežama koja se generira u jednoj minuti (Dayananda,
2019).
Kao prvi okvir za analizu veliki podataka javlja se Hadoop. Ovo je besplatan skup alata koji
za pohranu podataka koristi svoj sustav datoteka HDFS (Hadoop Distributed File System), a
za obradu podataka koristi Map-Reduce programski model. Za pohranu i spremanje podataka
se koristi Hadoop klaster. (Mali, 2020).
Drugi razvojni okvir za analizu podataka je Apache Spark koji se naslanja na Hadoop.
Spark se može pokretati na Hadoop klaster i može pristupiti Hadoop izvorima podataka.
Apache Spark proširuje Map-Reduce programski model tako što uključuje iterativne upite i
„Stream processing“ odnosno procesiranje podataka u realnom vremenu. Spark obrađuje
podatke 100 puta brže od Hadoop-a unutar memorije, a 10 puta brže na disku. (Mali, 2020).
Sljedeći u generaciji alata za analizu velikih podataka je Apache Flink. Flink je besplatan
alat koji služi za obradu podataka u realnom vremenu i nema svoj sustav za pohranu podataka
(najčešće koristi HDFS). Puno brže procesira podatke od Spark-a i Hadoop-a. Razvoj alata za
analizu velikih podataka najčešće možemo usporediti sa razvojem mobilnog interneta. Hadoop
je 2G, Spark je 3G, a Flink je 4G. (Mali, 2020).
3
3. Apache Spark
Kako bi razumjeli Spark i način kako on funkcionira potrebno je znati neke osnove pojmove
i elemente Sparka:
• Spark klaster
• Sustav upravljanja resursima
• Spark aplikacije
• Spark drivere
• Spark izvršitelje
U nastavku će biti objašnjeni svaki od navedenih elemenata.
4
Slika 2. Komunikacija Spark aplikacije i Cluster managera (Luu, 2018)
Spark aplikacija
Spark aplikaciju možemo podijeliti na dva dijela:
• Logika obrade podataka aplikacije
• Spark driver
Logika obrade podataka može biti neki jednostavan program ili može biti kompleksan
„machine learning“ model koji sadrži puno iteracija i koji se izvršava nekoliko sati. Spark driver
je središnji koordinator svake Spark aplikacije, on komunicira sa „Cluster manager-om“ kako
bi odredio na kojoj mašini će se izvršiti logika obrade podataka. Za svaku mašinu driver
zahtjeva od „Cluster manager-a“ da pokrene proces koji se naziva izvršitelj (engl. Executor).
Spark driver također upravlja i distribuira zadatcima na svakom izvršitelju. Ukoliko logika
obrade podataka zahtjeva ispis podataka za korisnika, tada će Spark driver u suradnji sa
izvršiteljima prikupiti i spojiti sve podatke kako bi driver mogao ispisati rezultate. Ulazna točka
u Spark aplikaciju je kroz klasu „SparkSession“ koja omogućava postavljanje konfiguracije i
API-a za izražavanje logike obrade podataka (Luu, 2018).
5
izvršitelji imaju zadatak spremanja podataka u memoriju ili disk kada je to zadano programskog
logikom (Luu, 2018).
Dva najvažnija podsustava ekosustava Hadoop su HDFS i MapReduce. Upravo ova dva
sustava omogućavaju paralelnu obradu podataka na više mašina unutar klastera.
HDFS je distribuirani datotečni sustav koji služi za pohranu velikih podataka na klasteru na
računalima generalne namjene. HDFS sustav je dizajniran tako da je otporan na pojavu greške
i kvar hardvera, upravo iz toga razloga se koristi hardver niskog budžeta. Ovaj sustav spreman
podatke tako da ih replicira na više računala unutar klastera, a podaci koji se zapišu jednom
mogu se čitati više puta i koristiti u raznim analizama. (White, 2010).
MapReduce je jednostavan programski model za obradu velikih podataka na klasteru
računala. Ovaj model omogućava paralelno računanje nad skupom podataka i upravo ovaj
model je omogućio razvoj i nastanak Apache Spark arhitekture. (White, 2010).
Spark elementi
Razlog zašto je Apache Spark brz i pouzdan alat za upravljanje velikom količinom
podataka su upravo njegovi elementi. Njegovi elementi su napravljeni da rješavaju sve
nedostatke koje je Hadoop MapReduce imao. Apache Spark se sastoji od sljedećih elemenata:
1. Jezgra (engl. Spark Core)
2. Spark Streaming
3. Spark SQL
6
4. GraphX
5. MLlib (Machine Learning)
Spark core
Spark core je osnovni mehanizam za obradu i distribuciju podataka. Sastoji se od dva dijela:
distribuirane računalne infrastrukture i otpornog skupa podataka (engl. Resilient Distributed
Datasets , kratica RDD).
Distribuirana računalna infrastruktura je zadužena za distribuciju, koordinaciju i raspored
računalnih zadataka na mašinama unutar klastera. Ona omogućava brzu i efikasnu te
paralelnu obradu velikog broja podataka na klaster mašinama. (Luu, 2018).
RDD (Resilient Distributed Datasets) će dodatno biti objašnjen u sljedećem poglavlju
Spark Streaming
Spark Streaming je komponenta koja se koristi za tok podataka koji nastaju u realnom vremenu
iz različitih izvora kao što su Twitter, tržišta dionica i sl. (Dayananda, 2019).
Spark SQL
Spark SQL komponenta omogućava rad sa strukturiranim podacima te podržava pisanje SQL
naredbi. Ova komponenta zapravo spaja relacijsku obradu podataka sa Spark programskim
sučeljem (Dayananda, 2019).
Spark GraphX
GraphX je komponenta koja omogućava kreiranje grafova s proizvoljnim vrijednostima na
bridovima i vrhovima. Također, GraphX biblioteka sadrži kolekciju usmjerenih grafova (Luu,
2018).
7
Spark MLlib
Spark MLlib datoteka sadrži više od 50 postupaka odnosno algoritama strojnog učenja.
Omogućava razne algoritme za strojno učenje, ali nudi i funkcionalnosti kao što su evaluacija
modela i učitavanje podataka (Luu, 2018).
Otporni distribuirani skup podataka (engl. Resilient distributed datasets, skraćeno RDD) je
nepromjenjiv, otporna na pogreške i paralelan skup podataka koji omogućava korisnicima da
spremaju rezultate u memoriju, kontroliraju raspodjelu podataka i manipuliraju njima pomoću
bogatog skupa operatora. (Luu, 2018).
RDD podržava dva tipa podataka:
• Transformacije – omogućavaju kreiranje novog skupa podataka od već postojećih.
• Akcije – vraćaju vrijednost driver programu nakon što naprave određene izračune
na skupu podataka („Apache Spark documentation“, bez dat.).
8
Glavna razlika između transformacije i akcije je ta da transformacija kreira novi skup
podataka, dok akcija bilježi ili piše rezultat određene radnje na disk. Druga bitna razlika je ta
što je evaluacija transformacije „lijena“ (engl. lazy evaluation), a razlog tome je velika količina
podataka. To zapravo znači da će Spark odgoditi evaluaciju pozvane operacije sve dok se ne
poduzme određena akcija. Operacija transformacije će zapamtiti transformacijsku logiku koju
će kasnije pozvati ili zapisati. Pozivanjem neke operacije akcije će automatski okinuti sve
transformacije koje su prethodno zapamćene i to će rezultirati vraćanjem određenih rezultata
driver programu ili zapisom podataka na nekom sustav za pohranu podataka kao što je HDFS
ili u neku lokalnu datoteku (Luu, 2018).
U nastavku će biti prikazan primjer aplikacije na kojoj ćemo vidjeti sve ranije navedene
mogućnosti i elemente Spark-a. Prvo ćemo učitati podatke iz izvora u ovom slučaju iz .JSON
datoteke koji sadrži podatke o trenutnom stanju broja zaraženih, aktivnih i umrlih slučajeva od
Covid-a 19 u Hrvatskoj. Potom ćemo srediti te podatke i na osnovu tih sređenih podataka
napraviti određenu analizu pomoću Apache Spark mehanizama. Kako nam Spark daje
mogućnost rada sa više programski jezika (Scala i Python), ovaj program je napisan u Python-
u.
Prvo je potrebno instalirati Javu (Java se besplatno može skinuti sa Oracle službene
https://www.oracle.com/java/technologies/javase-downloads.html). Nakon instalacije Jave
9
potrebno je instalirati Python, a najbolji način da se to napravi je skinuti Anacondu za
Windowse koja podržava Python. Razlog zašto to radimo preko Anaconde je „Jupyter
notebook“ pomoću kojeg ćemo pokretati aplikaciju. Tek kada smo sve to napravili potrebno je
instalirati Apache Spark, instalacijski paket možemo skinuti sa Apache Spark službene
stranice (https://spark.apache.org/). Nakon što instaliramo Spark potrebno je još skinuti i
instalirati Scala programski jezik, koji stavljamo na istu lokaciju kao i Apache Spark. Scalu
možemo skinuti sa sljedeće stranice https://spark.apache.org/. Zadnja stvar koju moramo
instalirati je „hadoop winutils“. Postupak instalacije svih navedenih aplikacija možete pronaći
na videu koji se nalazi u literaturi pod rednim brojem osam.
Nakon što smo skinuli i instalirati sve navedene aplikacije potrebno je u naprednim
postavkama Windows okruženja dodati nove varijable. Prvo odemo na postavke računala kao
na slici ispod.
10
Slika 6. Opcije unutar naprednih postavki u Windows10
Potom će nam se otvoriti sljedeći prozor u koje vidimo korisničke i sistemske varijable.
11
Slika 7. Dodavanje novih varijabli
Potrebno je dodati sljedeće varijable kako bi mogli pokrenuti Spark unutar Windows okruženja:
• HADOOP_HOME = C:\spark\hadoop
• JAVA_HOME = C:\Program Files\Java\jdk1.8.0_151
• SCALA_HOME = C:\spark\scala\bin
• SPARK_HOME = C:\spark\spark\bin
• PYSPARK_PYTHON = C:\Users\user\Anaconda3\envs\python.exe
• PYSPARK_DRIVER_PYTHON = C:\Users\user\Anaconda3\envs\Scripts\jupyter.exe
• PYSPARK_DRIVER_PYTHON_OPTS = notebook
Putanja do pojedinih aplikacija ne mora nužno biti ista te ukoliko ne koristimo aplikaciju Jupyter
posljednje dvije varijable nam nisu potrebne.
12
Slika 8. Spark verzija
conf = SparkConf().setAppName("Coronavirus")
conf = (conf.setMaster('local[2]')
.set('spark.executor.memory', '4G')
.set('spark.driver.memory', '45G')
.set('spark.driver.maxResultSize', '10G'))
sc = SparkContext.getOrCreate(conf=conf)
spark = SparkSession(sc)
13
Kreiranje SQL konteksta, učitavanje podataka
Kako bi mogli učitati određen skup podataka unutar Spark aplikacije, potrebno je kreirati
Spark SQL kontekst. SQL kontekst možemo kreirati upravo iz Spark konteksta kojeg smo
kreirali u prethodnom poglavlju. U programskom kodu ispod, osim kreiranja SQL konteksta,
možete vidjeti da su učitani podaci iz više .JSON datoteka. Svi podaci su preuzeti sa stranice
www.koronavirus.hr te su podaci jako dobro sređeni što nam omogućava lakšu manipulaciju
sa njima. Također u kodu ispod možete primijetiti da smo za svaku datoteku koju smo učitali
kreirali shemu. Prilikom učitavanja podataka prosljeđujemo tu shemu i tako kreiramo
DataFrame s određenim brojem stupaca i redova na kojima se mogu izvršavati deklarativni
upiti.
schema = StructType([
StructField("Datum", StringType(), True),
StructField("Zupanija", StringType(), True),
StructField("dob", IntegerType(), True),
StructField("spol", StringType(), True),
])
schema = StructType([
StructField("Datum", StringType(), True),
StructField("IzlijeceniHrvatska", IntegerType(), True),
StructField("IzlijeceniSvijet", IntegerType(), True),
14
StructField("SlucajeviHrvatska", IntegerType(), True),
StructField("SlucajeviSvijet", IntegerType(), True),
StructField("UmrliHrvatska", IntegerType(), True),
StructField("UmrliSvijet", IntegerType(), True),
])
15
Slika 10. Tablica Osobe
16
Slika 11. Tablica zaraženih Hrvatska
zupanije = zupanijeDf.registerTempTable("zupanije")
17
zarazeni = sqlContext.sql("select Zupanija, broj_zarazenih from zupanije
group by 1,2 order by 2")
zarazeni.collect()
x1=aktivni.toPandas()["Zupanija"].values.tolist()
y1=aktivni.toPandas()["broj_aktivni"].values.tolist()
z1=zarazeni.toPandas()["broj_zarazenih"].values.tolist()
d1=umrlih.toPandas()["broj_umrlih"].values.tolist()
U nastavku će biti prikazani prvo kod pomoću kojeg smo kreirali određene grafove, a nakon
koda će biti prikazani grafovi za broj aktivnih, zaraženi i umrlih slučajeva od koronavirusa u RH
poredano po županijama.
fig = plt.figure(figsize=(20,5))
ax1 = fig.add_subplot(1,2,1)
def autolabel(rects):
for rect in rects:
height = rect.get_height()
ax1.text(rect.get_x() + rect.get_width()/2., height,'%d' %
int(height), ha='center', va='bottom')
autolabel(rects1)
plt.savefig("Broj_aktivnih.png", dpi=300, bbox_inches='tight')
plt.show()
18
Slika 12. Broj aktivnih slučajeva u RH
fig = plt.figure(figsize=(20,5))
ax2 = fig.add_subplot(1,2,1)
rects2 = ax2.bar(x1, z1)
ax2.set_xticklabels(x1, rotation=60, horizontalalignment='right',
fontsize='12')
ax2.set_title("Broj zaraženih slučajeva po županijama")
ax2.set_ylabel('broj zarazenih')
def autolabel(rects):
for rect in rects:
height = rect.get_height()
ax2.text(rect.get_x() + rect.get_width()/2., height,'%d' %
int(height), ha='center', va='bottom')
autolabel(rects2)
plt.savefig("Broj_zarazenih.png", dpi=300, bbox_inches='tight')
19
plt.show()
fig1=plt.figure(figsize=(20,5))
ax3 = fig1.add_subplot(1,2,1)
def autolabel(rects):
for rect in rects:
height = rect.get_height()
ax3.text(rect.get_x() + rect.get_width()/2., height,'%d' %
int(height), ha='center', va='bottom')
20
autolabel(rects3)
plt.savefig("broj_umrlih.png", dpi=300, bbox_inches='tight')
plt.show()
osobe = osobeDf.registerTempTable("osobe")
spolM = sqlContext.sql("select count(spol) as Muski from osobe where spol
= 'M'")
spolZ = sqlContext.sql("select count(spol) as Zene from osobe where spol
= 'Ž'")
muski = spolM.toPandas()["Muski"].values.tolist()
zene= spolZ.toPandas()["Zene"].values.tolist()
#Pie
labels = "Muškarci", "Žene"
values = [muski,zene]
plt.pie(values, labels = labels, autopct='%1.1f%%', startangle=140)
21
plt.title("Postotak oboljelih prema spolu")
plt.axis('equal')
plt.savefig("broj_oboljelih prema spolu.png", dpi=300,
bbox_inches='tight')
plt.show()
mlad = mladi.toPandas()["Mladi"].values.tolist()
srednji = srednjadob.toPandas()["SrednjaDob"].values.tolist()
star = stari.toPandas()["Stari"].values.tolist()
22
plt.savefig("broj_oboljelih_prema_dobi.png", dpi=300,
bbox_inches='tight')
plt.show()
Pod Mladi spadaju svih mlađi od 25 godina, srednja dob podrazumijeva ljude između 25 i
50 godina, dok za stariju dob mislimo na sve ljude starije od 50 godina.
23
3.3.1.1. Linearna regresija
Regresijska analiza se sastoji od različitih metoda koje imaju za cilj ispitati ovisnost
jedne varijable o jednoj ili više drugih varijabli. Jedna od tih metoda je upravo Linearna
regresija. S obzirom na broj ulaznih i izlaznih varijabli razlikujemo više vrsta linearne regresije:
„Modelom jednostavne regresije analitički se izražava statistički odnos među dvjema pojavama
predočenima vrijednostima numeričkih varijabli. Model sadrži zavisnu i jednu nezavisnu
varijablu. Model jednostavne linearne regresije prikladan je za opisivanje pojava koje su u
linearnom statističkom odnosu. Primijenit će se u slučaju kada jediničnom povećanju
vrijednosti nezavisne varijable odgovara približno ista linearna promjena vrijednosti zavisne
varijable.“.
𝑌 = 𝑎 + 𝑏𝑋 + 𝑢
gdje je
X – nezavisna varijabla
Y = zavisna varijabla
a, b - parametri
𝑌𝑖 = 𝑎 + 𝑏𝑥𝑖 + 𝑢𝑖
Kada bi odnos među varijablama bio funkcionalan, svaka bi vrijednost varijable 𝑢𝑖 bila jednaka
nuli odnosno geometrijski, sve bi točke s koordinatama (𝑥𝑖 , 𝑦𝑖 ), i = 1,2,...,n ležale na istome
pravcu. (Šošić, 2004.)
24
Kako su odnosi među pojavama statistički, treba odrediti kriterij prema kojemu će se izabrati
jednadžba pravca ŷ = a + bx koja će ‘najbolje’ opisati odnos pojava na temelju njihovih
opaženih vrijednosti.
𝑢𝑖 = 𝑦𝑖 − ŷ𝑖
𝑦𝑖 − ŷ𝑖
𝑢𝑖,𝑟𝑒𝑙 = ∗ 100
𝑦𝑖
𝑛 𝑛 𝑛
1
𝜎ŷ = √ (∑ 𝑦𝑖2 − 𝑎 ∑ 𝑦𝑖 − 𝑏 ∑ 𝑥𝑖 𝑦𝑖 )
𝑛
𝑖=1 𝑖=1 𝑖=1
25
𝜎ŷ
𝑉ŷ = ∗ 100
𝑦̅
𝑎 ∑𝑛𝑖=1 𝑦𝑖 + 𝑏 ∑𝑛𝑖=1 𝑥𝑖 𝑦𝑖 − 𝑛 ∗ 𝑦̅ 2
𝑅2 = , 0 ≤ 𝑅2 ≤ 1
∑𝑛𝑖=1 𝑦𝑖2 − 𝑛 ∗ 𝑦̅ 2
Za kraj analize kreiran je algoritam koji pomoću linearne regresije računa predikciju
broja umrlih na osnovu 5 varijabli: broja zaraženih u svijetu, broja zaraženih u RH, broja umrlih
u svijetu, broj izliječenih u svijetu i broj izliječenih u RH. Svi podaci za testiranje ovog algoritma
su preuzeti iz sljedeće tablice:
Kako bi napravili predikciju prvo je potrebno odrediti zavisne i nezavisne varijable. Cilj
je izračunati predikciju za broj umrlih osoba u RH stoga kolonu „UmrlihHrvatska“ uzimamo kao
26
zavisnu varijablu. Varijabla „UmrlihHrvatska“ zapravo ovisi od drugih kolona unutar ove tablice
pa kao nezavisne varijable u ovom slučaju se mogu uzeti sve ostale kolone osim datuma. U
ovom primjeru imamo više ulaza, a samo jedan izlaz pa možemo zaključiti da se radi o
univarijatnoj (višestrukoj) linearnoj regresiji. Nezavisne varijable u ovom primjeru su:
„IzliječeniHrvatska“, „IzliječeniSvijet“, „SlučajeviHrvatska“, „SlučajeviSvijet“, „UmrliSvijet“, a
zavisna varijabla je „UmrlihHrvatska“.
Pomoću sljedećeg koda smo izvukli sve podatke iz gore navedene tablice, definirali
varijable i podijelili podatke na trening podatke i testne podatke:
coronaSvijet = svijetDf.registerTempTable("coronavirus")
data = sqlContext.sql("select * from coronavirus where SlucajeviSvijet >
0 order by 4")
data.collect()
data.show(15)
#data.printSchema()
#definiranje varijabli
assembler = VectorAssembler(inputCols = [
"IzlijeceniHrvatska","IzlijeceniSvijet",
"SlucajeviHrvatska", "SlucajeviSvijet",
"UmrliHrvatska","UmrliSvijet"], outputCol="varijable")
27
col("Datum"),col("varijable"),
(col("UmrliHrvatska").cast("Int").alias("UmrliHrvatska")))
#trainingDataFinal.show(truncate=False , n=50)
Model je napravljen tako da podijeli podatke na trening podatke i testne podatke. Algoritam 80
% podataka uzima kao trening podatke, a 20 % kao testne podatke pa zato imamo 259
nasumičnih redova koji su pripremili ovaj model, a 63 reda koji predviđaju stvarnu vrijednost.
Na tablici se pod kolonom „varijable“ nalaze sve nezavisne varijable, dok je kolona
„UmrlihStvarno“ zavisna varijabla.
Kada smo odredili varijable i podijelili podatke pomoću dolje navedenog koda pozovemo
funkciju „Linear regresion“ te pomoću naredbe „fit“ testiramo ovaj naše model, a zatim
usporedimo stvarne vrijednosti sa onim koje je algoritam predvidio.
28
testingDataFinal = assembler.transform(
testingData).select(
col("Datum"),col("varijable"),
(col("UmrliHrvatska")).cast("Int").alias("UmrlihStvarno"))
testingDataFinal.show(truncate=False, n=10)
Rezultat ove radnje je prikazan na slici ispod. Vidimo da predikcija ne odstupa puno od stvarnih
vrijednosti.
Iako možemo vidjeti da su rezultati predikcije dosta točni, potrebno je to provjeriti. Kako je
navedeno u prethodnom poglavlju pokazatelj reprezentativnosti modela možemo provjeriti
pomoću koeficijenta determinacije. Pomoću funkcije „RegressionEvaluator“ je izračunat
koeficijent determinacije.
#evaluator
evaluator = RegressionEvaluator(
labelCol="UmrlihStvarno", predictionCol="prediction",
metricName="r2")
#izračun koeficijenta determinacije
29
r2 = evaluator.evaluate(prediction)
print ("koeficijent determinacije R2= ", r2)
Dobijemo:
30
4. Apache Flink
Projekt Apache Flink je započeo u Berlinu 2009 godine te je tek nakon par godina
istraživanja odnosno u prosincu 2014 prihvaćen kao jedan od glavnih Apache projekata.
Glavna zadaća ovog programa je distribucija podataka uz visoku propusnost i nisku latenciju.
Podržava programsko sučelje za Java i Scala programske jezike.
Najpoznatija definicija Apache Flinka je upravo ona sa njihovih službenih stranica: „Apache
Flink je platforma otvorenog koda za distribuciju/raspodjelu/ distribuiranih tokova i podataka.
Jezgra Apache Flinka je mehanizam za strujanje podataka (data streaming) koji pruža
distribuciju podataka, komunikaciju i toleranciju grešaka za raspodijeljene proračune preko
protoka podataka. Flink gradi skupnu obradu na vrhu strujnog motora, preklapajući podršku
izvorne iteracije, upravlja memorijom i optimizira programe“. („Apache Flink documentation“,
bez dat.)
Slika 20. Apache Flink Ekosustav (Apache Flink Tutorial- Ecosystem Components, bez dat.)
31
Skladištenje (engl. Storage/Streaming)
Prema prezentaciji „Introduction to Apache Flink“ (Edureka, 2016) možemo reći da je Flink
zapravo jedini alat za obradu podataka koji nema sustav skladištenja. Dizajniran je tako da
može čitati i pisati podatke sa različitih sustava skladištenja. Nije bitno radi li se o datoteci,
skupu podataka ili nekim „streaming“ podatcima. Na slici 20 navedeni su neki sustavi
skladištenja sa koji Flink može čitati/pisati podatke:
32
ukoliko želimo raditi sa SQL upitima potrebno je uključiti „Table“ knjižicu u svoj program. Sve
navedene datotečne knjižnice sadrže algoritme i funkcije koje se mogu koristit u izradi
aplikacije. Također prilikom izrade aplikacije postoje dvije mogućnosti distribucije podataka. U
prvoj opciji podaci se obrađuju na nekom određenom skupu, taj skup je sastavljen od podataka
koji su prikupljeni u određenom vremenskom periodu, te je skup konačan. Ovaj tip procesiranja
i skupljanja podataka naziva se „Batch processing“ i još je jedna stvar karakteristična za njega,
skup podataka koji se analiza uvijek je negdje spremljen. Druga opcija je procesiranje
podataka u realnom vremenu, odnosno slanje i analiza podataka čim se podaci generiraju.
Ovaj tip prijenosa i analize podataka se naziva „Stream processing“. Prvi oblik nam omogućava
da prikupimo točne i sigurne podatke, ali druga opcija omogućava veću propusnost podataka,
ali često njihov sadržaj nije potpun. (Edureka, 2016)
Apache Flink kao i Apache Spark također podržava upravitelj – izvršitelj arhitekturu. Ova
arhitektura je najbolje vidljiva priliko pokretanja nekog Flink programa. Svaki Flink program
sastoji se od dva procesa: upravitelj (engl. master) i izvršitelj (engl. worker). Na sljedećoj slici
možemo vidjeti od koji procesa se sastoji pokretanje nekog Flink programa.
33
Kako se može vidjeti na slici postoje tri glavne uloge odnosno procesa koja sudjeluju u
pokretanju nekog Flink programa. Kada se program pokrene on automatski predaju radnju
„klijentu“ (engl. Job Client). Klijent ima ulogu proslijediti taj proces do „Voditelja poslova“ (engl.
Job Manager). Voditelj poslova provjerava koji „Upravitelj poslova“ (engl. Task Manager) ima
najviše resursa potrebnih za obavljanje određenog zadatka. Upravitelj poslova koji ima najviše
resursa će dobiti zadatak od Voditelja poslova. Nakon toga Upravitelj poslova inicira dretvu
koja pokreće program, osim toga Upravitelj šalje izvještaj ukoliko se status ove radnje
promjeni. Nakon što je radnja završena, rezultati se preko Voditelja poslova šalju nazad do
klijenta i time je proces pokretanja Flink programa završen. (Deshpande, 2017).
Ulogu „upravitelja“ u ovoj arhitekturi ima Voditelj poslova (engl. „Job Manager“). Ovaj
proces je zadužen za raspoređivanje zadataka, upravljanje greškama, kreiranja kontroli
točaka. Kako bi uspješno obavio sve navedene zadatke, ova proces ima tri glavne
komponente: sustav uloga, raspored i kontrolu točku. U svakom programu može biti više
Voditelja procesa, ali jedan je glavni. U slučaju da je on nedostupan, drugi preuzima njegovu
ulogu. (Deshpande, 2017).
Ulogu „izvršitelja“ u ovoj arhitekturi ima Upravitelj poslova (engl. „Task Manager“). On je
zadužen za pokretanje jednog ili više zadataka koje dobije od Voditelja poslova. Ovaj proces
se može podijeliti na „slotove“ (engl. slots) tako da recimo svaki slot dobije 25 % ukupno
alocirane memorije na nekom „Task manager-u“ što omogućava paralelno izvršavanje više
zadataka istovremeno. Bitno je napomenuti da svaki slot može pokrenuti jednu ili više dretvi.
(Deshpande, 2017).
Klijent zapravo ne spada u ovu arhitekturu i nije dio Flink programa priliko pokretanja, ali
od njega kreće ovaj proces i on je zadužen za prihvaćanje programa od korisnika i kreiranje
toka podataka. Nakon toga prosljeđuje podatke „Job Manager-u“ te je zadužen za prikazivanje
rezultata korisniku, nakon što je program završio. (Deshpande, 2017).
Kako smo ustanovili ranije Apache Flink je alat pomoću kojega možemo procesirati i
analizirati velike količine podataka u realnom vremenu. U nastavku će ukratko biti opisan
proces prijenosa podataka unutar Apache Flink okruženja. Kako bi proces prijenosa podataka
bio što jasniji prvo je potrebno definirati što je to zapravo tok ili prijenos podataka (engl.
DataStream).Tok ili prijenos podataka možemo definirati kao skup podataka koji može biti
konačan ili neograničen. Bitno je napomenuti da se podaci unutar ovog skupa ne mogu
mijenjati, ali se mogu prosljeđivati te se na njima se mogu raditi razne analize pomoću
34
„DataStream“ operacija unutar Flink-a, te operacije se još nazivaju i transformacije. Osnovne
transformacije za prijenos podataka unutar Flink okruženja su:
• Map – prima jedan element ili skup i rezultat ove operacije je jedan element ili skup.
• FlatMap - prima jedan element i vraća nula, jedan ili više elemenata.
• Filter – filtrira skup podataka i vraća samo one elemente koji zadovoljavaju uvjet
istinitosti.
• KeyBy - logički dijeli skup na dva dijela, elementi sa istim ključevima će biti svrstati
u isti grupu.
• Reduce – smanjiva skup tako što svaku novu vrijednost elementa uspoređuje sa
njegovom smanjenom vrijednosti te prikaže zadnju vrijednost.
• Aggregations – skupljanje podataka po određenim ključevima i kreiranje novog
skupa podataka.
• Window – grupira podatke prema određenim karakteristikama (npr. Svi podaci koji
su došli u zadnji 5 minuta).
• WindowAll - grupira podatke prema određenim karakteristikama (npr. Svi podaci
koji su došli u zadnji 5 minuta). Razlikuje se od Window transformacije po tome što
grupira sve podatke, dok Window transformacija grupira podatke koji su podijeljeni
odnosno samo jedan manji skup podataka. Zapravo to znači da će ova naredba u
programu doći prije KeyBy transformacije, a Window transformacija će doći poslije
KeyBy transformacije.
• Window Apply – primjenjuje generalnu funkciju na prozor (engl. Window) u cijelosti
• Window Reduce - primjenjuje „reduce“ funkciju na određeni prozor i vraća skup
sa reduciranim vrijednostima.
• Aggregations on windows - sakuplja sadržaj određenog prozora.
• Union – spaja dva ili više toka podataka i kreira novi skup koji sadrži sve podatke
iz oba toka.
• Window Join – spaja dva toka podataka prema određenom ključu u zajednički
prozor.
• Interval Join – povezuje dva elementa iz dva različita toka podataka preko
zajedničkog ključa u određenom vremenskom intervalu.
• Window CoGroup – grupira dva toka i to svaki prema zadanom ključu u zajednički
prozor.
• Connect – spaja dva toka podataka tako tokovi ne gube svoja svojstva. Ova
transformacija omogućava dijeljenje podataka između dva toka podataka.
• CoMap, CoFlatMap – slično kao map i flatMap na spojenom toku podataka.
35
• Iterate – kreira povratnu petlju tako što prosljeđuje rezultat jednog operatora na
neki stari postojeći operator. Ova transformacija je korisna za kreiranje algoritama
koji konstanto ažuriraju neki model. („Apache Flink documentation“, bez dat.)
36
• Globalni prozor (engl. Global Windows) – ovaj tip prozora dodjeljuje sve
elemente istog ključa u individualni „global window“. Uz ovaj tip prozora se koristi
okidač (engl. trigger) i nema kraj na koji možemo proslijediti agregirane elemente.
Okidač unutar Apache Flink programa određuje kada je window spreman za
procesiranje podataka. Pomoću sljedećih naredbi okidač određuje što uraditi sa
podatcima:
o CONTINUE – ne radi ništa,
o FIRE – napravi izračun,
o PURGE – izbriši sadržaj prozora,
o FIRE_AND_PURGE – napravi izračun i izbriši sadržaj prozora nakon toga.
Za brisanje sadržaja prozora koristi se „Evictor“ koji dolazi nakon naredbe okidača,
a prije ili poslije „window“ funkcije. („Apache Flink documentation“, bez dat.)
Svaki „streaming“ proces koji podržava vrijeme događaja mora imati način kako mjeriti
napredak vremena događaja. Mehanizam koji mjeri napredak vremena događaja unutar Flink
programa zove se vodeni žig (engl. „Watermark“). Vodeni žig mjeri koliko je vremena prošlo u
nekom „stream-u“. Recimo ako imamo neki prozor koji ima vrijeme trajanja od jedan sat Vodeni
37
žig će nam javiti kada je to vrijeme događaja isteklo i poslije toga taj prozor više neće primati
nove elemente. („Apache Flink documentation“, bez dat.)
Već smo ranije napomenuli da neki elementi dođu izvan reda odnosno da postoji određeno
kašnjenje prilikom prijenosa podataka. Elemente koji dođu nakon što je Vodeni žig označio
istek vremena nazivaju se Kasni elementi (engl. Late elements). Program neće odmah nužno
odbaciti te elemente zato što unutar Flink programa postoji mehanizam koji se zove
„Dozvoljeno kašnjenje“ (engl. Allowed lateness). Dozvoljeno kašnjenje je dopušteno
vremensko kašnjenje elemenata prije nego što elementi budu odbačeni. Početna vrijednosti
Dozvoljenog kašnjenja je nula, ali za svaki program se može odrediti kašnjenje po želji. Ukoliko
elementi dođu izvan tog vremena bit će odbačeni, ali ako dođu unutar tog vremena uzrokovat
će ponovo pokretanje prozora sa novim rezultatima. Kao izlaznu vrijednost dobit ćemo više
rezultata za isti izračun. („Apache Flink documentation“, bez dat.)
Tolerancija pogreške (engl. Fault tolerance) prilikom pogreške unutar Flink aplikacije
omogućava vratiti stanje kakvo je bilo prije same pogreške unutar programa. Otpornost na
pogrešnu unutar Flink programa omogućava kontrolna točka. Kontrolna točka (engl.
checkpointing) je neprestano snimanje distribuiranih tokova podataka. Svaki snimak čuva
stanje aplikacije u određenom vremenskom periodu. Ovi snimci stanja ne koriste puno resursa
i spremaju se na postojeće skladište, najčešće je to HDFS. („Apache Flink documentation“,
bez dat.)
38
5. Primjer: Algoritam za analizu Twitter podataka
unutar Apache Flink-a
U ovom primjeru će biti prikazano kako možemo povući podatke sa Twittera i na njima
napraviti analizu u realnom vremenu. Kako bismo ovo napravili potrebno je prvo kreirati
programerski Twitter račun koji nam omogućava „streaming“ podataka u našu aplikaciju. Cilj
same aplikacije će biti spremati statuse (engl. Twits) koje u sebi sadrže podatke o potresima
u svijetu. Unutar svakog statusa Twitter nam omogućava da vidimo sa kojeg je uređaja
odnosno operacijskog sustava status napisan. Upravo to će biti iskorišteno kako bi napravili
analizu sa koji uređaja dolazi najviše statusa. Ova analiza može pomoći programerima koji
žele kreirati neku aplikaciju, a nisu sigurni koji operacijski sustav je najbolji za tu aplikaciju.
Prije same instalacije bitno je napomenuti da Apache Flink najbolje radi na Linux
operacijskom sustavu, stoga ćemo u ovom primjeru instalirati Linux Ubuntu, na Virtualnoj
mašini, na koje će biti instaliran Apache Flink. Postupak instalacije Linux Ubuntu-a se nalazi u
poglavlju Dodaci.
Prvobitno je potrebno instalirati Javu. Za instalaciju Jave je potrebno skinuti zadnju stabilnu
verziju te unutar Linux terminala ukucati sljedeće naredbe:
java – version
provjeriti koja verzija je instalirana.
Instalacija Apache Flink-a je također veoma jednostavna. Prvo je potrebno skinuti zadnju
verziju Apache Flink-a i potom u terminal upisati sljedeću naredbu:
./bin/start-cluster.sh
Flink kao i Spark ima svoju nadzoru ploču (engl. Dashboard) u kojoj možemo vidjeti sve
procese koji su pokrenuti ili završeni unutar Flink aplikacije. Na Nadzornoj ploči možemo vidjeti
i logove te tako pratiti rad ili eventualne greške Flink aplikacija.
39
Nadzora ploča se nalazi na web-u i možemo joj pristupiti tako da u web pregledniku ukucamo
sljedeću lokaciju: localhost: 8081. Nakon toga bi trebali dobiti prozor kao na slici ispod.
Prema službenoj Apache Flink dokumentaciji („Apache Flink documentation“, bez dat.)
svaki Flink program koji radi transformacije nad nekim podaci se sastoji od sljedećih dijelova:
Program smo kreirali prema gore navedenim uputama, program je pisan u Java
programsko jeziku pa je zbog toga korištena Eclipse razvojna okolina. Kreirali smo novi projekt
unutar Eclipsa kojeg smo nazvali „P1“. Unutar tog projekta smo kreirali klasu „Use_Case“ u
kojoj se nalazi logika samo programa.
40
Okruženje za pokretanje programa i učitavanje podataka
Pomoću sljedeće naredbe unutar naše klase „Use_Case“ kreiramo okruženje za
„streaming“ podataka:
StreamExecutionEnvironment env =
StreamExecutionEnvironment.getExecutionEnvironment();
Kada smo kreirali okruženje potrebno je prije samog učitavanja podataka unijeti pristupne
podatke koje smo dobili kada smo kreirali aplikaciju na našem programerskom Twitter računu.
To smo napravili pomoću sljedećeg koda:
Tek nakon što Twitter potvrdi gore navedene ključeve i tokene te utvrdi da se radi o našoj
aplikaciji i našem Twitter profilu, biti ćemo u mogućnosti povući podatke sa Twitter-a. Nakon
što povučemo podatke spremamo u „datastream“ koji smo nazvali „twitterData“.
41
Filtriranje podataka
Nakon što smo učitali podatke i otvorili smo vezu prema Twitteru, potrebno je raščlaniti i
filtrirati podatke. Za ova dva zadatka su kreirane 4 funkcije:
1. „TweerParse“ učitava podatke i kreirane nove objekte koji će biti u .JSON formatu.
42
{
final List<String>
keywords=Arrays.asList("earthquake","earthquakes","magnitude","Richter
scale","kilometers","epicenter","depth","sezmiologist","Croatia","world","E
urope","earthquake victims","plate
tectonics","clefts","litosfere","hipocenter","geophysics","Mercalli
scale","sezmiograph","landslide");
43
String sourceHtml = node.get("source").asText().toLowerCase();
if (sourceHtml.contains("ipad")||
sourceHtml.contains("iphone"))
source = "AppleMobile";
else if (sourceHtml.contains("mac"))
source = "AppleMac";
else if (sourceHtml.contains("android"))
source = "Android";
else if (sourceHtml.contains("BlackBerry"))
source = "BlackBerry";
else if (sourceHtml.contains("web"))
source = "Web";
else
source = "Other";
}
return new Tuple2<String, JsonNode>(source, node); //
rezultat (Android,tweet)
}
}
Nakon toga pozove sve kreirane funkcije jednu po jednu kako bi na kraju dobili samo one
vrijednosti koje nam trebaju.
44
da nakon svakog sata ponovo krećemo zbrajati sa koji uređaja odnosno operacijskih sustava
je napisan status.
env.execute("Twitter Analysis");
Na kraju smo rezultat ove analize zapisali u tekstualnu datoteku tako što okinuli naredbu
za pokretanje programa. Kada odemo na novo kreirani folder možemo vidjeti rezultate naše
analize. Na osnovu ovi podataka možemo odrediti koji operacijski sustav je najbolji i tako
donijeti odluku te napravi aplikaciju za potrese za onaj operacijski sustav koji ima najviše
objavljenih statusa. Sljedeća slika nam pokazuje podatke koji su generirani u našoj tekstualnoj
datoteci „earthquake.txt“. „Stream“ podataka je trajao dva sata i dobili smo rezultate da je u
periodu od 8 do 9 sati napisano :
Nakon isteka ovog sata brojač se vrati na nulu i ponovo broji rezultate. Tako da u periodu
od 9 do 10 imamo sljedeće rezultate:
46
Slika 24. Prikaz rezultata u vremenskom periodu od 9 do 10 h
Unutar ove kratke analize od dva sata možemo zaključiti da je aplikaciju najbolje praviti za
android uređaje, dok su nam Apple Mobile uređaji druga najbolja opcija. Vidimo da se
BlackBerry uređaji ne pojavljuju, a razlog tome je upravo taj što jako mali broj ljudi koristi ove
uređaje. Vidimo također da veliki broj korisnika statuse piše preko web-a, ali ipak je to puno
manji broj u odnosnu na prva dva operacijska sustava.
47
6. Usporedba razvojnih okvira za „Velike podatke“
Mehanizmi procesiranja Serijski (engl. Batch ) Serijski (engl. Batch ) Protočno, neprekidno
podataka (engl. stream)
Brzina Sporiji od Spark-a i Flink- 100 puta brži od Hadoop- Brži od Spark-a
a a
Programski jezici Java, C, C++, Ruby, Java, Scala, Python, R Java, Scala, R, Python
Na osnovu navedene tablice možemo vidjeti koje su točno razlike između Spark-a i Flink-a.
Glavna razlika je upravo to što je Flink razvojni okvir koji omogućava procesiranje i obradu
podataka u realnom vremenu, dok Spark radi na nekom konačnom skupu podataka sa
određenim kašnjenjem. Također je bitno napomenuti da su okviri implementirati u različitim
programskim jezicima, Flink je implementiran u Javi, a Spark u Scala programskom jeziku.
Flink je brži u obradi podataka i omogućava aktivno upravljanje memorijom pa se rijetko kad
48
može dogoditi da se memorija zapuni odnosno da ostane bez memorijskom prostora. Ranije
verzije Spark-a nisu imale aktivno upravljanje memorijom, međutim u noviji verzijama je
omogućeno aktivno upravljanje memorijom. Navedeni alati zahtijevaju visoku kvalitetu
hardvera i mnogo RAM-a. Oba razvoja okvira sadrže podršku za strojno učenje, kao i grafičku
podršku te podršku za SQL. Kako se može vidjeti na primjerima iznad, navedena svojstva se
koriste u obliku knjižica (engl. Libarires) koje sadrže klase i algoritme koje možemo koristit za
implementaciju grafova, SQL upita te kreiranje algoritama za strojno učenje.
49
7. Zaključak
U ovom radu predstavljena su dva okvira za analizu podataka Apache Spark i Apache
Flink. Okviri su korišteni kroz dva različita pristupa, Apache Spark smo koristili za serijsku
obradu podataka odnosno za obradu i analizu podataka preko izvora koji se ne mijenja, dok
smo Apache Flink koristili za obradu toka podataka u realnom vremenu. Kako su navedeni
alati slojevite arhitekture, pomoću Spark-a smo prikazali SQL model i model strojnog učenja,
dok smo pomoću Flink-a prikazali „data streaming“ model. Također jako bitno je napomenuti
da su alati dostupni u više programski jezika kao što su: Scala, Java i Python te da su oba
alata besplatna. Prvi algoritam za prikaz stanja i predikciju broja oboljelih je pisan u Python-u,
dok je algoritam za obradu Twitter podataka napisan u Java programskom jeziku. Osim toga,
navede su razlike između ova dva alata i možemo zaključiti da je Flink brži i pouzdani alat za
obradu podataka u realnom vremenu.
Količina digitalnih podataka nekontrolirano raste stoga alati poput Flink-a i Spark-a
predstavljaju budućnost obrade i analize podataka. Kako i puno puta do sada, kako bi se
prilagodili društvenim i tehnološkim promjenama ljudi konstanto moraju stjecati nova znanja i
vještine. Podatkovna znanost je mlada znanost i sigurno će se u idući nekoliko godina dodatno
razvijati. Znanja poput programiranja i analize podataka u navedenim ili nekim drugim alati su
definitivno zanimanja budućnosti.
50
Popis literature
51
16. Apache Spark Ecosystem [slika] (bez dat.) preuzeto 14.01.2021 s
https://www.analyticsvidhya.com/blog/2020/11/introduction-to-spark-streaming-add-
new-tag/
17. Kornelije Rabuzin (2011). Uvod u SQL Varaždin: Fakultet organizacije i informatike
18. Maleković, M., Rabuzin K. (2016). Uvod u baze podataka. Varaždin etc.: Fakultet
organizacije i informatike etc.
19. Rabuzin, K. (2014). SQL : napredne teme. Varaždin: Fakultet organizacije i informatike.
20. Routray S. (2020) Machine Learning : Linear Regression using Pyspark preuzeto
19.01.2021 s https://towardsdatascience.com/machine-learning-linear-regression-
using-pyspark-9d5d5c772b42
52
Dodaci
Za instalaciju Linux-a na virtualnoj mašini prvo je potrebno skinuti Oracle virtualnu mašinu
sa sljedeće stranice: https://www.virtualbox.org/wiki/Downloads. Zatim je potrebno skinuti
zadnju verziju Ubuntu Linux-a sa sljedeće stranice: https://ubuntu.com/download/desktop.
Bitno je da skinete 64-bitnu LTS verziju sa navedene stranice.
Nakon što smo preuzeli instalacijske pakete možemo pokrenuti virtualnu mašinu. Kada je
mašina pokrenuta odaberemo opciju „New“ kako je prikazano na slici ispod.
53
opciju „Storage“ → Controlloer:IDE → Choose disk i odaberete Linux LTS datoteku koju ste
prethodno skinuti.
Nakon toga jednostavno pokrenete svoju virtualnu mašinu i odaberete vremensku zonu, jezik
i naziv vaše računala. Nakon što Linux završi sa instalacijom obavezno ponovo pokrenite vašu
mašinu i time je instalacijski postupak završio.
54
B. Popis slika
C. Popis tablica
55