Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
ed:lab_05 [2024/03/12 15:12] pszwed [PiComputeApp] |
ed:lab_05 [2024/03/13 03:24] (current) pszwed [1.2 Zbuduj obraz spark-jupyter] |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Laboratorium 5 ====== | + | ====== Laboratorium 5 ====== |
- | FIXME Strona w trakcie edycji | + | |
- | ===== Konfiguracja Dockera ===== | + | ===== 1. Konfiguracja Dockera ===== |
Naszym celem jest zbudowanie konfiguracji jak na rysunku: cztery kontenery połączone wspólną siecią | Naszym celem jest zbudowanie konfiguracji jak na rysunku: cztery kontenery połączone wspólną siecią | ||
Line 29: | Line 29: | ||
</ | </ | ||
+ | |||
+ | **Pobierz pliki konfiguracyjne i zbiór danych: {{ : | ||
==== Utwórz sieć spark-network ==== | ==== Utwórz sieć spark-network ==== | ||
Line 35: | Line 37: | ||
</ | </ | ||
- | ==== Zbuduj obraz spark-python ==== | + | ==== 1.1. Zbuduj obraz spark-python ==== |
Przejdź do katalogu '' | Przejdź do katalogu '' | ||
Line 67: | Line 69: | ||
- | ==== Zbuduj obraz spark-jupyter ==== | + | ==== 1.2 Zbuduj obraz spark-jupyter ==== |
Przejdź do katalogu '' | Przejdź do katalogu '' | ||
Line 83: | Line 85: | ||
pip3 cache purge; \ | pip3 cache purge; \ | ||
pip3 install pyspark numpy scikit-learn pandas matplotlib plotly jupyterlab; \ | pip3 install pyspark numpy scikit-learn pandas matplotlib plotly jupyterlab; \ | ||
+ | apt-get install -y pandoc; \ | ||
+ | apt-get install -y texlive-xetex texlive-fonts-recommended texlive-plain-generic; | ||
+ | apt-get install -y texlive-latex-extra texlive-fonts-extra texlive-lang-all; | ||
rm -rf / | rm -rf / | ||
+ | |||
+ | |||
RUN echo "spark ALL=(ALL) NOPASSWD: ALL" >> / | RUN echo "spark ALL=(ALL) NOPASSWD: ALL" >> / | ||
ENV JAVA_HOME / | ENV JAVA_HOME / | ||
Line 97: | Line 104: | ||
</ | </ | ||
- | ==== Uruchomienie klastra ==== | + | Obraz zawiera zbiór bibliotek ogólnego zastosowania języka Python do eksploracji danych, wizualizacji i uczenie maszynowego: |
+ | * bibliotekę pyspark | ||
+ | * typowe biblioteki uczenia maszynowego (ale bez tensorflow) | ||
+ | * jupyter-lab (wsparcie dla notatników) | ||
+ | * poandoc i instalację latexa (po załadowaniu notatnika możliwy jest wydruk w formacjie PDF z zawijaniem długich linii | ||
+ | |||
+ | Jak uruchomić - [[https:// | ||
+ | |||
+ | ==== 1.3 Uruchomienie klastra ==== | ||
W katalogu cluster powinien znaleźć się plik '' | W katalogu cluster powinien znaleźć się plik '' | ||
Line 180: | Line 195: | ||
* WorkerUI (worker-1) [[http:// | * WorkerUI (worker-1) [[http:// | ||
- | ==== Uruchomienie węzła spark-jupyter ==== | + | ==== 1.4 Uruchomienie węzła spark-jupyter ==== |
Kontener będzie uruchamiany za pomocą polecenia: | Kontener będzie uruchamiany za pomocą polecenia: | ||
Line 194: | Line 209: | ||
* W momencie uruchomienia wołany jest shell | * W momencie uruchomienia wołany jest shell | ||
- | ===== Java ===== | + | ===== 2 Java ===== |
- | ==== PiComputeApp ==== | + | ==== 2.1 PiComputeApp ==== |
**1.** Dodaj kod klasy do projektu i wprowadź odpowiednie wywołanie w funkcji '' | **1.** Dodaj kod klasy do projektu i wprowadź odpowiednie wywołanie w funkcji '' | ||
Line 284: | Line 299: | ||
**5.** Umieść w spawozdaniu fragmenty zrzutów ekranu pokazujące działanie wykonawcy Sparka (konsoli i DriverUI) | **5.** Umieść w spawozdaniu fragmenty zrzutów ekranu pokazujące działanie wykonawcy Sparka (konsoli i DriverUI) | ||
| | ||
- | ==== PiComputeAppDistributed ==== | + | ==== 2.2 PiComputeAppDistributed ==== |
**1.** Wprowadź minimalną zmianę w kodzie aplikacji. Różnicą jest wskazanie adresu węzła Master. | **1.** Wprowadź minimalną zmianę w kodzie aplikacji. Różnicą jest wskazanie adresu węzła Master. | ||
Line 302: | Line 317: | ||
**4.** Zamieść w spawozdaniu zrzuty WebUI węzłów Master i Worker(ów) wskazujących, | **4.** Zamieść w spawozdaniu zrzuty WebUI węzłów Master i Worker(ów) wskazujących, | ||
+ | |||
+ | ==== 2.3 LoadDistributedDataset ==== | ||
+ | |||
+ | Załadujemy zbiór danych do Sparka. Musi być on dostępny dla węzłów | ||
+ | * Driver | ||
+ | * Worker | ||
+ | |||
+ | W przemysłowym zastosowaniu byłby widoczny np. na rozproszonym systemie plików. W naszym przypadku skorzystamy z montowanych wolumenów Dockera (czyli będzie widoczny lokalnie). | ||
+ | |||
+ | **Kontener wykonujący program węzła driver ('' | ||
+ | |||
+ | **1.** Dodaj kod klasy dla nowej aplikacji oraz wywołaj ją w Main.main() | ||
+ | |||
+ | <code java> | ||
+ | public class LoadDistributedDataset { | ||
+ | |||
+ | public static void main(String[] args) { | ||
+ | SparkSession spark = SparkSession.builder() | ||
+ | .appName(" | ||
+ | .master(" | ||
+ | .getOrCreate(); | ||
+ | |||
+ | Dataset< | ||
+ | .option(" | ||
+ | .option(" | ||
+ | .load(" | ||
+ | |||
+ | df.show(5); // To raczej zakomentuj... | ||
+ | df=df.select(" | ||
+ | df.show(5); | ||
+ | df.printSchema(); | ||
+ | |||
+ | |||
+ | } | ||
+ | } | ||
+ | |||
+ | </ | ||
+ | |||
+ | **2.** Skonfiguruj i zbuduj nowy artefakt (np. '' | ||
+ | |||
+ | **3.** Przekopiuj **ręcznie** artefakt do katalogu '' | ||
+ | |||
+ | **4.** Przejdź do katalogu '' | ||
+ | |||
+ | < | ||
+ | docker run -it --rm -v " | ||
+ | </ | ||
+ | |||
+ | Następnie sprawdź, czy artefakt i podkatalog '' | ||
+ | |||
+ | **5.** Wykonaj '' | ||
+ | |||
+ | < | ||
+ | / | ||
+ | |||
+ | </ | ||
+ | |||
+ | |||
+ | **6.** Oczekiwany efekt: | ||
+ | * widoczna uruchomiona lub wykonana aplikacja w WebUI węzłów Master i Worker | ||
+ | * Wydrukowana ramka na konsoli (węzła driver w Dockerze) | ||
+ | |||
+ | < | ||
+ | +-------+----+----------+------------------+ | ||
+ | |country|year|population|electricity_demand| | ||
+ | +-------+----+----------+------------------+ | ||
+ | | Poland|2000| | ||
+ | | Poland|2001| | ||
+ | | Poland|2002| | ||
+ | | Poland|2003| | ||
+ | | Poland|2004| | ||
+ | +-------+----+----------+------------------+ | ||
+ | only showing top 5 rows | ||
+ | |||
+ | root | ||
+ | |-- country: string (nullable = true) | ||
+ | |-- year: integer (nullable = true) | ||
+ | |-- population: long (nullable = true) | ||
+ | |-- electricity_demand: | ||
+ | |||
+ | </ | ||
+ | |||
+ | |||
+ | ===== 3 PySpark + Jupyter ===== | ||
+ | |||
+ | Spróbujemy powtórzyć te kroki w środowisku Jupyter korzystając z biblioteki PySpark. | ||
+ | |||
+ | PySpark zapewnia interfejs w języku Python do platformy Spark. Aby go użyć - biblioteka PySpark musi być zainstalowana na wszystkich węzałach (co było uwzględnione przy budowie obrazów). Wewnętrznie korzysta z biblioteki [[https:// | ||
+ | |||
+ | |||
+ | ==== 3.1 Uruchomienie jupyter-lab ==== | ||
+ | |||
+ | **1.** Uruchom obraz '' | ||
+ | |||
+ | < | ||
+ | docker run -it --rm -v " | ||
+ | </ | ||
+ | |||
+ | |||
+ | **2.** Wydaj polecenie | ||
+ | |||
+ | < | ||
+ | sudo --preserve-env jupyter-lab | ||
+ | </ | ||
+ | |||
+ | |||
+ | **3.** W przeglądarce otwórz | ||
+ | |||
+ | Obraz '' | ||
+ | |||
+ | |||
+ | ==== 3.2 Wyznaczanie liczby PI ==== | ||
+ | |||
+ | **1.** Utwórz notatnik '' | ||
+ | |||
+ | <code python> | ||
+ | import pyspark | ||
+ | from random import random | ||
+ | from operator import add | ||
+ | |||
+ | from pyspark.sql import SparkSession | ||
+ | </ | ||
+ | |||
+ | <code python> | ||
+ | spark = SparkSession.builder.appName(" | ||
+ | </ | ||
+ | |||
+ | Tu otwórz [[http:// | ||
+ | |||
+ | <code python> | ||
+ | partitions = 100 | ||
+ | n = 1_000_000 * partitions | ||
+ | |||
+ | def f(_: int) -> float: | ||
+ | x = random() * 2 - 1 | ||
+ | y = random() * 2 - 1 | ||
+ | return 1 if x ** 2 + y ** 2 <= 1 else 0 | ||
+ | |||
+ | count = spark.sparkContext.parallelize(range(1, | ||
+ | print(" | ||
+ | </ | ||
+ | |||
+ | <code python> | ||
+ | spark.stop() | ||
+ | </ | ||
+ | |||
+ | **2.** Możesz uruchamiać interaktywnie kolejne komórki i monitorować działanie aplikacji w WebUI. Do momentu jawnego zakończenia sesji, będzie ona aktywna. | ||
+ | |||
+ | ==== 3.3 LoadEnergyDataset ==== | ||
+ | |||
+ | **1.** Utwórz notatnik i wprowadź w nim kod: | ||
+ | |||
+ | <code python> | ||
+ | import pyspark | ||
+ | from random import random | ||
+ | from operator import add | ||
+ | |||
+ | from pyspark.sql import SparkSession | ||
+ | </ | ||
+ | |||
+ | <code python> | ||
+ | spark = SparkSession.builder.appName(" | ||
+ | </ | ||
+ | |||
+ | **2.** załaduj dane | ||
+ | |||
+ | <code python> | ||
+ | df = spark.read.format(" | ||
+ | </ | ||
+ | |||
+ | Możesz spróbować je wyświetlić | ||
+ | <code python> | ||
+ | df.show(5, | ||
+ | </ | ||
+ | ... ale raczej skasuj wyjście komórki | ||
+ | |||
+ | **3.** Wybierzemy dane do wyświetlenia | ||
+ | <code python> | ||
+ | df2 = df.select(" | ||
+ | </ | ||
+ | |||
+ | I wyświetlimy je: | ||
+ | |||
+ | <code python> | ||
+ | df2.show(5) | ||
+ | df2.printSchema() | ||
+ | </ | ||
+ | |||
+ | Zauważ, że ze względu na //lazy evaluation// | ||
+ | |||
+ | |||
+ | **3.** Wybierzmy podzbiór danych z Polski z interesującymi nas niepustymi wartościami | ||
+ | |||
+ | <code python> | ||
+ | df_pl = df.select(' | ||
+ | df_pl.show() | ||
+ | </ | ||
+ | |||
+ | === Wykresy=== | ||
+ | Przekonwertujemy dane do postaci list | ||
+ | |||
+ | <code python> | ||
+ | import matplotlib.pyplot as plt | ||
+ | df_pl = df_pl.orderBy(' | ||
+ | y = df_pl.select(' | ||
+ | pop = df_pl.select(' | ||
+ | dem = df_pl.select(' | ||
+ | </ | ||
+ | |||
+ | oraz wyświetlimy je... | ||
+ | <code python> | ||
+ | plt.plot(y, | ||
+ | plt.xlabel(' | ||
+ | plt.ylabel(' | ||
+ | plt.title(' | ||
+ | plt.show() | ||
+ | </ | ||
+ | |||
+ | <code python> | ||
+ | plt.plot(y, | ||
+ | plt.xlabel(' | ||
+ | plt.ylabel(' | ||
+ | plt.title(' | ||
+ | plt.show() | ||
+ | </ | ||
+ | |||
+ | <code python> | ||
+ | plt.scatter(pop, | ||
+ | plt.xlabel(' | ||
+ | plt.ylabel(' | ||
+ | plt.title(' | ||
+ | plt.show() | ||
+ | </ | ||
+ | |||
+ | === Regresja liniowa=== | ||
+ | Dla których zależności można zastosować regresję? | ||
+ | |||
+ | **1.** Dodaj kod: | ||
+ | |||
+ | <code python> | ||
+ | from pyspark.ml.regression import LinearRegression | ||
+ | from pyspark.ml.feature import VectorAssembler | ||
+ | |||
+ | va=VectorAssembler().setInputCols([" | ||
+ | df_plf = va.transform(df_pl) | ||
+ | df_plf.show(5) | ||
+ | |||
+ | lr = LinearRegression()\ | ||
+ | .setMaxIter(10)\ | ||
+ | .setRegParam(3.0)\ | ||
+ | .setElasticNetParam(0.5)\ | ||
+ | .setFeaturesCol(" | ||
+ | .setLabelCol(" | ||
+ | model = lr.fit(df_plf) | ||
+ | </ | ||
+ | |||
+ | **2.** Wyświetl metryki oraz równanie regresji | ||
+ | |||
+ | <code python> | ||
+ | print(f' | ||
+ | print(f' | ||
+ | print(f' | ||
+ | print(f' | ||
+ | </ | ||
+ | |||
+ | **3.** Wyświetl wykresy | ||
+ | |||
+ | <code python> | ||
+ | import numpy as np | ||
+ | # from pyspark.sql.types import StructType, StructField, | ||
+ | from pyspark.ml.linalg import Vectors | ||
+ | |||
+ | xmin = np.min(y) | ||
+ | xmax = np.max(y) | ||
+ | xx = np.linspace(xmin-1, | ||
+ | |||
+ | yy = [model.predict(Vectors.dense([x])) for x in xx] | ||
+ | |||
+ | plt.scatter(y, | ||
+ | plt.plot(xx, | ||
+ | plt.legend() | ||
+ | plt.title(' | ||
+ | plt.show() | ||
+ | </ | ||
+ | |||
+ | **4.** Zakończ sesję | ||
+ | |||
+ | Przed zakończeniem sesji obejrzyj DriverUI (localhost: | ||
+ | |||
+ | <code python> | ||
+ | spark.stop() | ||
+ | </ | ||
+ | |||
+ | ==== 3.4 TODO - regresja dla Chin ==== | ||
+ | |||
+ | Przeprowadź taką samą analizę dla Chin, ale spróbuj znaleźć zależność pomiędzy liczbą ludności, a zapotrzebowaniem na energię (która w przypadku Chin jest raczej widoczna). | ||
+ | |||
+ | **Zapisz notatnik jako PDF i prześlij razem ze sprawozdaniem** | ||
+ |