<commit_before>---
title: "Getting started from Apache Spark"
---
<!--
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

# Getting started from Apache Spark

{{< localstorage language language-py >}}

If you already know [_Apache Spark_](http://spark.apache.org/),
learning _Apache Beam_ is easy.
The Beam and Spark APIs are similar, so you already know the basic concepts.

Spark stores data _Spark DataFrames_ for structured data,
and in _Resilient Distributed Datasets_ (RDD) for unstructured data.
We are using RDDs for this guide.

A _Spark RDD_ represents a collection of elements,
while in Beam it's called a _Parallel Collection_ (PCollection).
A PCollection in Beam does _not_ have any ordering guarantees.

Likewise, a transform in Beam is called a _Parallel Transform_ (PTransform).

Here are some examples of common operations and their equivalent between PySpark and Beam.

## Overview

Here's a simple example of a PySpark pipeline that takes the numbers from one to four,
multiplies them by two, adds all the values together, and prints the result.

{{< highlight py >}}
import pyspark

sc = pyspark.SparkContext()
result = (
    sc.parallelize([1, 2, 3, 4])
    .map(lambda x: x * 2)
    .reduce(lambda x, y: x + y)
)
print(result)
{{< /highlight >}}

In Beam you _pipe_ your data through the pipeline using the
_pipe operator_ `|` like `data | beam.Map(...)` instead of chaining
methods like `data.map(...)`, but they're doing the same thing.

Here's how an equivalent pipeline looks like in Beam.

{{< highlight py >}}
import apache_beam as beam

with beam.Pipeline() as pipeline:
    result = (
        pipeline
        | beam.Create([1, 2, 3, 4])
        | beam.Map(lambda x: x * 2)
        | beam.CombineGlobally(sum)
        | beam.Map(print)
    )
{{< /highlight >}}

> ℹ️ Note that we called `print` inside a `Map` transform.
> That's because we can only access the elements of a PCollection
> from within a PTransform.

Another thing to note is that Beam pipelines are constructed _lazily_.
This means that when you _pipe_ `|` data you're only _decalring_ the
transformations and the order you want them to happen,
but the actual computation doesn't happen.
The pipeline is run _after_ the `with beam.Pipeline() as pipeline` context has
closed.
The pipeline is then sent to your runner of choice and it processes the data.

> ℹ️ When the `with beam.Pipeline() as pipeline` context closes,
> it implicitly calls `pipeline.run()` which triggers the computation to happen.

A label can optionally be added to a transform using the
_right shift operator_ `>>` like `data | 'My description' >> beam.Map(...)`.
This serves both as comments and makes your pipeline easier to debug.

This is how the pipeline looks after adding labels.

{{< highlight py >}}
import apache_beam as beam<commit_msg>Added extra explanations<commit_after>---
title: "Getting started from Apache Spark"
---
<!--
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

# Getting started from Apache Spark

{{< localstorage language language-py >}}

If you already know [_Apache Spark_](http://spark.apache.org/),
learning _Apache Beam_ is familiar.
The Beam and Spark APIs are similar, so you already know the basic concepts.

Spark stores data _Spark DataFrames_ for structured data,
and in _Resilient Distributed Datasets_ (RDD) for unstructured data.
We are using RDDs for this guide.

A Spark RDD represents a collection of elements,
while in Beam it's called a _Parallel Collection_ (PCollection).
A PCollection in Beam does _not_ have any ordering guarantees.

Likewise, a transform in Beam is called a _Parallel Transform_ (PTransform).

Here are some examples of common operations and their equivalent between PySpark and Beam.

## Overview

Here's a simple example of a PySpark pipeline that takes the numbers from one to four,
multiplies them by two, adds all the values together, and prints the result.

{{< highlight py >}}
import pyspark

sc = pyspark.SparkContext()
result = (
    sc.parallelize([1, 2, 3, 4])
    .map(lambda x: x * 2)
    .reduce(lambda x, y: x + y)
)
print(result)
{{< /highlight >}}

In Beam you _pipe_ your data through the pipeline using the
_pipe operator_ `|` like `data | beam.Map(...)` instead of chaining
methods like `data.map(...)`, but they're doing the same thing.

Here's what an equivalent pipeline looks like in Beam.

{{< highlight py >}}
import apache_beam as beam

with beam.Pipeline() as pipeline:
    result = (
        pipeline
        | beam.Create([1, 2, 3, 4])
        | beam.Map(lambda x: x * 2)
        | beam.CombineGlobally(sum)
        | beam.Map(print)
    )
{{< /highlight >}}

> ℹ️ Note that we called `print` inside a `Map` transform.
> That's because we can only access the elements of a PCollection
> from within a PTransform.

Another thing to note is that Beam pipelines are constructed _lazily_.
This means that when you pipe `|` data you're only _decalring_ the
transformations and the order you want them to happen,
but the actual computation doesn't happen.
The pipeline is run _after_ the `with beam.Pipeline() as pipeline` context has
closed.

> ℹ️ When the `with beam.Pipeline() as pipeline` context closes,
> it implicitly calls `pipeline.run()` which triggers the computation to happen.

The pipeline is then sent to your
[runner of choice](https://beam.apache.org/documentation/runners/capability-matrix/)
and it processes the data.

> ℹ️ The pipeline can run locally with the _DirectRunner_,
> or in a distributed runner such as Flink, Spark, or Dataflow.
> The Spark runner is not related to PySpark.

A label can optionally be added to a transform using the
_right shift operator_ `>>` like `data | 'My description' >> beam.Map(...)`.
This serves both as comments and makes your pipeline easier to debug.

This is how the pipeline looks after adding labels.

{{< highlight py >}}
import apache_beam as beam
{'fraction_non_alphanumeric': 0.08070894975831258, 'fraction_numerical': 0.004101362238171965, 'mean_word_length': 3.9948792977322602, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 38, 'https://': 1, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4225532', 'n_tokens_mistral': 1983, 'n_tokens_neox': 1899, 'n_words': 951}