PySparkとビッグデータ処理の最初のステップ

PySparkとビッグデータ処理の最初のステップ

1台のマシンで処理するにはデータの量が大きすぎるという状況に直面することが一般的になりつつあります。 幸いなことに、Apache Spark、Hadoopなどの技術は、この正確な問題を解決するために開発されました。 これらのシステムのパワーは、PySparkを使用してPythonから直接利用できます!

ギガバイト以上のデータセットを効率的に処理することは、あなたがデータサイエンティスト、Web開発者、またはその中間者であるかどうかに関係なく、* Python開発者の手の届く範囲内です*。

このチュートリアルでは、次のことを学びます:

  • Pythonの概念をビッグデータに適用できるもの

  • Apache SparkとPySparkの使用方法

  • 基本的なPySparkプログラムの書き方

  • 小さなデータセットでローカルにPySparkプログラムを実行する方法

  • PySparkのスキルを分散システムに取り入れるための次のステップ

*無料ボーナス:*リンク:[Python Tricks:The Book]の章にアクセスするには、ここをクリックして、Pythonのベストプラクティスを簡単な例とともに示します。すぐに適用して、より美しい+ Pythonコードを記述できます。

Pythonのビッグデータの概念

_just_としての人気にもかかわらずhttps://en.wikipedia.org/wiki/Scripting_language [スクリプト言語]、Pythonはhttps://realpythonのようないくつかのhttps://en.wikipedia.org/wiki/Programming_paradigm [プログラミングパラダイム]を公開しています。 .com/numpy-array-programming/[配列指向プログラミング]、https://realpython.com/python3-object-oriented-programming/[オブジェクト指向プログラミング]、https://realpython.com/courses/python -3-concurrency-asyncio-module/[非同期プログラミング]、および他の多くの。 意欲的なビッグデータの専門家にとって特に興味深いパラダイムの1つは、https://realpython.com/courses/functional-programming-python/[functional programming]です。

関数型プログラミングは、ビッグデータを扱う際の一般的なパラダイムです。 機能的な方法で記述すると、https://en.wikipedia.org/wiki/Embarrassingly_parallel [embarrassingly parallel]コードになります。 つまり、コードを取得して複数のCPUまたはまったく異なるマシンで実行する方が簡単です。 一度に複数のシステムで実行することにより、単一のワークステーションの物理メモリとCPUの制限を回避できます。

これはPySparkエコシステムの力であり、機能的なコードを取得して、コンピューターのクラスター全体に自動的に配布できます。

Pythonプログラマにとって幸いなことに、関数型プログラミングのコアアイデアの多くは、Pythonの標準ライブラリとビルトインで利用できます。 Pythonの快適さを離れることなく、ビッグデータ処理に必要な多くの概念を学ぶことができます。

関数型プログラミングの核となる考え方は、外部状態を維持せずに関数によってデータを操作する必要があるということです。 これは、コードがグローバル変数を回避し、データをその場で操作する代わりに常に*新しいデータ*を返すことを意味します。

関数型プログラミングのもう1つの一般的なアイデアは、https://en.wikipedia.org/wiki/Anonymous_function [anonymous functions]です。 Pythonは、https://realpython.com/code-evaluation-with-aws-lambda-and-api-gateway/[AWS Lambda functions]と混同しないように、 `+ lambda +`キーワードを使用して匿名関数を公開します。

用語と概念のいくつかを知ったので、これらのアイデアがPythonエコシステムでどのように現れるかを探ることができます。

ラムダ関数

Pythonのhttps://realpython.com/python-lambda/[lambda functions]はインラインで定義され、単一の式に制限されています。 組み込みの `+ sorted()`関数を使用すると、おそらく ` lambda +`関数を見たことがあるでしょう。

>>>

>>> x = ['Python', 'programming', 'is', 'awesome!']
>>> print(sorted(x))
['Python', 'awesome!', 'is', 'programming']
>>> print(sorted(x, key=lambda arg: arg.lower()))
['awesome!', 'is', 'programming', 'Python']

iterableの各アイテムに対して、「+ sorted 」の「 key +」パラメーターが呼び出されます。 これにより、ソートが行われる前にすべての文字列を小文字に変更することで、ソートで大文字と小文字が区別されなくなります。

これは、外部状態を保持しない小さな匿名関数である「+ lambda +」関数の一般的なユースケースです。

