- Raw S3 Parquet (S3 Data Lake,
catalogType=s3) — inferred from the Parquet file’s physical and logical types. - Iceberg (AWS Glue / S3 Tables,
catalogType=iceberg-rest) — inferred from the Iceberg table schema.
Numeric columns (
INT, LONG, FLOAT, DOUBLE, BIG_DECIMAL) are inferred as metrics; everything else (BOOLEAN, STRING, JSON, BYTES, time columns) as dimensions. You can adjust this in the schema before creating the table.Raw S3 Parquet → Pinot
For the S3 Data Lake source. Types come from the Parquet file metadata.Primitive Types
Logical Types
Integer Subtypes
String and Binary Types
Temporal Types
Decimal Types
All ParquetDECIMAL variants map to Pinot BIG_DECIMAL, preserving scale and precision.
Complex Types
To use
JSON_MATCH or JSON_EXTRACT_SCALAR on complex columns, you must enable a JSON index on those columns. Without it, queries will fail with a Cannot apply JSON_MATCH on column without json index error. Configure the index in the table’s index settings.Iceberg → Pinot
For the AWS Glue and AWS S3 Tables sources. Types come from the Iceberg table schema.Timestamp granularity is inferred from the Iceberg type (current releases):
timestamp_ns/timestamptz_ns→EPOCH|NANOSECONDStimestamp(p)with an explicit precision → milliseconds forp ≤ 3, microseconds forp ≤ 6, nanoseconds above that- plain
timestamp/timestamptz→EPOCH|MICROSECONDS, matching Iceberg’s on-disk microsecond storage
timestamp as EPOCH|MILLISECONDS, which mislabeled microsecond data (values ~1000× off). Tables onboarded on those builds keep their inferred format — set the time column’s granularity explicitly if it doesn’t match the data. See Time column.Time column
A Pinot table can designate one column as its primary time column — aDateTimeFieldSpec that records the event time of each row. See the Apache Pinot DateTimeFieldSpec reference for the general schema requirement and format syntax.
How the time column is used in an External Table
- Segment pruning — a query with a time filter skips segments whose time range can’t match, so fewer remote files are read.
- Retention — if a retention period is configured on the table, segments older than it are dropped.
How the time column is detected
During onboarding, after the schema is inferred, StarTree selects a time column automatically — choosing, in order:- The first non-nullable millisecond-granularity datetime column.
- Otherwise, the first millisecond-granularity datetime column (nullable allowed).
- Otherwise, the first datetime column of any unit.
DateTimeFieldSpec are candidates — TIMESTAMP, DATE, and (raw Parquet) INT96. A plain integer column holding an epoch value is not auto-detected; set it as the time column manually if needed. If the source has no timestamp/date column, no time column is set; you can assign one in the schema before creating the table.
Granularity
For raw Parquet, the inferredDateTimeFieldSpec preserves the source unit:
For Iceberg, the granularity follows the type:
timestamp_ns → nanoseconds, timestamp(p) → from the precision, and plain timestamp / timestamptz → microseconds (older 0.16.0 builds inferred milliseconds — see the note in the Iceberg → Pinot section above).
Values are stored in the source unit — there is no implicit downscaling — so account for the unit in time-range queries. If the inferred granularity doesn’t match what the underlying Parquet actually stores (for example, a table onboarded on an older build), set the time column’s granularity explicitly.
Known Limitations
Unsigned Integer Types
ParquetUINT32 and UINT64 (unsigned 32-bit and 64-bit integers) are stored in Pinot as a signed LONG. This means:
- Values that fit within the signed range are accurate.
- Values above
2,147,483,647(for UINT32) are stored as negative numbers or wrap around, silently corrupting approximately half the data.
INT32_MAX, treat the Pinot LONG values with caution or apply a transformation at ingestion time.
Null Handling in Complex Types
MAP columns that contain null values in keys or values may not propagate null bitmaps correctly to Pinot segments. This can result in nulls being replaced by type defaults (e.g., 0 for integers, empty string for strings). Verify null behavior after ingestion.
Current onboarding flows set nullHandlingEnabled: true on the generated table config automatically, and when the source schema has nullable fields, the inferred Pinot schema marks them nullable and enables column-based null handling (enableColumnBasedNullHandling). Tables created on older builds may have null handling off — see Advanced Guidance.
INT96 (Deprecated)
INT96 has no column statistics in Parquet, which affects min/max pruning during segment generation. It should not be used as a timeColumnName.
