Skip to main content

Smart Spark Optimizer: Skew Rebalancer + Key Detector + DRTree

Project description

HexaDruid ๐Ÿง โšก

PyPI version Python Version License: MIT

HexaDruid is an intelligent Spark optimizer designed to tackle data skew, ambiguous key detection, and schema bloat using smart salting, recursive shard-aware rule trees, and adaptive tuning. It enables better parallelism, safer memory layout, and intelligent insight into skewed datasets using PySparkโ€™s native DataFrame API.


๐Ÿš€ Installation

pip install hexadruid

๐Ÿ” Features

  • ๐Ÿ“Š Smart Salting using Z-score or IQR skew analysis + percentile bucketing
  • ๐ŸŒฒ Recursive DRTree for shard-based logical filtering with SQL predicates
  • ๐Ÿ”‘ Primary & Composite Key Detection (UUIDs, alphanumerics, hex โ€” optional)
  • ๐Ÿง  Schema Inference with safe type coercion, length introspection & metadata tags
  • โš™๏ธ Auto-Parameter Advisor for optimal salt count and shuffle parallelism
  • ๐Ÿ“‰ Z-Score Plots and partition size diagnostics for visibility
  • โœ… Fully PySpark-native โ€” No RDDs, no CLI dependencies, no black-box wrappers

๐Ÿง  Quickstart

from hexadruid import HexaDruid

hd = HexaDruid(df)

# Step 1: Apply smart salting to balance skew
df_salted = hd.apply_smart_salting("sales_amount")

# Step 2 (Optional): Detect candidate primary or composite keys
key_info = hd.detect_keys()

# Step 3: Run schema optimizer + DRTree analyzer
typed_df, inferred_schema, dr_tree = HexaDruid.schemaVisor(df)

๐Ÿ“š What Does It Do?

Imagine a typical DataFrame:

order_id (UUID) amount
a12e... 500.0
b98c... 5000.0
... ...

You're doing:

df.groupBy("amount").agg(...)

But most rows have the same amount, so Spark sends 99% of the work to 1 executor = skew ๐Ÿ’ฅ


โš–๏ธ Smart Salting to the Rescue

df2 = hd.apply_smart_salting("amount")

What happens?

 Step 1: Analyze column distribution via IQR or Z-score
 Step 2: Generate N percentile buckets
 Step 3: Assign salt ID per row using bucket bounds
 Step 4: Create salted_key = amount_salt
 Step 5: Repartition on salted_key for parallelism

๐Ÿ“ˆ This rebalances the shuffle phase for joins, groupBy, and aggregates.


๐Ÿง  DRTree Explained Visually

The DRTree is a decision-rule tree, not a classifier.

It recursively splits data into shards by applying SQL-style predicates. Each leaf is a filtered logical subset of the DataFrame.

                        [Root: sales_amount]
                                |
                   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
        [amount <= 500]             [amount > 500]
               |                           |
       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”            โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
 [amount <= 100] [>100, โ‰ค500]   [>500, โ‰ค1000]  [>1000]
       |         |                  |             |
   [Leaf A]   [Leaf B]          [Leaf C]       [Leaf D]
 (shard_1)   (shard_2)         (shard_3)      (shard_4)

Each leaf holds:

  • Filtered subset of the DataFrame (as a Spark SQL query)
  • Associated metadata like row count, min/max, schema drift
  • Auto key detection can run within these shards

๐Ÿ”ฌ Leaf-Level Parallelization

DRTree enables parallel insight:

  • Each leaf is autonomous (you can infer schema, key, and stats per leaf)
  • Makes the system robust to changes over time (drift detection)
  • Enables controlled analytics:
[DRTree Output]
Leaf A:
  - rows: 30K
  - key_confidence: 0.92
  - type: Float(5,2)

Leaf D:
  - rows: 300K (hotspot!)
  - key_confidence: 0.12
  - type: String(255)

๐Ÿ”‘ Key Detection (Optional & Shard-Aware)

key_info = hd.detect_keys()

You donโ€™t need to force primary keys.

This is just analysis โ€” it evaluates uniqueness confidence for each column (or combination of columns):

  • Primary Key:
score = (approx_count_distinct(col) / total_rows) - null_ratio

