Skip to content

Commit c9550ae

Browse files
committed
Add note with links to Java client options and server settings docs
Add a note block linking to ClientConfigProperties.java and the documentation pages for Java client configuration and ClickHouse server session settings.
1 parent 80be01a commit c9550ae

1 file changed

Lines changed: 18 additions & 66 deletions

File tree

docs/integrations/data-ingestion/apache-spark/spark-native-connector.md

Lines changed: 18 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1600,7 +1600,7 @@ The connector implements the Spark DataSource V2 push-down interfaces, meaning t
16001600
| **Column pruning** | `SupportsPushDownRequiredColumns` | Only the columns selected by the query are fetched from ClickHouse. `SELECT col1, col2` avoids transferring all columns. |
16011601
| **Filter predicates** | `SupportsPushDownFilters` | `WHERE` conditions using standard comparison operators, `IN`, `IS NULL`, `LIKE`, etc. Unsupported expressions fall back to Spark-side evaluation. |
16021602
| **Limit** | `SupportsPushDownLimit` | `LIMIT N` is sent to ClickHouse, preventing full table scans for small result sets. |
1603-
| **Aggregations** | `SupportsPushDownAggregates` | `GROUP BY` + aggregate functions (`SUM`, `COUNT`, `MIN`, `MAX`, `AVG`) are executed in ClickHouse. A probe query (`WHERE 1=0`) is first sent to determine the output schema. |
1603+
| **Aggregations** | `SupportsPushDownAggregates` | `GROUP BY` + aggregate functions (`SUM`, `COUNT`, `MIN`, `MAX`, `AVG`) are executed in ClickHouse. |
16041604
| **Runtime filters** | `SupportsRuntimeFiltering` | Dynamic filters produced during query execution (e.g. from broadcast joins) are applied at scan time. Must be enabled explicitly. |
16051605

16061606
To enable runtime filtering:
@@ -1771,14 +1771,11 @@ To apply ClickHouse server settings only to read requests (not writes), use `spa
17711771

17721772
| Tuning | Configuration | Notes |
17731773
|---|---|---|
1774-
| **Increase batch size** | `spark.clickhouse.write.batchSize=50000` | Default is 10,000. Larger batches reduce round-trips. Reduce if you see "Broken Pipe" errors. |
1774+
| **Increase batch size** | `spark.clickhouse.write.batchSize=50000` | Default is 10,000. Larger batches reduce round-trips. |
17751775
| **Arrow write format** | `spark.clickhouse.write.format=arrow` (default) | Arrow is faster than JSON for most data types. Use `json` only for Variant/JSON column types. |
17761776
| **Compression** | `spark.clickhouse.write.compression.codec=lz4` (default) | Reduces network transfer during writes. |
1777-
| **Async inserts** | `option.clickhouse_setting_async_insert=1` | Shifts buffering to ClickHouse, reducing memory pressure on the server for high-frequency writes. |
1778-
| **Pre-sort data** | `spark.clickhouse.write.localSortByKey=true` (default) | Local sort before writing reduces MergeTree merge pressure. |
17791777
| **Repartition by partition** | `spark.clickhouse.write.repartitionByPartition=true` (default) | Groups rows by partition before writing, reducing the number of parts created. |
17801778
| **Explicit partition count** | `spark.clickhouse.write.repartitionNum=N` | Forces Spark to repartition to exactly N partitions before writing (via `requiredNumPartitions()`). Default `0` means no requirement. Alternatively, use `df.repartition(N)` before the write call. |
1781-
| **Strict distribution** | `spark.clickhouse.write.repartitionStrictly=true` | Controls whether Spark can skip the connector's required write distribution (e.g. by coalescing partitions). When `false`, Spark may apply optimizations that bypass the connector's partitioning contract; when `true`, Spark always enforces it. This is distinct from `df.repartition()`, which reshuffles data before the write pipeline begins. Defaults to `false` on Spark 3.4+; on earlier versions it always behaves as `true` regardless of this setting. |
17821779

17831780
### Recommended starting configuration for bulk loads {#bulk-load-config}
17841781

@@ -1787,59 +1784,10 @@ spark.conf.set("spark.clickhouse.write.batchSize", "50000")
17871784
spark.conf.set("spark.clickhouse.write.format", "arrow")
17881785
spark.conf.set("spark.clickhouse.write.compression.codec", "lz4")
17891786
spark.conf.set("spark.clickhouse.write.repartitionByPartition", "true")
1790-
spark.conf.set("spark.clickhouse.write.localSortByKey", "true")
17911787
```
17921788

17931789
## Troubleshooting {#troubleshooting}
17941790

