You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
Copy file name to clipboardExpand all lines: docs/integrations/data-ingestion/apache-spark/spark-native-connector.md
+18-66Lines changed: 18 additions & 66 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1600,7 +1600,7 @@ The connector implements the Spark DataSource V2 push-down interfaces, meaning t
1600
1600
|**Column pruning**|`SupportsPushDownRequiredColumns`| Only the columns selected by the query are fetched from ClickHouse. `SELECT col1, col2` avoids transferring all columns. |
1601
1601
|**Filter predicates**|`SupportsPushDownFilters`|`WHERE` conditions using standard comparison operators, `IN`, `IS NULL`, `LIKE`, etc. Unsupported expressions fall back to Spark-side evaluation. |
1602
1602
|**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. |
1604
1604
|**Runtime filters**|`SupportsRuntimeFiltering`| Dynamic filters produced during query execution (e.g. from broadcast joins) are applied at scan time. Must be enabled explicitly. |
1605
1605
1606
1606
To enable runtime filtering:
@@ -1771,14 +1771,11 @@ To apply ClickHouse server settings only to read requests (not writes), use `spa
1771
1771
1772
1772
| Tuning | Configuration | Notes |
1773
1773
|---|---|---|
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. |
|**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. |
1776
1776
|**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. |
1779
1777
|**Repartition by partition**|`spark.clickhouse.write.repartitionByPartition=true` (default) | Groups rows by partition before writing, reducing the number of parts created. |
1780
1778
|**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. |
1782
1779
1783
1780
### Recommended starting configuration for bulk loads {#bulk-load-config}
### 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+):
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
-
1843
1791
### Cannot connect to shard hostname {#troubleshooting-shard-hostname}
1844
1792
1845
1793
**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
1856
1804
1857
1805
---
1858
1806
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
-
1871
1807
### Write fails with unsupported partition expression {#troubleshooting-partition-expression}
1872
1808
1873
1809
**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
### 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:
0 commit comments