All Products
Search
Document Center

E-MapReduce:Spark Load

Last Updated:Mar 25, 2026

Spark Load is an asynchronous bulk import method that uses external Spark cluster resources to preprocess and load data into Doris. It is designed for initial large-scale data migrations from Hadoop Distributed File System (HDFS) or Hive tables—data volumes of more than 10 GB to terabytes—where offloading ETL work to Spark significantly reduces the compute load on your Doris cluster.

Submit and manage Spark Load jobs using the MySQL protocol. View job status with the SHOW LOAD command.

For smaller data volumes or data stored outside Spark-accessible systems, use Stream Load or Broker Load instead. Broker Load requires no Spark cluster but consumes more Doris cluster resources.

Prerequisites

Before you begin, ensure that you have:

  • A running Spark cluster (version 2.4.5 or later)

  • A running Hadoop cluster with YARN (version 2.5.2 or later) if using YARN mode

  • Access to HDFS or a Hive table containing your source data

  • USAGE_PRIV permission on the Spark resource in Doris

  • enable_spark_load set to true in fe.conf

Key concepts

Spark ETL The ETL job runs on Spark and preprocesses data before it enters Doris. Preprocessing includes building global dictionaries (for BITMAP columns), partitioning, sorting, and aggregating data.

Broker An independent stateless process that provides Doris with read access to remote storage systems such as HDFS. The frontend (FE) node and backend (BE) nodes use brokers to transfer ETL output files.

Global dictionary A mapping structure that converts raw column values to integer-encoded values. Required when importing data into BITMAP aggregate columns using roaring bitmaps. A global dictionary can only be created when the data source is a Hive table.

Use cases

Spark Load is suited for:

  • Initial bulk migration: Loading more than 10 GB to TBs of historical data into Doris for the first time

  • HDFS-based sources: Data stored in HDFS or Hive tables accessible from Spark

  • BITMAP preprocessing: Data with columns that require global dictionary encoding before import

How it works

Submit a Spark Load job through the MySQL client. The FE node records metadata and returns a success acknowledgment. The job then runs through five stages:

                 |
            +----v----+
            |   FE    |---------------------------------+
            +----+----+                                 |
                 | 3. FE send push tasks                |
                 | 5. FE publish version                |
    +------------+------------+                         |
    |            |            |                         |
+---v---+    +---v---+    +---v---+                     |
|  BE   |    |  BE   |    |  BE   |                     |1. FE submit Spark ETL job
+---^---+    +---^---+    +---^---+                     |
    |4. BE push with broker   |                         |
+---+---+    +---+---+    +---+---+                     |
|Broker |    |Broker |    |Broker |                     |
+---^---+    +---^---+    +---^---+                     |
    |            |            |                         |
+---+------------+------------+---+ 2.ETL +-------------v---------------+
|               HDFS              +------->       Spark cluster         |
|                                 <-------+                             |
+---------------------------------+       +-----------------------------+
  1. The FE node submits an extract, transform, and load (ETL) job to the Spark cluster.

  2. The Spark cluster runs the ETL job: builds global dictionaries, partitions, sorts, and aggregates data.

  3. The FE node retrieves the preprocessed data directories and schedules BE nodes to run push jobs.

  4. BE nodes pull files from HDFS using brokers and convert them into Doris storage format.

  5. The FE node publishes a new version, completing the import.

Global dictionary

When it's needed

Doris BITMAP columns use roaring bitmaps, which require integer input. When importing data into BITMAP aggregate columns, Spark Load can build a global dictionary to encode raw values as integers during the ETL phase. The dictionary is stored as a Hive table structure mapping original values to encoded values.

Important

Global dictionaries can only be created when importing from a Hive table, not from HDFS files directly.

How it's built

  1. Read source data into a temporary Hive table (hive_table).

  2. Deduplicate values and store distinct raw values in distinct_value_table.

  3. Create a dict_table with columns for raw values and encoded values.

  4. Perform a LEFT JOIN on distinct_value_table and dict_table, encode new values using a window function, and write results back to dict_table.

  5. Join dict_table with hive_table to replace raw values with encoded integers.

  6. Feed the encoded hive_table into the remaining ETL pipeline for import into Doris.

Data preprocessing (DPP)