Pythonには、 + filter()++ map()+、および `+ reduce()`などの他の一般的な関数型プログラミング関数もあります。 これらすべての関数は、 ` lambda `関数または同様の方法で ` def +`で定義された標準関数を利用できます。

+ filter()++ map()+、および + reduce()+

組み込みのhttps://realpython.com/lessons/filter-function-overview/[filter()]、https://realpython.com/lessons/map-function-overview/[+map ()+ `]、およびhttps://realpython.com/lessons/reduce-function-overview/[ + reduce()+ `]関数はすべて関数型プログラミングで一般的です。 これらの概念がPySparkプログラムの機能のかなりの部分を占めることがすぐにわかるでしょう。

コアPythonコンテキストでこれらの関数を理解することが重要です。 その後、その知識をPySparkプログラムとSpark APIに翻訳できるようになります。

`+ filter()`は、通常は ` lambda +`関数として表される条件に基づいて、イテレータからアイテムをフィルタリングします。

>>>

>>> x = ['Python', 'programming', 'is', 'awesome!']
>>> print(list(filter(lambda arg: len(arg) < 8, x)))
['Python', 'is']

`+ filter()`は反復可能なものを取り、各項目で ` lambda `関数を呼び出し、 ` lambda `が ` True +`を返した項目を返します。

注意: `+ filter()`も反復可能であるため、 ` list()`を呼び出す必要があります。 ` filter()`は、値をループするときにのみ値を提供します。 ` list()+`は、ループを使用する代わりに、すべてのアイテムを一度にメモリに入れます。

次のような一般的な `+ for `ループパターンを置き換えるために、 ` filter()+`を使用することを想像できます。

def is_less_than_8_characters(item):
    return len(item) < 8

x = ['Python', 'programming', 'is', 'awesome!']
results = []

for item in x:
    if is_less_than_8_characters(item):
        results.append(item)

print(results)

このコードは、8文字未満のすべての文字列を収集します。 コードは `+ filter()+`の例よりも冗長ですが、同じ機能で同じ結果を実行します。

`+ filter()`のもう少し明白な利点は、反復可能を返すことです。 つまり、 ` filter()+`では、イテレート可能オブジェクト内のすべてのアイテムを一度に保持するのに十分なメモリがコンピューターにある必要はありません。 これは、数ギガバイトのサイズに急速に成長する可能性のあるビッグデータセットでますます重要になっています。

`+ map()`は、反復可能オブジェクトの各アイテムに関数を適用するという点で ` filter()`と似ていますが、元のアイテムの1対1のマッピングを常に生成します。 ` map()`が返す *new* イテラブルは、元のイテラブルと常に同じ数の要素を持ちますが、これは ` filter()+`の場合ではありませんでした:

>>>

>>> x = ['Python', 'programming', 'is', 'awesome!']
>>> print(list(map(lambda arg: arg.upper(), x)))
['PYTHON', 'PROGRAMMING', 'IS', 'AWESOME!']

`+ map()`はすべてのアイテムで ` lambda `関数を自動的に呼び出し、次のような ` for +`ループを効果的に置き換えます。

results = []

x = ['Python', 'programming', 'is', 'awesome!']
for item in x:
    results.append(item.upper())

print(results)

`+ for `ループの結果は、すべてのアイテムを大文字の形式で収集する ` map()`の例と同じです。 ただし、 ` filter()`の例と同様に、 ` map()+`は反復可能オブジェクトを返します。これにより、大きすぎてメモリに完全に収まらない大量のデータを再び処理できるようになります。

最後に、Python標準ライブラリの最後の関数トリオは `+ reduce()`です。 ` filter()`および ` map()`と同様に、 ` reduce()+`はiterableの要素に関数を適用します。

繰り返しますが、適用される関数は、 `+ def `キーワードまたは ` lambda +`関数で作成された標準のPython関数です。

ただし、 `+ reduce()`は新しい反復可能オブジェクトを返しません。 代わりに、 ` reduce()+`は反復可能値を単一の値に減らすために呼び出される関数を使用します。

>>>

>>> from functools import reduce
>>> x = ['Python', 'programming', 'is', 'awesome!']
>>> print(reduce(lambda val1, val2: val1 + val2, x))
Pythonprogrammingisawesome!

このコードは、反復可能オブジェクト内のすべてのアイテムを左から右に結合して単一のアイテムにします。 `+ reduce()`はすでに単一の項目を返しているため、ここでは ` list()+`の呼び出しはありません。

