spark_catalog, and tables are identified by {catalog name}.{database}.{table}. With the new
catalog feature, it is now possible to add and work with multiple catalogs in a single Spark application.
Choosing Between Catalog API and TableProvider API
The ClickHouse Spark connector supports two access patterns: the Catalog API and the TableProvider API (format-based access). Understanding the differences helps you choose the right approach for your use case.Catalog API vs TableProvider API
Requirements
- Java 8 or 17 (Java 17+ required for Spark 4.0)
- Scala 2.12 or 2.13 (Spark 4.0 only supports Scala 2.13)
- Apache Spark 3.3, 3.4, 3.5, or 4.0
Compatibility matrix
Installation & setup
For integrating ClickHouse with Spark, there are multiple installation options to suit different project setups. You can add the ClickHouse Spark connector as a dependency directly in your project’s build file (such as inpom.xml
for Maven or build.sbt for SBT).
Alternatively, you can put the required JAR files in your $SPARK_HOME/jars/ folder, or pass them directly as a Spark
option using the --jars flag in the spark-submit command.
Both approaches ensure the ClickHouse connector is available in your Spark environment.
Import as a Dependency
- Maven
- Gradle
- SBT
- Spark SQL/Shell CLI
Download the library
The name pattern of the binary JAR is:Register the catalog (required)
In order to access your ClickHouse tables, you must configure a new Spark catalog with the following configs:
These settings could be set via one of the following:
- Edit/Create
spark-defaults.conf. - Pass the configuration to your
spark-submitcommand (or to yourspark-shell/spark-sqlCLI commands). - Add the configuration when initiating your context.
Using the TableProvider API (Format-based Access)
In addition to the catalog-based approach, the ClickHouse Spark connector supports a format-based access pattern via the TableProvider API.Format-based Read Example
- Python
- Scala
- Java
Format-based Write Example
- Python
- Scala
- Java
TableProvider Features
The TableProvider API provides several powerful features:Automatic Table Creation
When writing to a non-existent table, the connector automatically creates the table with an appropriate schema. The connector provides intelligent defaults:- Engine: Defaults to
MergeTree()if not specified. You can specify a different engine using theengineoption (e.g.,ReplacingMergeTree(),SummingMergeTree(), etc.) - ORDER BY: Required - You must explicitly specify the
order_byoption when creating a new table. The connector validates that all specified columns exist in the schema. - Nullable Key Support: Automatically adds
settings.allow_nullable_key=1if ORDER BY contains nullable columns
- Python
- Scala
- Java
TableProvider Connection Options
When using the format-based API, the following connection options are available:Connection Options
Table Creation Options
These options are used when the table doesn’t exist and needs to be created:
* The
order_by option is required when creating a new table. All specified columns must exist in the schema.** Automatically set to
1 if ORDER BY contains nullable columns and not explicitly provided.
Writing Modes
The Spark connector (both TableProvider API and Catalog API) supports the following Spark write modes:append: Add data to existing tableoverwrite: Replace all data in the table (truncates table)
- Python
- Scala
- Java
Configuring ClickHouse Options
Both the Catalog API and TableProvider API support configuring ClickHouse-specific options (not connector options). These are passed through to ClickHouse when creating tables or executing queries. ClickHouse options allow you to configure ClickHouse-specific settings likeallow_nullable_key, index_granularity, and other table-level or query-level settings. These are different from connector options (like host, database, table) which control how the connector connects to ClickHouse.
Using TableProvider API
With the TableProvider API, use thesettings.<key> option format:
- Python
- Scala
- Java
Using Catalog API
With the Catalog API, use thespark.sql.catalog.<catalog_name>.option.<key> format in your Spark configuration:
ClickHouse Cloud settings
When connecting to ClickHouse Cloud, make sure to enable SSL and set the appropriate SSL mode. For example:Read data
- Java
- Scala
- Python
- Spark SQL
Write data
- Java
- Scala
- Python
- Spark SQL
DDL operations
You can perform DDL operations on your ClickHouse instance using Spark SQL, with all changes immediately persisted in ClickHouse. Spark SQL allows you to write queries exactly as you would in ClickHouse, so you can directly execute commands such as CREATE TABLE, TRUNCATE, and more - without modification, for instance:When using Spark SQL, only one statement can be executed at a time.
Working with VariantType
VariantType support is available in Spark 4.0+ and requires ClickHouse 25.3+ with experimental JSON/Variant types enabled.
VariantType for working with semi-structured data. VariantType maps to ClickHouse’s JSON and Variant types, allowing you to store and query flexible schema data efficiently.
This section focuses specifically on VariantType mapping and usage. For a complete overview of all supported data types, see the Supported data types section.
ClickHouse Type Mapping
Reading VariantType Data
When reading from ClickHouse,JSON and Variant columns are automatically mapped to Spark’s VariantType:
- Scala
- Python
- Java
Writing VariantType Data
You can write VariantType data to ClickHouse using either JSON or Variant column types:- Scala
- Python
- Java
Creating VariantType Tables with Spark SQL
You can create VariantType tables using Spark SQL DDL:Configuring Variant Types
When creating tables with VariantType columns, you can specify which ClickHouse types to use:JSON Type (Default)
If novariant_types property is specified, the column defaults to ClickHouse’s JSON type, which only accepts JSON objects:
Variant Type with Multiple Types
To support primitives, arrays, and JSON objects, specify the types in thevariant_types property:
Supported Variant Types
The following ClickHouse types can be used inVariant():
- Primitives:
String,Int8,Int16,Int32,Int64,UInt8,UInt16,UInt32,UInt64,Float32,Float64,Bool - Arrays:
Array(T)where T is any supported type, including nested arrays - JSON:
JSONfor storing JSON objects
Read Format Configuration
By default, JSON and Variant columns are read asVariantType. You can override this behavior to read them as strings:
- Scala
- Python
- Java
Write Format Support
VariantType write support varies by format:
Configure the write format:
Best Practices
- Use JSON type for JSON-only data: If you only store JSON objects, use the default JSON type (no
variant_typesproperty) - Specify types explicitly: When using
Variant(), explicitly list all types you plan to store - Enable experimental features: Ensure ClickHouse has
allow_experimental_json_type = 1enabled - Use JSON format for writes: JSON format is recommended for VariantType data for better compatibility
- Consider query patterns: JSON/Variant types support ClickHouse’s JSON path queries for efficient filtering
- Column hints for performance: When using JSON fields in ClickHouse, adding column hints improves query performance. Currently, adding column hints via Spark isn’t supported. See GitHub issue #497 for tracking this feature.
Example: Complete Workflow
- Scala
- Python
- Java
Configurations
The following are the adjustable configurations available in the connector.Using Configurations: These are Spark-level configuration options that apply to both Catalog API and TableProvider API. They can be set in two ways:
-
Global Spark configuration (applies to all operations):
-
Per-operation override (TableProvider API only - can override global settings):
spark-defaults.conf or when creating the Spark session.