The Spark ETL job runs the following DPP steps:

  1. Read data from HDFS or a Hive table.

  2. Apply field mappings and expression-based transformations. Generate a bucket_id field for data bucketing based on partition metadata.

  3. Build rollup trees from Doris table rollup metadata.

  4. Traverse rollup trees to aggregate data layer by layer, where each layer is derived from the previous one.

  5. Distribute aggregated data to buckets based on bucket_id and write to HDFS.

  6. Brokers pull the output files from HDFS and push them to Doris BE nodes.

Hive Bitmap UDF

Spark Load supports directly importing bitmap data generated in Hive into Doris using the Hive Bitmap UDF.

Configure a Spark resource

Before submitting a Spark Load job, register the Spark cluster as an external resource in Doris. Doris uses its Resource Management module to track and manage external resources.

Create a resource

CREATE EXTERNAL RESOURCE resource_name
PROPERTIES
(
  type = spark,
  spark_conf_key = spark_conf_value,
  working_dir = path,
  broker = broker_name,
  broker.property_key = property_value,
  broker.hadoop.security.authentication = kerberos,
  broker.kerberos_principal = doris@YOUR.COM,
  broker.kerberos_keytab = /home/doris/my.keytab
  broker.kerberos_keytab_content = ASDOWHDLAWI********ALDJSDIWALD
)

The following table describes the key parameters:

ParameterRequiredDescription
typeYesSet to spark.
spark.masterYesSet to yarn or spark://host:port.
spark.submit.deployModeYesDeployment mode: cluster or client.
spark.hadoop.yarn.resourcemanager.addressWhen spark.master=yarnYARN ResourceManager address.
spark.hadoop.fs.defaultFSWhen spark.master=yarnDefault HDFS filesystem address.
working_dirYes (for ETL)HDFS directory where ETL output is stored. Example: hdfs://host:port/tmp/doris.
brokerYes (for ETL)Name of the broker registered with ALTER SYSTEM ADD BROKER.
broker.property_keyNoAuthentication properties for the broker to read ETL intermediate files.
broker.hadoop.security.authenticationWhen using KerberosSet to kerberos.
broker.kerberos_principalWhen using KerberosKerberos principal for authentication.
broker.kerberos_keytabWhen using KerberosPath to the keytab file on the broker server.
broker.kerberos_keytab_contentWhen using KerberosBase64-encoded content of the keytab file. Use either this or broker.kerberos_keytab.

For a full list of Spark configuration parameters, see Spark Configuration.

Example: YARN cluster mode

CREATE EXTERNAL RESOURCE "spark0"
PROPERTIES
(
  "type" = "spark",
  "spark.master" = "yarn",
  "spark.submit.deployMode" = "cluster",
  "spark.jars" = "xxx.jar,yyy.jar",
  "spark.files" = "/tmp/aaa,/tmp/bbb",
  "spark.executor.memory" = "1g",
  "spark.yarn.queue" = "queue0",
  "spark.hadoop.yarn.resourcemanager.address" = "127.0.0.1:9999",
  "spark.hadoop.fs.defaultFS" = "hdfs://127.0.0.1:10000",
  "working_dir" = "hdfs://127.0.0.1:10000/tmp/doris",
  "broker" = "broker0",
  "broker.username" = "user0",
  "broker.password" = "password0"
);

Example: Spark standalone client mode

CREATE EXTERNAL RESOURCE "spark1"
PROPERTIES
(
  "type" = "spark",
  "spark.master" = "spark://127.0.0.1:7777",
  "spark.submit.deployMode" = "client",
  "working_dir" = "hdfs://127.0.0.1:10000/tmp/doris",
  "broker" = "broker1"
);

Example: Kerberos-authenticated cluster

CREATE EXTERNAL RESOURCE "spark_on_kerberos"
PROPERTIES
(
  "type" = "spark",
  "spark.master" = "yarn",
  "spark.submit.deployMode" = "cluster",
  "spark.jars" = "xxx.jar,yyy.jar",
  "spark.files" = "/tmp/aaa,/tmp/bbb",
  "spark.executor.memory" = "1g",
  "spark.yarn.queue" = "queue0",
  "spark.hadoop.yarn.resourcemanager.address" = "127.0.0.1:9999",
  "spark.hadoop.fs.defaultFS" = "hdfs://127.0.0.1:10000",
  "working_dir" = "hdfs://127.0.0.1:10000/tmp/doris",
  "broker" = "broker0",
  "broker.hadoop.security.authentication" = "kerberos",
  "broker.kerberos_principal" = "doris@YOUR.COM",
  "broker.kerberos_keytab" = "/home/doris/my.keytab"
);