注意: Python 3.xは、組み込みの `+ reduce()`関数を ` functools +`パッケージに移動しました。

+ lambda ++ map()++ filter()+、および `+ reduce()+`は多くの言語に存在する概念であり、通常のPythonプログラムで使用できます。 まもなく、これらの概念がPySpark APIに拡張され、大量のデータを処理できるようになるでしょう。

Sets

Setsは、標準Pythonに存在するもう1つの一般的な機能であり、ビッグデータ処理で広く役立ちます。 セットはリストに非常に似ていますが、順序がなく、重複する値を含めることができない点が異なります。 セットは、Python dictのキーに似ていると考えることができます。

PySparkのHello World

優れたプログラミングチュートリアルと同様に、「+ Hello World +」の例から始めてください。 以下はPySparkに相当するものです。

import pyspark
sc = pyspark.SparkContext('local[*]')

txt = sc.textFile('file:////usr/share/doc/python/copyright')
print(txt.count())

python_lines = txt.filter(lambda line: 'python' in line.lower())
print(python_lines.count())

まだすべての詳細について心配する必要はありません。 主なアイデアは、PySparkプログラムが通常のPythonプログラムとそれほど変わらないことを念頭に置くことです。

注意: PySparkがまだ​​インストールされていない場合、または指定された `+ copyright +`ファイルがない場合、このプログラムはシステム上でhttps://realpython.com/python-exceptions/[Exception]を発生させる可能性があります。後で行う方法について説明します。

このプログラムの詳細はすぐに学習しますが、よく見てください。 プログラムは、総行数と、「+ copyright 」という名前のファイル内の単語「 python +」を持つ行の数をカウントします。

  • PySparkプログラムは通常のPythonプログラムとそれほど違いはありませんが、*クラスターで実行している場合は特に、*実行モデルは通常のPythonプログラムと非常に異なる可能性があります。

クラスター上にいる場合、複数のノードに処理を分散させる背後で多くのことが発生する可能性があります。 ただし、現時点では、プログラムをPySparkライブラリを使用するPythonプログラムと考えてください。

PythonとシンプルなPySparkプログラムに存在するいくつかの一般的な機能概念を見てきたので、今度はSparkとPySparkについてさらに詳しく見ていきましょう。

Sparkとは

https://spark.apache.org [Apache Spark]はいくつかのコンポーネントで構成されているため、説明が難しい場合があります。 その核となるのは、Sparkは大量のデータを処理するための汎用*エンジン*です。

Sparkはhttps://scala-lang.org [Scala]で記述され、https://en.wikipedia.org/wiki/Java_virtual_machine [JVM]で実行されます。 Sparkには、ストリーミングデータの処理、機械学習、グラフ処理、さらにSQLを介したデータとのやり取りのためのコンポーネントが組み込まれています。

このガイドでは、ビッグデータを処理するためのコアSparkコンポーネントについてのみ学習します。 ただし、機械学習やSQLなどの他のすべてのコンポーネントはすべて、PySparkを介してPythonプロジェクトでも使用できます。

PySparkとは何ですか?

Sparkは、JVM上で実行される言語であるScalaに実装されていますが、Pythonを介してすべての機能にアクセスするにはどうすればよいですか?

PySparkが答えです。

PySparkの現在のバージョンは2.4.3であり、Python 2.7、3.3以上で動作します。

PySparkは、Scala APIの上にあるPythonベースのラッパーと考えることができます。 これは、参照する2つのドキュメントセットがあることを意味します。

PySpark APIドキュメントには例がありますが、多くの場合、Scalaのドキュメントを参照して、コードをPySparkプログラムのPython構文に変換する必要があります。 幸いなことに、Scalaは非常に読みやすい関数ベースのプログラミング言語です。

PySparkはhttps://www.py4j.org [Py4Jライブラリ]を介してSpark ScalaベースのAPIと通信します。 Py4JはPySparkやSparkに固有のものではありません。 Py4Jでは、あらゆるPythonプログラムがJVMベースのコードと通信できます。

PySparkが機能的パラダイムに基づいている理由は2つあります。

  1. Sparkのネイティブ言語であるScalaは、機能ベースです。

  2. 機能的なコードは並列化がはるかに簡単です。

PySparkを考えるもう1つの方法は、単一のマシンまたはマシンのクラスターで大量のデータを処理できるライブラリです。

