Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 42 additions & 38 deletions docs/src/format/index/scalar/zonemap.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@

Zone maps are a columnar database technique for predicate pushdown and scan pruning.
They break data into fixed-size chunks called "zones" and maintain summary statistics
(min, max, null count) for each zone, enabling efficient filtering by eliminating
zones that cannot contain matching values.
(minimum, maximum, and null count) for each zone. Ordered zone maps use minimum
and maximum values to eliminate zones that cannot match. Null-only zone maps
store only top-level null information for nested values without scalar ordering.

Zone maps are "inexact" filters - they can definitively exclude zones but may include
false positives that require rechecking.

In addition, since finding NULLs is a common query pattern, the index also maintains a
bitmap of null rows which allows it to return exact results for IS NULL queries.
Current writers also maintain a bitmap of null rows for exact `IS NULL` and
`IS NOT NULL` queries.

## Index Details

Expand All @@ -19,43 +17,49 @@ bitmap of null rows which allows it to return exact results for IS NULL queries.

## Storage Layout

The zone map index stores zone statistics in a single file:

1. `zonemap.lance` - Zone statistics for query pruning
`zonemap.lance` is the index entry point. Each record describes one zone.
Ordered indices use the indexed logical type for extrema. Null-only indices
use Arrow `Null` extrema columns and store the indexed logical type separately.

```python
extrema_type = value_type if supports_min_max else pa.null()

pa.schema([
pa.field("min", extrema_type, nullable=True),
pa.field("max", extrema_type, nullable=True),
pa.field("null_count", pa.uint32(), nullable=False),
pa.field("nan_count", pa.uint32(), nullable=False),
pa.field("fragment_id", pa.uint64(), nullable=False),
pa.field("zone_start", pa.uint64(), nullable=False),
pa.field("zone_length", pa.uint64(), nullable=False),
])
```

### Zone Statistics File Schema
The schema metadata contains:

| Column | Type | Nullable | Description |
|---------------|------------|----------|-----------------------------------------|
| `min` | {DataType} | true | Minimum value in the zone |
| `max` | {DataType} | true | Maximum value in the zone |
| `null_count` | UInt32 | false | Number of null values in the zone |
| `nan_count` | UInt32 | false | Number of NaN values (for float types) |
| `fragment_id` | UInt64 | false | Fragment containing this zone |
| `zone_start` | UInt64 | false | Starting row offset within the fragment |
| `zone_length` | UInt32 | false | Number of rows in this zone |
- `rows_per_zone`: decimal string containing the configured maximum zone size.
- `null_bitmap`: global-buffer index of the serialized `RowAddrTreeMap`.
- `data_type`: global-buffer index of the logical type for null-only indices.

### Schema Metadata
The `data_type` global buffer is an Arrow IPC schema:

| Key | Type | Description |
|---------------------|--------|-------------------------------------------|
| `rows_per_zone` | String | Number of rows per zone (default: "8192") |
| `null_bitmap` | UInt32 | Index of null bitmap global buffer |
```python
pa.schema([
pa.field("value", value_type, nullable=True),
])
```

### Global Buffers
## Query Semantics

| Metadata Key | Description |
|---------------------|------------------------------------------------------------|
| `null_bitmap` | A serialized RowAddrTreeMap specifying which rows are null |
Ordered zone maps provide inexact pruning for `Equals`, `Range`, and `IsIn`.
Null-only zone maps do not advertise these predicates because they have no
value bounds. Both modes use the null bitmap for exact null predicates.

## Accelerated Queries
`ZoneMapIndexDetails.supports_min_max` records the mode. An absent value means
ordered mode for compatibility with existing version-0 indices.

The zone map index provides inexact results for the following query types (nullability queries
return exact results):
## Index Versions

| Query Type | Description | Operation | Result Type |
|------------|---------------------------|---------------------------------------------|-------------|
| **Equals** | `column = value` | Includes zones where min ≤ value ≤ max | AtMost |
| **Range** | `column BETWEEN a AND b` | Includes zones where ranges overlap | AtMost |
| **IsIn** | `column IN (v1, v2, ...)` | Includes zones that could contain any value | AtMost |
| **IsNull** | `column IS NULL` | Includes zones where null_count > 0 | Exact |
- Version 0 stores ordered zone maps.
- Version 1 stores null-only zone maps. Version-0 readers reject this version
and fall back to scanning instead of interpreting absent value bounds.
4 changes: 4 additions & 0 deletions protos/index_old.proto
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ message ZoneMapIndexDetails {
// true means IS NULL is exact and IS NOT NULL can be answered without a
// full scan.
optional bool has_null_bitmap = 3;
// Whether the index stores ordered min/max bounds. Absent means true for
// version-0 indexes written before this field was added. False identifies
// the version-1 null-only layout.
optional bool supports_min_max = 4;
}
message InvertedIndexDetails {
enum DocumentGranularity {
Expand Down
Loading
Loading