Manage resources

View resources

SHOW RESOURCES
SHOW PROC "/resources"

Ordinary accounts can only see resources for which they have USAGE_PRIV. Root and admin accounts see all resources.

Grant and revoke permissions

-- Grant USAGE_PRIV on a specific resource to a user
GRANT USAGE_PRIV ON RESOURCE "spark0" TO "user0"@"%";

-- Grant USAGE_PRIV on a specific resource to a role
GRANT USAGE_PRIV ON RESOURCE "spark0" TO ROLE "role0";

-- Grant USAGE_PRIV on all resources to a user
GRANT USAGE_PRIV ON RESOURCE * TO "user0"@"%";

-- Grant USAGE_PRIV on all resources to a role
GRANT USAGE_PRIV ON RESOURCE * TO ROLE "role0";

-- Revoke USAGE_PRIV on a specific resource from a user
REVOKE USAGE_PRIV ON RESOURCE "spark0" FROM "user0"@"%";

Drop a resource

DROP RESOURCE resource_name

Configure the Spark client

The FE node runs spark-submit internally to dispatch Spark Load jobs. Configure the Spark client on the FE node before submitting any jobs. Download Spark 2.4.5 or a later 2.x version.

Configure the Spark home directory

Place the Spark client in a directory on the same machine as the FE node. Set spark_home_default_dir in fe.conf to point to this directory. The default value is lib/spark2x relative to the FE root. This parameter cannot be blank.

Configure the Spark dependency package

Package all JAR files in the Spark client's jars/ folder into a ZIP file. Set spark_resource_path in fe.conf to the path of this ZIP file. If left blank, the FE node looks for lib/spark2x/jars/spark-2x.zip in its root directory and returns an error if the file is not found.

When a Spark Load job is submitted, the dependency package is uploaded to a remote directory in HDFS. The remote path follows this structure:

__spark_repository__spark0/
    |-__archive_1.0.0/
    |        |-__lib_990325d2c0d1d5e45bf675e54e44fb16_spark-dpp-1.0.0-jar-with-dependencies.jar
    |        |-__lib_7670c29daf535efe3c9b923f778f61fc_spark-2x.zip
    |-__archive_1.1.0/
    |        |-__lib_64d5696f99c379af2bee28c1c84271d5_spark-dpp-1.1.0-jar-with-dependencies.jar
    |        |-__lib_1bbb74bb6b264a270bc7fca3e964160f_spark-2x.zip
    |-__archive_1.2.0/
    |        |-...

The remote path is located in working_dir/{cluster_id} and named _spark_repository_{resource_name}. The FE node also uploads the Dynamic Partition Pruning (DPP) dependency package alongside spark-2x.zip. If the dependency files already exist in the remote repository, they are not re-uploaded.

Configure the YARN client

The FE node uses YARN commands to query application status and terminate applications. Configure the YARN client on the FE node. Download Hadoop 2.5.2 or a later 2.x version.

Configure the YARN executable path

Place the YARN client on the same machine as the FE node. Set yarn_client_path in fe.conf to the path of the YARN binary executable. The default value is lib/yarn-client/hadoop/bin/yarn relative to the FE root.

Configure the YARN config directory (optional)

When the FE node runs YARN commands, it generates core-site.xml and yarn-site.xml in a temporary config directory. The default path is lib/yarn-config relative to the FE root. To change this path, set yarn_config_dir in fe.conf.

Submit a Spark Load job

For the full syntax reference, run HELP SPARK LOAD in the MySQL client.

Syntax

LOAD LABEL load_label
    (data_desc, ...)
    WITH RESOURCE resource_name
    [resource_properties]
    [PROPERTIES (key1=value1, ... )]

-- load_label:
    db_name.label_name

-- data_desc (HDFS file):
    DATA INFILE ('file_path', ...)
    [NEGATIVE]
    INTO TABLE tbl_name
    [PARTITION (p1, p2)]
    [COLUMNS TERMINATED BY separator]
    [(col1, ...)]
    [COLUMNS FROM PATH AS (col2, ...)]
    [SET (k1=f1(xx), k2=f2(xx))]
    [WHERE predicate]

-- data_desc (Hive table):
    DATA FROM TABLE hive_external_tbl
    [NEGATIVE]
    INTO TABLE tbl_name
    [PARTITION (p1, p2)]
    [SET (k1=f1(xx), k2=f2(xx))]
    [WHERE predicate]

