All Products
Search
Document Center

E-MapReduce:Use Spark to access DataHub

Last Updated:Mar 26, 2026

E-MapReduce (EMR) Hadoop clusters support two Spark APIs for consuming DataHub data: Spark Streaming and Spark Structured Streaming. This topic shows how to set up each approach with working code examples.

Choose an API

Spark StreamingSpark Structured Streaming
API generationOlder (DStream-based)Newer (DataFrame-based)
Offset managementDataHub manages offsets via a subscription (subId)Spark manages offsets internally — no subId needed
Shard controlConsume a single shard or all shardsReads all shards automatically
Use whenYou need shard-level control or are maintaining existing codeStarting a new pipeline or prefer the DataFrame API

Use Spark Streaming to consume DataHub data

Prerequisites

Before you begin, ensure that you have:

  • An EMR Hadoop cluster

  • A DataHub topic with at least one shard

  • A DataHub subscription ID (subId) — see Create a subscription

Consume data from a specific shard

Pass a shardId to DatahubUtils.createStream to read from one shard:

datahubStream = DatahubUtils.createStream(
  ssc,
  project,        // DataHub project name
  topic,          // DataHub topic name
  subId,          // DataHub subscription ID
  accessKeyId,
  accessKeySecret,
  endpoint,       // DataHub endpoint
  shardId,        // ID of the shard to consume
  read,           // Function to process each RecordEntry
  StorageLevel.MEMORY_AND_DISK)

datahubStream.foreachRDD(rdd => println(rdd.count()))

// Read data from the first field in RecordEntry
def read(record: RecordEntry): String = {
  record.getString(0)
}

Consume data from all shards

Omit the shardId argument to consume from all shards in the topic:

datahubStream = DatahubUtils.createStream(
  ssc,
  project,        // DataHub project name
  topic,          // DataHub topic name
  subId,          // DataHub subscription ID
  accessKeyId,
  accessKeySecret,
  endpoint,       // DataHub endpoint
  read,           // Function to process each RecordEntry
  StorageLevel.MEMORY_AND_DISK)

datahubStream.foreachRDD(rdd => println(rdd.count()))

// Read data from the first field in RecordEntry
def read(record: RecordEntry): String = {
  record.getString(0)
}
Note

For the complete sample code, see SparkDatahubDemo.scala.

Use Spark Structured Streaming to consume DataHub data

Spark Structured Streaming treats DataHub as a streaming source and manages offsets internally. You do not need a DataHub subscription ID (subId).

Add the dependency

Spark 2

Add the following Maven dependency:

<dependency>
  <groupId>com.aliyun.emr</groupId>
  <artifactId>emr-datahub_2.11</artifactId>
  <version>2.0.0</version>
</dependency>

Spark 3

Download emr-datasources_shaded_***.jar from the cluster directory /opt/apps/SPARK-EXTENSION/spark-extension-current/spark3-emrsdk/ and add it as a dependency.

Note

If that directory does not exist in your cluster, use /usr/lib/emrsdk-current/ instead. Replace emr-datasources_shaded_***.jar with the actual filename in your cluster directory.

Read and process DataHub data

The following example creates a read stream from DataHub, groups records by key, and writes counts to the console:

val spark = SparkSession
  .builder()
  .appName("test datahub")
  .getOrCreate()

// Create a read stream from DataHub
val datahubRows = spark
  .readStream
  .format("datahub")
  .option("access.key.id", System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"))
  .option("access.key.secret", System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"))
  .option("endpoint", "https://dh-cn-hangzhou.aliyuncs.com")
  .option("project", "project_test")
  .option("topic", "topic_test")
  .option("startingoffsets", "earliest")
  .load

// The schema has two fields: key and value
datahubRows.printSchema()
println("print schema" + datahubRows.schema.toString())
val df = datahubRows.groupBy("key").count()

// Write aggregated results to the console
val query = df
  .writeStream
  .format("console")
  .outputMode("complete")
  .start()

query.awaitTermination(100000)
spark.close()

The core process:

  1. Create a read stream to load data from DataHub into a DataFrame.

  2. Apply processing logic to the DataFrame.

  3. Create a write stream to output the results.

Important

Configure environment variables before running this code. For details, see Configure environment variables.

Parameters

Required

ParameterDescription
access.key.idAccessKey ID of the Alibaba Cloud account used to create the DataHub project
access.key.secretAccessKey secret of the Alibaba Cloud account used to create the DataHub project
endpointEndpoint of the DataHub API. View the endpoint on the DataHub page.
projectName of the DataHub project
topicName of the DataHub topic

Optional

ParameterDescription
startingoffsetsOffset from which data consumption starts. Valid values: latest, earliest, or a JSON string specifying per-shard offsets (see below).
endingoffsetsOffset at which data consumption ends. Valid values: latest or a JSON string specifying per-shard offsets (see below).
decimal.precisionRequired if the topic contains a field of the DECIMAL type.
decimal.scaleRequired if the topic contains a field of the DECIMAL type.

JSON format for per-shard offsets

Use the following format to specify offsets for individual shards:

{
  "<project>#<topic>": {
    "<shardId>": "<offset>"
  }
}

Example:

{
  "project_test#topic_test": {
    "0": "100"
  }
}