If score โ‰ฅ 0.99, itโ€™s a good candidate.

  • Composite Key:
combo_key = concat_ws("_", col1, col2, ...)
score = approx_count_distinct(combo_key) / total_rows - null_ratio

DRTree passes its shard filters into detect_keys() to evaluate keys per subgroup โ€” boosting accuracy.


๐Ÿง  Smart Salting Internals

๐Ÿงช Step-by-step:

  1. Detect Skew

    • If z_score range is too large or
    • IQR shows asymmetry (Q3 - Q2 โ‰ซ Q2 - Q1)
  2. Split by Percentiles

percentiles = percentile_approx("amount", [0.0, 0.1, ..., 1.0])
  1. Salt Bucketing Logic
salt = when(col >= p0 & col < p1, 0) \
     .when(col >= p1 & col < p2, 1) ...
  1. Create Salted Key
salted_key = concat_ws("_", col("amount"), col("salt"))
df = df.withColumn("salted_key", salted_key).repartition("salted_key")
  1. Auto-Tune Salt Count
  • If distribution is dense, fewer buckets suffice
  • Otherwise, more salting is applied dynamically

๐Ÿ“ˆ Visualization Example

Output from schemaVisor():

Leaf Node A [shard_0]
- size: 102,391
- type: Float(8,2)
- confidence: 92%

Leaf Node B [shard_1]
- size: 489,128 (dense zone)
- skew detected!
- Recommended salt count: 10

You can visualize the Z-score distribution:

Before:
  [โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ–              ]

After:
  [โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ–       โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ– โ–    ]

๐Ÿงช Testing

pytest tests/

Mocked SparkSession with synthetic data is used to ensure full coverage.


๐Ÿงฑ Suggested Project Structure

hexadruid/
โ”œโ”€โ”€ __init__.py
โ”œโ”€โ”€ core.py                # HexaDruid entry point
โ”œโ”€โ”€ skew_balancer.py       # Smart salting logic
โ”œโ”€โ”€ drtree.py              # DRTree shard splitting
โ”œโ”€โ”€ key_detection.py       # Unique key checker
โ”œโ”€โ”€ schema_optimizer.py    # Type inference
โ”œโ”€โ”€ advisor.py             # Parameter tuning
โ”œโ”€โ”€ utils.py               # Logging, plots, etc.
โ””โ”€โ”€ tests/                 # Test suite

๐Ÿ”ง Roadmap

  • CLI interface
  • Delta Lake + Iceberg support
  • JupyterLab extension
  • DRTree JSON export for audits
  • Cost metrics estimation
  • Column statistics and visualization dashboard

๐Ÿ“„ License

MIT License


๐Ÿค Contributing

Pull requests, ideas, and contributions welcome!

We believe Spark shouldnโ€™t be slow. Letโ€™s make it smarter together.


Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

hexadruid-0.1.6.tar.gz (25.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

hexadruid-0.1.6-py3-none-any.whl (22.4 kB view details)

Uploaded Python 3

File details

Details for the file hexadruid-0.1.6.tar.gz.

File metadata

  • Download URL: hexadruid-0.1.6.tar.gz
  • Upload date:
  • Size: 25.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.11.9

File hashes

Hashes for hexadruid-0.1.6.tar.gz
Algorithm Hash digest
SHA256 6b96a95d82eeb5f7501385d4f56fabf48a32026931849fe0ffe4b98c1584ea75
MD5 2164ee35cf0c11d4e7d6ed114e8306f3
BLAKE2b-256 9861dbb9729577cb0c4dc42012a7563d197137fbafa47754570af7c8ffb98308

See more details on using hashes here.

File details

Details for the file hexadruid-0.1.6-py3-none-any.whl.

File metadata

  • Download URL: hexadruid-0.1.6-py3-none-any.whl
  • Upload date:
  • Size: 22.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.11.9

File hashes

Hashes for hexadruid-0.1.6-py3-none-any.whl
Algorithm Hash digest
SHA256 c1786a5d7d80c30a93214e64fe7fde5743eaf92de6bf90fa55d8cfaf274185a1
MD5 d950e412c49a414e5cab6795e49efc99
BLAKE2b-256 90231eef14642ccb5661496af80a4a4cc8350537eb887dd805df4c339c6585f8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page