-- resource_properties:
    (key2=value2, ...)

Supported data sources are CSV files in HDFS and Hive external tables. Other rules follow Broker Load conventions.

Parameters

Data description parameters

Only CSV files and Hive tables are supported as data sources. Other rules are consistent with Broker Load.

Job parameters

Job parameters (set in PROPERTIES) apply to the entire import job and follow the same rules as Broker Load.

Per-job Spark resource overrides

To override Spark resource settings for a single job without changing the cluster-level resource configuration, specify overrides inline:

WITH RESOURCE 'spark0'
(
  "spark.driver.memory" = "1g",
  "spark.executor.memory" = "3g"
)

Overrides apply only to the current job.

Examples

Example 1: Import from HDFS files

LOAD LABEL db1.label1
(
    DATA INFILE("hdfs://abc.com:8888/user/palo/test/ml/file1")
    INTO TABLE tbl1
    COLUMNS TERMINATED BY ","
    (tmp_c1,tmp_c2)
    SET
    (
        id=tmp_c2,
        name=tmp_c1
    ),
    DATA INFILE("hdfs://abc.com:8888/user/palo/test/ml/file2")
    INTO TABLE tbl2
    COLUMNS TERMINATED BY ","
    (col1, col2)
    where col1 > 1
)
WITH RESOURCE 'spark0'
(
    "spark.executor.memory" = "2g",
    "spark.shuffle.compress" = "true"
)
PROPERTIES
(
    "timeout" = "3600"
);

Example 2: Import from a Hive table

First, create an external Hive table in Doris:

CREATE EXTERNAL TABLE hive_t1
(
    k1 INT,
    K2 SMALLINT,
    k3 varchar(50),
    uuid varchar(100)
)
ENGINE=hive
properties
(
  "database" = "tmp",
  "table" = "t1",
  "hive.metastore.uris" = "thrift://0.0.0.0:8080"
);

Then submit the load job. The columns in the Doris target table must exist in the external Hive table:

LOAD LABEL db1.label1
(
    DATA FROM TABLE hive_t1
    INTO TABLE tbl1
    SET
    (
        uuid=bitmap_dict(uuid)
    )
)
WITH RESOURCE 'spark0'
(
    "spark.executor.memory" = "2g",
    "spark.shuffle.compress" = "true"
)
PROPERTIES
(
    "timeout" = "3600"
);

Example 3: Import BINARY bitmap data from a Hive table

Use this approach when the source Hive column is of type BINARY and the data was serialized using the org.apache.doris.load.loadv2.dpp.BitmapValue class from spark-dpp.

Create the external Hive table:

CREATE EXTERNAL TABLE hive_t1
(
    k1 INT,
    K2 SMALLINT,
    k3 varchar(50),
    uuid varchar(100) -- BINARY type in the Hive table
)
ENGINE=hive
properties
(
  "database" = "tmp",
  "table" = "t1",
  "hive.metastore.uris" = "thrift://0.0.0.0:8080"
);

Submit the load job using binary_bitmap:

LOAD LABEL db1.label1
(
    DATA FROM TABLE hive_t1
    INTO TABLE tbl1
    SET
    (
        uuid=binary_bitmap(uuid)
    )
)
WITH RESOURCE 'spark0'
(
    "spark.executor.memory" = "2g",
    "spark.shuffle.compress" = "true"
)
PROPERTIES
(
    "timeout" = "3600"
);
Important

binary_bitmap requires a Hive table as the data source.

Example 4: Import from a partitioned Hive table

Hive table definition:

CREATE TABLE test_partition(
    id int,
    name string,
    age int
)
PARTITIONED BY (dt string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
STORED AS TEXTFILE;

Doris target table definition:

CREATE TABLE IF NOT EXISTS test_partition_04
(
    dt date,
    id int,
    name string,
    age int
)
UNIQUE KEY(`dt`, `id`)
DISTRIBUTED BY HASH(`id`) BUCKETS 1
PROPERTIES (
    "replication_allocation" = "tag.location.default: 1"
);

Create the Spark resource and submit the load job:

CREATE EXTERNAL RESOURCE "spark_resource"
PROPERTIES
(
  "type" = "spark",
  "spark.master" = "yarn",
  "spark.submit.deployMode" = "cluster",
  "spark.executor.memory" = "1g",
  "spark.yarn.queue" = "default",
  "spark.hadoop.yarn.resourcemanager.address" = "localhost:50056",
  "spark.hadoop.fs.defaultFS" = "hdfs://localhost:9000",
  "working_dir" = "hdfs://localhost:9000/tmp/doris",
  "broker" = "broker_01"
);

LOAD LABEL demo.test_hive_partition_table_18
(
    DATA INFILE("hdfs://localhost:9000/user/hive/warehouse/demo.db/test/dt=2022-08-01/*")
    INTO TABLE test_partition_04
    COLUMNS TERMINATED BY ","
    FORMAT AS "csv"
    (id,name,age)
    COLUMNS FROM PATH AS (`dt`)
    SET
    (
        dt=dt,
        id=id,
        name=name,
        age=age
    )
)
WITH RESOURCE 'spark_resource'
(
    "spark.executor.memory" = "1g",
    "spark.shuffle.compress" = "true"
)
PROPERTIES
(
    "timeout" = "3600"
);

Global dictionary in load jobs

When the target Doris table has a BITMAP aggregate column, specify bitmap_dict in the SET clause to trigger global dictionary creation:

SET (doris_field_name = bitmap_dict(hive_field_name))
Important

Global dictionary creation is only supported when the data source is a Hive table.

View import jobs

Spark Load jobs are asynchronous. Record the job label when you submit a job, then use it to check status:

SHOW LOAD ORDER BY createtime DESC LIMIT 1\G

Example output:

*************************** 1. row ***************************
         JobId: 76391
         Label: label1
         State: FINISHED
      Progress: ETL:100%; LOAD:100%
          Type: SPARK
       EtlInfo: unselected.rows=4; dpp.abnorm.ALL=15; dpp.norm.ALL=28133376
      TaskInfo: cluster:cluster0; timeout(s):10800; max_filter_ratio:5.0E-5
      ErrorMsg: N/A
    CreateTime: 2019-07-27 11:46:42
  EtlStartTime: 2019-07-27 11:46:44
 EtlFinishTime: 2019-07-27 11:49:44
 LoadStartTime: 2019-07-27 11:49:44
LoadFinishTime: 2019-07-27 11:50:16
           URL: http://1.1.*.*:80**/proxy/application_15866****3848_0035/
    JobDetails: {"ScannedRows":28133395,"TaskNumber":1,"FileNumber":1,"FileSize":200000}

Spark Load-specific fields differ from Broker Load as follows:

FieldDescription
StateJob lifecycle: PENDINGETLLOADINGFINISHED (or CANCELLED on failure).
ProgressTwo components: ETL (Spark preprocessing progress) and LOAD (BE push progress). LOAD progress is calculated as: number of imported tablets in all replicas / total number of tablets in the import job × 100%. LOAD reaches 99% when all tablets are pushed; it becomes 100% only after the version is published.
TypeAlways SPARK for Spark Load jobs.
JobDetailsUpdated after the ETL phase. Includes scanned rows, task count, file count, and file size.
URLLink to the YARN application page for the ETL job.
Import progress is not linear. A period without progress does not necessarily mean the job is stuck.

For a complete description of all fields, see Broker Load.

View logs

Spark Load generates a log file when a job is submitted. Logs are stored at:

{FE_ROOT}/log/spark_launcher_log/spark_launcher_{load_job_id}_{label}.log

Logs are retained for three days and deleted together with the job metadata from the FE node.

Cancel a job

If the import job is not in the FINISHED or CANCELLED state, you can cancel the import job by specifying its label. For the full syntax, run HELP CANCEL LOAD.

System configurations

The following fe.conf parameters apply globally to all Spark Load jobs:

ParameterDefaultDescription
enable_spark_loadfalseEnable Spark Load and external resource creation. Set to true to activate.
spark_load_default_timeout_second259200 (3 days)Default job timeout in seconds.
spark_home_default_dirfe/lib/spark2xRoot directory of the Spark client.
spark_resource_path(empty)Path to the packaged Spark dependency ZIP file.
spark_launcher_log_dirfe/log/spark_launcher_logDirectory for Spark Load log files.
yarn_client_pathfe/lib/yarn-client/hadoop/bin/yarnPath to the YARN binary executable.
yarn_config_dirfe/lib/yarn-configDirectory where YARN config files (core-site.xml, yarn-site.xml) are generated.

What's next

  • Broker Load — simpler import method for smaller datasets or non-Spark environments

  • Stream Load — synchronous import for real-time or small-batch scenarios