Pythonコンテキストでは、PySparkには、 `+ threading `または ` multiprocessing +`モジュールを必要とせずに並列処理を処理する方法があると考えてください。 スレッド、プロセス、さらにはさまざまなCPU間の複雑な通信と同期はすべて、Sparkによって処理されます。

PySpark APIとデータ構造

PySparkとやり取りするには、https://spark.apache.org/docs/latest/rdd-programming-guide.html#resilient-distributed-datasets-rdds [Resilient Distributed Datasets](RDD)という特殊なデータ構造を作成します。

RDDは、クラスターで実行している場合、スケジューラーによってデータを複数のノードに自動的に変換および分散する複雑さをすべて隠します。

PySparkのAPIとデータ構造をよりよく理解するには、前述の「+ Hello World +」プログラムを思い出してください。

import pyspark
sc = pyspark.SparkContext('local[*]')

txt = sc.textFile('file:////usr/share/doc/python/copyright')
print(txt.count())

python_lines = txt.filter(lambda line: 'python' in line.lower())
print(python_lines.count())

PySparkプログラムのエントリポイントは、 `+ SparkContext `オブジェクトです。 このオブジェクトを使用すると、Sparkクラスターに接続してRDDを作成できます。 ` local [*] `文字列は、_local_クラスターを使用していることを示す特別な文字列です。これは、シングルマシンモードで実行していることを示す別の方法です。 ` * +`は、マシン上の論理コアと同じ数のワーカースレッドを作成するようにSparkに指示します。

クラスタを使用している場合、「+ SparkContext +」の作成はより複雑になります。 Sparkクラスターに接続するには、認証とクラスターに固有の他のいくつかの情報を処理する必要がある場合があります。 これらの詳細は、次のように設定できます。

conf = pyspark.SparkConf()
conf.setMaster('spark://head_node:56887')
conf.set('spark.authenticate', True)
conf.set('spark.authenticate.secret', 'secret-key')
sc = SparkContext(conf=conf)

`+ SparkContext +`を取得したら、RDDの作成を開始できます。

RDDはさまざまな方法で作成できますが、一般的な方法の1つはPySparkの `+ parallelize()`関数です。 ` parallelize()+`は、リストやタプルなどのPythonデータ構造をRDDに変換できます。これにより、フォールトトレラントで分散された機能が提供されます。

RDDをよりよく理解するために、別の例を検討してください。 次のコードは、10,000個の要素の反復子を作成し、 `+ parallelize()+`を使用してそのデータを2つのパーティションに分散します。

>>>

>>> big_list = range(10000)
>>> rdd = sc.parallelize(big_list, 2)
>>> odds = rdd.filter(lambda x: x % 2 != 0)
>>> odds.take(5)
[1, 3, 5, 7, 9]

`+ parallelize()+`は、イテレータを*分布*数のセットに変換し、Sparkのインフラストラクチャのすべての機能を提供します。

このコードは、先ほど見たPythonの組み込みの `+ filter()`ではなく、RDDの ` filter()`メソッドを使用していることに注意してください。 結果は同じですが、舞台裏で起こっていることは大幅に異なります。 RDDの ` filter()+`メソッドを使用すると、その操作は複数のCPUまたはコンピューターに分散して発生します。

繰り返しになりますが、Sparkが「+ multiprocessing +」の作業を行い、すべてがRDDデータ構造にカプセル化されていることを想像してください。

`+ take()`はRDDの内容を表示する方法ですが、ごく一部のサブセットです。 ` take()+`は、そのデータのサブセットを分散システムから単一のマシンにプルします。

`+ take()+`は、単一のマシンでデータセット全体を検査できない可能性があるため、デバッグには重要です。 RDDはビッグデータでの使用に最適化されているため、現実のシナリオでは、単一のマシンにデータセット全体を保持するのに十分なRAMがない場合があります。

*注意:*シェルでこのような例を実行すると、Sparkは一時的に `+ stdout `に情報を出力します。これについてはすぐにわかります。 ` stdout `は、一時的に ` [Stage 0:>(0 + 1)/1] +`のように表示される場合があります。

`+ stdout +`テキストは、SparkがRDDを分割し、データを異なるCPUとマシンで複数のステージに処理する方法を示しています。

RDDを作成する別の方法は、前の例で見た `+ textFile()+`でファイルを読み込むことです。 RDDはPySparkを使用するための基本的なデータ構造の1つであるため、APIの多くの関数はRDDを返します。