1795-
### Broken pipe or connection reset during write {#troubleshooting-broken-pipe}
1796-
1797-
**Symptom**: `CHServerException: [HTTP] Broken pipe (Write failed)` or `Connection reset by peer` during INSERT.
1798-
1799-
**Cause**: ClickHouse closed the connection mid-stream, typically due to memory pressure on the ClickHouse server when the batch is too large.
1800-
1801-
**Fix**:
1802-
1. Reduce `spark.clickhouse.write.batchSize`. Start with 1,000–5,000 and increase gradually.
1803-
2. Enable async inserts to shift buffering to ClickHouse:
1804-
```python
1805-
spark.conf.set("spark.sql.catalog.clickhouse.option.clickhouse_setting_async_insert", "1")
1806-
spark.conf.set("spark.sql.catalog.clickhouse.option.clickhouse_setting_wait_for_async_insert", "1")
1807-
```
1808-
3. Increase `max_memory_usage` on the ClickHouse server, or raise it for the session via:
1809-
```python
1810-
spark.conf.set("spark.sql.catalog.clickhouse.option.clickhouse_setting_max_memory_usage", "10000000000")
1811-
```
1812-
1813-
---
1814-
1815-
### Too many schema inference `WHERE 1=0` queries {#troubleshooting-schema-inference}
1816-
1817-
**Symptom**: A `SELECT ... WHERE 1=0` query appears in ClickHouse query logs whenever a query with aggregation push-down is executed from Spark.
1818-
1819-
**Cause**: When aggregation push-down is triggered, the connector sends a probe query to ClickHouse to determine the output schema of the pushed-down aggregation. This is by design and only occurs when aggregation push-down is active.
1820-
1821-
**Fix**: There is no connector-level option to suppress the probe query. The `WHERE 1=0` probe is a near-zero-cost round-trip that does not scan data. If it is unacceptable, use one of the following options:
1822-
1823-
**Option 1 — Disable aggregate push-down at the session level** (Spark 3.3+):
1824-
1825-
```python
1826-
spark.conf.set("spark.sql.sources.v2.pushAggregation.enabled", "false")
1827-
```
1828-
1829-
This prevents Spark's optimizer from calling `pushAggregation()` entirely. The aggregation runs in Spark instead of being pushed to ClickHouse.
1830-
1831-
**Option 2 — Read raw data and aggregate in Spark**:
1832-
1833-
```python
1834-
# Read raw data — no aggregation push-down, no probe query
1835-
df = spark.sql("SELECT * FROM clickhouse.default.my_table")
1836-
result = df.groupBy("id").agg({"value": "sum"})
1837-
```
1838-
1839-
Note: supplying `.schema(...)` on the `DataFrameReader` only skips the `inferSchema()` round-trip; it does not suppress the `WHERE 1=0` probe, which is part of query optimization and not schema inference.
1840-
1841-
---
1842-
18431791
### Cannot connect to shard hostname {#troubleshooting-shard-hostname}
18441792

18451793
**Symptom**: Reads or writes fail with connection errors referencing shard hostnames that are not the coordinator node.
@@ -1856,18 +1804,6 @@ Note: supplying `.schema(...)` on the `DataFrameReader` only skips the `inferSch
18561804

18571805
---
18581806

1859-
### Too many Spark tasks when reading a partitioned Distributed table {#troubleshooting-too-many-tasks}
1860-
1861-
**Symptom**: Spark creates far more tasks than expected (e.g., thousands) when reading a `Distributed` table.
1862-
1863-
**Cause**: With `spark.clickhouse.read.distributed.convertLocal=true` (default), one Spark partition is created per (shard × ClickHouse partition). A 4-shard cluster with a table partitioned by day over 1 year = 4 × 365 = 1,460 Spark tasks.
1864-
1865-
**Fix**:
1866-
- Use `spark.clickhouse.read.distributed.convertLocal=false` to read through the coordinator (1 task total).
1867-
- Apply a partition filter in your query so only relevant partitions are read, reducing the partition list the connector discovers.
1868-
1869-
---
1870-
18711807
### Write fails with unsupported partition expression {#troubleshooting-partition-expression}
18721808

18731809
**Symptom**: `AnalysisException` referencing an unsupported transform (e.g. `months(key)`) when writing to a table with `PARTITION BY toYYYYMM(key)`.
@@ -1893,6 +1829,22 @@ If you also have `spark.clickhouse.write.distributed.convertLocal=true`, ignorin
18931829
spark.catalog.refreshTable("clickhouse.database.table_name")
18941830
```
18951831

1832+
---
1833+
1834+
### KEEPER_EXCEPTION during writes {#troubleshooting-keeper-exception}
1835+
1836+
**Symptom**: Writes fail with `Coordination::Exception: Can't get data for node ... node doesn't exist (KEEPER_EXCEPTION)`. Retries may produce duplicate data.
1837+
1838+
**Cause**: Too many concurrent Spark tasks overwhelm the ClickHouse replica's coordination layer (ClickHouse Keeper / ZooKeeper). This is common when the replica has limited CPU or memory relative to the write concurrency.
1839+
1840+
**Fix**:
1841+
- Reduce the number of Spark write tasks by repartitioning the DataFrame before writing:
1842+
```python
1843+
df.repartition(N).writeTo("clickhouse.db.table").append()
1844+
```
1845+
- Increase the ClickHouse replica's compute resources (CPU / memory).
1846+
- If using `ReplicatedMergeTree`, consider writing through a `Distributed` table to spread load across shards.
1847+
18961848
## Contributing and support {#contributing-and-support}
18971849

18981850
If you'd like to contribute to the project or report any issues, we welcome your input!

0 commit comments

Comments
 (0)