RDDと他のデータ構造の重要な違いの1つは、結果が要求されるまで処理が遅延することです。 これはhttps://realpython.com/introduction-to-python-generators/[Python generator]に似ています。 Pythonエコシステムの開発者は通常、https://realpython.com/introduction-to-python-generators/[lazy evaluation]という用語を使用してこの動作を説明します。

処理を行わずに、同じRDDに複数の変換を積み重ねることができます。 Sparkは、変換のhttps://en.wikipedia.org/wiki/Directed_acyclic_graph [有向非巡回グラフ]を保持しているため、この機能が可能です。 基になるグラフは、最終結果が要求されたときにのみアクティブになります。 前の例では、 `+ take()+`を呼び出して結果を要求するまで計算は行われませんでした。

RDDから結果を要求する方法は複数あります。 RDDで `+ collect()`を使用することで、結果を評価して単一のクラスターノードに収集するように明示的に要求できます。 また、さまざまな方法で結果を暗黙的に要求することもできます。その1つは、前に見たように ` count()+`を使用することでした。

*注意:*これらのメソッドを使用するときは、データセット全体をメモリにプルするので注意してください。データセットが大きすぎて単一のマシンのRAMに収まらない場合は機能しません。

繰り返しますが、可能なすべての機能の詳細については、http://spark.apache.org/docs/latest/api/python/index.html [PySpark APIドキュメント]を参照してください。

PySparkのインストール

通常、http://hadoop.apache.org [Hadoopクラスター]でPySparkプログラムを実行しますが、他のクラスター展開オプションがサポートされています。 詳細については、https://spark.apache.org/docs/latest/cluster-overview.html [Sparkのクラスターモードの概要]をご覧ください。

*注:*これらのクラスターの1つをセットアップするのは困難な場合があり、このガイドの範囲外です。 理想的には、あなたのチームには、それを機能させるためのウィザードhttps://realpython.com/learning-paths/python-devops/[DevOps]エンジニアがいます。 そうでない場合、Hadoopはhttp://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-common/SingleCluster.html [ガイド]を公開して、あなたを支援します。

このガイドでは、ローカルマシンでPySparkプログラムを実行するいくつかの方法を紹介します。 これはテストや学習に役立ちますが、すぐに新しいプログラムを取得してクラスターで実行し、ビッグデータを真に処理したいと思うでしょう。

必要な依存関係がすべてあるため、PySpark自体をセットアップするのも難しい場合があります。

PySparkはJVMの上で実行され、機能するために多くの基盤となるJavaインフラストラクチャが必要です。 そうは言っても、私たちはhttps://realpython.com/docker-in-action-fitter-happier-more-productive/[Docker]の時代に住んでおり、PySparkの実験がはるかに簡単になります。

さらに良いことに、https://jupyter.org [Jupyter]の背後にある驚くべき開発者があなたのためにすべての面倒な作業を行ってくれました。 彼らは、すべてのPySpark依存関係とJupyterを含むhttps://github.com/jupyter/docker-stacks/tree/master/pyspark-notebook[Dockerfile]を公開しています。 したがって、Jupyterノートブックで直接実験できます。

注意: Jupyterノートブックには多くの機能があります。 ノートブックを効果的に使用する方法の詳細については、https://realpython.com/jupyter-notebook-introduction/[Jupyter Notebook:An Introduction]を参照してください。

まず、Dockerをインストールする必要があります。 まだDockerを設定していない場合は、https://realpython.com/docker-in-action-fitter-happier-more-productive/[Docker in Action – Fitter、Happier、More Productive]をご覧ください。

注: Dockerイメージは非常に大きくなる可能性があるため、PySparkおよびJupyterを使用するために約5 GBのディスク領域を使用しても問題ないことを確認してください。

次に、次のコマンドを実行して、事前に構築されたPySparkシングルノードセットアップでDockerコンテナーをダウンロードし、自動的に起動できます。 このコマンドは、Spark、PySpark、およびJupyterのすべての要件とともにhttps://hub.docker.com [DockerHub]から画像を直接ダウンロードするため、数分かかる場合があります。

$ docker run -p 8888:8888 jupyter/pyspark-notebook

そのコマンドが出力の印刷を停止すると、シングルノード環境でPySparkプログラムをテストするために必要なすべてを備えた実行中のコンテナーができます。

コンテナを停止するには、 `+ docker run +`コマンドを入力したのと同じウィンドウで[.keys]#Ctrl + C#を入力します。

いよいよいくつかのプログラムを実行します。

PySparkプログラムの実行

PySparkプログラムを実行するには、コマンドラインを使用するか、より視覚的なインターフェースを使用するかに応じて、いくつかの方法があります。 コマンドラインインターフェースの場合、 `+ spark-submit +`コマンド、標準のPythonシェル、または専用のPySparkシェルを使用できます。

最初に、Jupyterノートブックのより視覚的なインターフェースが表示されます。

Jupyterノートブック

Jupyterノートブックでプログラムを実行するには、次のコマンドを実行して、以前にダウンロードしたDockerコンテナーを開始します(まだ実行していない場合)。

$ docker run -p 8888:8888 jupyter/pyspark-notebook
Executing the command: jupyter notebook
[I 08:04:22.869 NotebookApp] Writing notebook server cookie secret to/home/jovyan/.local/share/jupyter/runtime/notebook_cookie_secret
[I 08:04:25.022 NotebookApp] JupyterLab extension loaded from/opt/conda/lib/python3.7/site-packages/jupyterlab
[I 08:04:25.022 NotebookApp] JupyterLab application directory is/opt/conda/share/jupyter/lab
[I 08:04:25.027 NotebookApp] Serving notebooks from local directory:/home/jovyan
[I 08:04:25.028 NotebookApp] The Jupyter Notebook is running at:
[I 08:04:25.029 NotebookApp] http://(4d5ab7a93902 or 127.0.0.1):8888/?token=80149acebe00b2c98242aa9b87d24739c78e562f849e4437
[I 08:04:25.029 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[C 08:04:25.037 NotebookApp]

    To access the notebook, open this file in a browser:
        file:///home/jovyan/.local/share/jupyter/runtime/nbserver-6-open.html
    Or copy and paste one of these URLs:
        http://(4d5ab7a93902 or 127.0.0.1):8888/?token=80149acebe00b2c98242aa9b87d24739c78e562f849e4437

これで、PySparkで実行されているコンテナーができました。 `+ docker run +`コマンド出力の最後にローカルURLが記載されていることに注意してください。

*注意:*トークン、コンテナID、およびコンテナ名はすべてランダムに生成されるため、 `+ docker +`コマンドからの出力はすべてのマシンでわずかに異なります。

このURLを使用して、WebブラウザーでJupyterを実行しているDockerコンテナーに接続する必要があります。 URLをコピーして、出力から* Webブラウザーに直接貼り付けます。 表示される可能性が高いURLの例を次に示します。

$ http://127.0.0.1:8888/?token=80149acebe00b2c98242aa9b87d24739c78e562f849e4437

以下のコマンドのURLはマシンによって多少異なる可能性がありますが、ブラウザーでそのURLに接続すると、次のようなJupyterノートブック環境にアクセスできます。

Jupyter Notebook homepage、width = 2552、height = 802

Jupyterノートブックページから、右端の[新規]ボタンを使用して、新しいPython 3シェルを作成できます。 次に、前の `+ Hello World +`の例のようなコードをテストできます。

import pyspark
sc = pyspark.SparkContext('local[*]')

txt = sc.textFile('file:////usr/share/doc/python/copyright')
print(txt.count())

python_lines = txt.filter(lambda line: 'python' in line.lower())
print(python_lines.count())

Jupyterノートブックでそのコードを実行すると次のようになります。

PySpark Hello World in Jupyter Notebook、width = 2556、height = 1104

ここでは舞台裏で多くのことが行われているため、結果が表示されるまでに数秒かかる場合があります。 セルをクリックしてもすぐに答えは表示されません。

コマンドラインインターフェース

コマンドラインインターフェースは、PySparkシェルや `+ spark-submit +`コマンドなど、PySparkプログラムを送信するためのさまざまな方法を提供します。 これらのCLIアプローチを使用するには、まずPySparkがインストールされているシステムのCLIに接続する必要があります。

DockerセットアップのCLIに接続するには、以前のようにコンテナーを起動してから、そのコンテナーに接続する必要があります。 繰り返しますが、コンテナを起動するには、次のコマンドを実行できます。

$ docker run -p 8888:8888 jupyter/pyspark-notebook

Dockerコンテナーを実行したら、Jupyterノートブックの代わりにシェル経由で接続する必要があります。 これを行うには、次のコマンドを実行してコンテナ名を見つけます。

$ docker container ls
CONTAINER ID        IMAGE                      COMMAND                  CREATED             STATUS              PORTS                    NAMES
4d5ab7a93902        jupyter/pyspark-notebook   "tini -g -- start-no…"   12 seconds ago      Up 10 seconds       0.0.0.0:8888->8888/tcp   kind_edison

このコマンドは、実行中のすべてのコンテナーを表示します。 `+ jupyter/pyspark-notebook `イメージを実行しているコンテナーの ` CONTAINER ID `を見つけ、それを使用してコンテナーの_inside_内の ` bash +`シェルに接続します。

$ docker exec -it 4d5ab7a93902 bash
[email protected]:~$

これで、 `+ bash `プロンプト_container_の内部に接続されます。 シェルのプロンプトが ` jovyan @ 4d5ab7a93902 +`に似たものに変わりますが、コンテナーの一意のIDを使用するため、動作していることを確認できます。

注意: `+ 4d5ab7a93902 `をマシンで使用されている ` CONTAINER ID +`に置き換えます。

クラスタ

Sparkと一緒にインストールされた `+ spark-submit +`コマンドを使用して、コマンドラインを使用してクラスターにPySparkコードを送信できます。 このコマンドは、PySparkまたはScalaプログラムを受け取り、クラスターで実行します。 これはおそらく、実際のビッグデータ処理ジョブを実行する方法です。

*注意:*これらのコマンドへのパスは、Sparkがインストールされた場所に依存し、おそらく、参照されたDockerコンテナを使用する場合にのみ機能します。

実行中のDockerコンテナで `+ Hello World +`サンプル(またはPySparkプログラム)を実行するには、まず上記のようにシェルにアクセスします。 コンテナのシェル環境に入ったら、https://www.lifewire.com/beginners-guide-to-nano-editor-3859002 [nano text editor]を使用してファイルを作成できます。

現在のフォルダーにファイルを作成するには、作成するファイルの名前で `+ nano +`を起動するだけです:

$ nano hello_world.py

`+ Hello World +`の例の内容を入力し、[。keys]#Ctrl + X#と入力して保存プロンプトに従ってファイルを保存します。

Nano Text Editorを使用した例、width = 2556、height = 1438

最後に、 `+ pyspark-submit +`コマンドを使用してSparkでコードを実行できます。

$/usr/local/spark/bin/spark-submit hello_world.py

このコマンドの結果、デフォルトで_大量の出力が発生するため、プログラムの出力を確認するのが困難になる場合があります。 `+ SparkContext +`変数のレベルを変更することで、PySparkプログラム内でログの詳細度をある程度制御できます。 それには、次の行をスクリプトの上部近くに配置します。

sc.setLogLevel('WARN')

これにより、 `+ spark-submit +`の出力の_some_が省略されるため、プログラムの出力をより明確に確認できます。 ただし、実際のシナリオでは、後でデバッグしやすくするために、出力をファイル、データベース、またはその他のストレージメカニズムに配置する必要があります。

幸いなことに、PySparkプログラムは引き続きPythonのすべての標準ライブラリにアクセスできるため、結果をファイルに保存することは問題ではありません。

import pyspark
sc = pyspark.SparkContext('local[*]')

txt = sc.textFile('file:////usr/share/doc/python/copyright')
python_lines = txt.filter(lambda line: 'python' in line.lower())

with open('results.txt', 'w') as file_obj:
    file_obj.write(f'Number of lines: {txt.count()}\n')
    file_obj.write(f'Number of lines with python: {python_lines.count()}\n')

これで、後で参照しやすくするために、結果が `+ results.txt +`という別のファイルに保存されます。

*注意:*上記のコードはhttps://realpython.com/python-f-strings/[f-strings]を使用します。これはPython 3.6で導入されました。

PySparkシェル

プログラムを実行するPySpark固有のもう1つの方法は、PySpark自体で提供されるシェルを使用することです。 繰り返しますが、Dockerセットアップを使用して、上記のようにコンテナのCLIに接続できます。 次に、次のコマンドで特殊なPythonシェルを実行できます。

$/usr/local/spark/bin/pyspark
Python 3.7.3 | packaged by conda-forge | (default, Mar 27 2019, 23:01:00)
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
Using Spark's default log4j profile: org/apache/spark/log4j-defaults.properties
Setting default log level to "WARN".
To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).
Welcome to
      ____              __
    /__/__  ___ _____//__
    _\ \/_ \/_ `/__/ '_/
  /__/.__/\_,_/_//_/\_\   version 2.4.1
     /_/

Using Python version 3.7.3 (default, Mar 27 2019 23:01:00)
SparkSession available as 'spark'.

これで、Dockerコンテナー_inside_のPysparkシェル環境で、Jupyterノートブックの例に似たコードをテストできます。

>>>

>>> txt = sc.textFile('file:////usr/share/doc/python/copyright')
>>> print(txt.count())
316

これで、通常のPythonシェルと同じようにPysparkシェルで作業できます。

注意: Pysparkシェルの例では、 `+ SparkContext `変数を作成する必要はありませんでした。 PySparkシェルは自動的に変数「 sc +」を作成し、シングルノードモードでSparkエンジンに接続します。

`+ spark-submit `またはJupyterノートブックを使用して実際のPySparkプログラムを送信するときは、*独自の ` SparkContext +`を作成する必要があります。

PySparkがPython環境にインストールされている限り、標準のPythonシェルを使用してプログラムを実行することもできます。 使用していたDockerコンテナでは、標準のPython環境でPySparkが有効になっていません。 そのため、DockerコンテナでPySparkを使用するには、前述のいずれかの方法を使用する必要があります。

PySparkと他のツールの組み合わせ

既に見たように、PySparkには、機械学習やSQLのような大規模なデータセットの操作などを行うための追加のライブラリが付属しています。 ただし、https://realpython.com/numpy-array-programming/[NumPy]やhttps://realpython.com/courses/pandas-dataframes-101/[Pandas]などの他の一般的な科学ライブラリも使用できます。

これらを同じ環境に*各クラスターノード*にインストールする必要があります。その後、プログラムは通常どおり使用できます。 次に、おなじみのhttps://realpython.com/courses/idiomatic-pandas-tricks-features-you-may-not-know/[idiomatic Pandas]のトリックをすべて自由に使用できます。

注意: Pandas DataFramesは熱心に評価されているため、すべてのデータは* 1台のマシン*でメモリに収まる必要があります。

実際のビッグデータ処理の次のステップ

PySparkの基本を学んだらすぐに、シングルマシンモードを使用していると機能しない可能性が高い膨大な量のデータの分析を確実に開始する必要があります。 Sparkクラスターのインストールとメンテナンスは、このガイドの範囲外であり、それ自体がフルタイムの仕事である可能性があります。

そのため、オフィスのIT部門を訪問するか、ホストされているSparkクラスターソリューションを検討する時間になるかもしれません。 ホストされる可能性のあるソリューションの1つは、https://databricks.com/spark/about [Databricks]です。

Databricksでは、https://azure.microsoft.com/en-us/[Microsoft Azure]またはhttps://aws.amazon.com [AWS]でデータをホストでき、https://databricks.com/があります。 try-databricks [14日​​間無料トライアル]。

動作中のSparkクラスターができたら、すべてのデータを分析のためにそのクラスターに取り込みます。 Sparkには、データをインポートする方法がいくつかあります。

  1. Amazon S3

  2. https://hive.apache.org [Apache Hive Data Warehouse]

  3. JDBCまたはhttps://en.wikipedia.org/wiki/Open_Database_Connectivity[ODBC]インターフェイスを持つデータベース

Network File Systemから直接データを読み取ることもできます。これは、前の例の仕組みです。

Databricksのようなホスト型ソリューションを使用している場合でも、独自のマシンのクラスターを使用している場合でも、すべてのデータにアクセスする方法が不足することはありません。

結論

PySparkは、ビッグデータ処理への優れたエントリポイントです。

このチュートリアルでは、「+ map()」、「 filter()+」などの関数型プログラミングの概念に精通していれば、事前に多くの時間を費やす必要がないことを学びました。およびhttps://realpython.com/learning-paths/python3-introduction/[basic Python]。 実際、NumPyやPandasなどの使い慣れたツールを含め、PySparkプログラムで直接知っているすべてのPythonを使用できます。

次のことができるようになりました。

  • ビッグデータに適用される組み込みのPythonの概念を理解する

  • *書き込み*基本的なPySparkプログラム

  • ローカルマシンで小さなデータセットでPySparkプログラムを実行する

  • Sparkクラスターまたは別のカスタムホストソリューションのような、より能力のあるビッグデータソリューションを*探索*