1Introduction¶
Geospatial vector data — points, lines, and polygons, each accompanied by a row
of descriptive attributes — is among the most widely exchanged kinds of
tabular data. Over the past few years the columnar data ecosystem has settled
on GeoParquet as its standard for such data.
GeoParquet specifies how geometries are encoded in the columns of an Apache
Parquet file and which metadata a reader needs in order to interpret them: the
coordinate reference system, the kinds of geometry present, how the edges
between vertices are to be understood, and the spatial extent of the data.
Since version 2.11 of the Parquet format, released in 2025, Parquet itself
defines native GEOMETRY and GEOGRAPHY column types with per-row-group
spatial statistics, and GeoParquet 2.0 builds directly on them.
HEP002 proposes Marquet, a convention that brings the same capability to HDF5. Marquet is not a new table format. It is a thin geospatial layer on top of H5Col (HEP001), the column-oriented table convention for HDF5, and it reuses H5Col for everything that is not specifically geospatial: the table group and its row count, per-column chunking and filtering, missing values, list columns, search indexes, and the rules that keep a table consistent while it is being appended to. What Marquet adds is the notion of a geometry column, the ways a geometry column may be stored, the attributes that describe its geometries, two kinds of spatial search index, and a precise mapping to and from GeoParquet.
1.1Why geospatial vector data belongs in HDF5¶
A great deal of the world’s gridded geospatial data already lives in HDF5: satellite swaths and granules, numerical weather and climate model output, radar volumes, and lidar products. The vector features that accompany such data — the stations that measured it, the storm tracks and fire perimeters derived from it, the field boundaries and flight lines that organize it — are usually kept in separate files, in formats such as shapefiles, GeoPackage, or GeoParquet. Keeping both in one HDF5 file removes that seam. The features and the arrays then travel together as one unit, share one access-control and transfer story, and are read through one API, and HDF5 object and region references can tie each feature to the slab of an array that it describes without duplicating any bytes. Scientists who work in C, Fortran, Java, MATLAB, IDL, or Julia can reach the features through the same HDF5 library they already use for the arrays.
Marquet records its metadata with HDF5’s own datatypes. Closed vocabularies, such as the list of geometry types or the edge interpretations, are HDF5 enumerated datatypes. Bounding boxes are compound datatypes with named fields. Links between columns are object references. An unknown coordinate reference system is an attribute with a null dataspace. And point geometries may be stored either as WKB or as floating-point coordinates.
1.2The name Marquet¶
The name Marquet (pronounced mar-kay or mar-ket) is a deliberate nod to the columnar data ecosystem, and specifically to Apache Parquet and GeoParquet, while giving spatial data in HDF5 an identity of its own. It comes from woodworking. Parquetry is the craft of laying uniform geometric blocks in repeating grid patterns, which makes it a good metaphor for ordinary tabular data: predictable rows and columns spread across a flat surface. Marquetry, by contrast, is the craft of cutting intricate shapes, organic curves, and whole pictures from veneer and then inlaying them into a larger, solid, three-dimensional structure such as a cabinet.
That distinction mirrors the step from flat files to HDF5. Geospatial data is inherently intricate: multipolygons, long winding linestrings, and dense coordinate sequences are the digital equivalent of marquetry’s custom-cut pieces. Just as marquetry relies on a solid piece of furniture to hold its designs, this specification inlays those geometries into the hierarchical, chunked storage of an HDF5 file. The layout underneath remains columnar, preserving the speed and efficiency that made Parquet successful, so Marquet brings the columnar practice of modern data engineering into the nested hierarchy of HDF5 and gives the community a standard way to place complex spatial shapes inside scientific data containers.
1.3Relationship to GeoParquet¶
Marquet follows the semantics of GeoParquet 2.0 as published in the release candidate v2.0.0-rc.1 (July 2026), together with the optional bounding-box covering columns that were restored to the specification after that release candidate. GeoParquet 2.0.0 had not been finalized when this draft was written; a later minor revision of Marquet will follow any differences in the final release. Marquet adopts GeoParquet’s vocabulary and defaults wherever they apply: geometries are encoded as Well-Known Binary, the default coordinate reference system is OGC:CRS84, coordinates are always ordered with easting or longitude first, edges are planar unless stated otherwise, and the geometry type names are GeoParquet’s own. Mapping to and from GeoParquet lists the correspondence between GeoParquet and Marquet in both directions, including the items that have no counterpart, and also covers GeoParquet 1.0 and 1.1 files.
The GeoParquet metadata is recorded in attributes on the table group and on each geometry column (§5 to §9). Point geometries may be stored as native coordinates as well as WKB (§7.4). Because rows can be appended to an H5Col table, Marquet also specifies how its summary metadata and search indexes are kept correct as the table changes (§11).
Several extensions have been proposed for GeoParquet since 2.0.0-rc.1: levels of detail, a quantized geometry encoding, a spatial ordering key, page-level spatial statistics, and a raster column format. All of them were at an early or “alpha” stage when this draft was written, and Marquet does not adopt them.
1.4Scope and non-goals¶
HEP002 specifies:
how a Marquet table is identified and how its geometry columns are listed,
the attributes that describe a geometry column — its encoding, geometry types, coordinate reference system, coordinate epoch, edge interpretation, polygon orientation, bounding box, and covering column,
three storage forms for geometry columns: variable-length WKB, fixed-length WKB, and native point coordinates,
two kinds of spatial search index, a block bounding-box index and a packed Hilbert R-tree, together with bounding-box covering columns,
how producers keep the geometry metadata correct when a table is modified,
the mapping between Marquet and GeoParquet.
HEP002 does not specify:
a spatial query language, spatial predicates, or a query engine,
geometric validity: as in GeoParquet, a geometry is stored as given, and this specification neither requires nor checks that polygons are valid in the OGC Simple Features sense,
curved or non-linear geometries (circular strings, curve polygons, TINs, polyhedral surfaces), which neither GeoParquet nor Parquet supports,
per-row coordinate reference systems; every geometry in a column shares the column’s coordinate reference system,
raster data, which HDF5 already stores natively as multidimensional datasets,
levels of detail, display-oriented encodings, or datasets partitioned across several tables or files.
2Conformance¶
The key words MUST, MUST NOT, SHOULD, SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL in this document are to be interpreted as described in RFC 2119 and RFC 8174 when, and only when, they appear in all capitals.
A Marquet table is an H5Col table group that conforms to HEP001 and satisfies every requirement of this specification that applies to it. A producer is Marquet-conformant when every Marquet table it writes is conformant. A consumer is Marquet-conformant when it can read the geometries of every conformant Marquet table, in all three storage forms, without loss, and interpret them according to the metadata defined here. Because every Marquet table is also an H5Col table, a consumer that implements only HEP001 can still read all of its columns, geometry columns included, as ordinary H5Col data.
This specification depends on two provisions of HEP001 that were added to it alongside this proposal: search indexes over list columns (HEP001, search indexes over list columns) and the scoping of names defined by HEPs layered on H5Col to the table groups that carry their marker attribute (rule 7 of HEP001 reserved names). See Relationship to HEP001.
As in HEP001, the names of integer and floating-point datatypes in this
document, such as uint64 or float64, constrain width and signedness but not
byte order; HDF5 converts byte order on read. The bytes of a WKB value are an
exception: they are stored in HDF5 as uninterpreted uint8 or opaque data,
and each WKB value declares its own byte order internally
(§7.1).
3Terminology¶
The terms defined in HEP001 — table group, column dataset, list column,
column, row, NROWS, and search index dataset among them — keep their
meanings here. The following terms are added.
- Marquet table
- An H5Col table group that carries the
MARQUET_VERSIONattribute and conforms to this specification. - Geometry
- A value of one of the seven geometry types of the OGC Simple Features model: Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon, or GeometryCollection, in one of the coordinate dimensions XY, XYZ, XYM, or XYZM.
- Geometry column
- A column of a Marquet table that holds one geometry, or a null value, per
row. Geometry columns are listed by the table group’s
GEOMETRY_COLUMNSattribute and carry the attributes of §6. - Primary geometry column
- The geometry column that consumers use by default when a table has several,
identified by the first element of
GEOMETRY_COLUMNS. - Storage form
- The HDF5 representation of a geometry column: a variable-length WKB column (an H5Col list column), a fixed-length WKB column (a column dataset of an opaque datatype), or a point column (a column dataset of a compound datatype). See §7.
- WKB
- The ISO variant of the OGC Well-Known Binary representation of a geometry, as used by GeoParquet and by Parquet’s native geospatial types. See §7.1.
- Null geometry and empty geometry
- A null geometry is a missing value: the row has no geometry at all. An empty
geometry is a geometry that has no coordinates, such as
POINT EMPTYorPOLYGON EMPTY. The two are distinct, as they are in WKB and GeoParquet. - Coordinate reference system (CRS)
- The definition that relates coordinate values to locations on, above, or below the Earth, given in Marquet as a PROJJSON document.
- Row block
- A run of consecutive rows whose geometries are summarized by one entry of a block-based search index. See §10.2.
- Covering column
- A column dataset that holds, for each row, a bounding box of that row’s geometry, so that consumers can test rows without decoding geometries. See §10.5.
4Data model overview¶
A Marquet table is an H5Col table group with one additional attribute that
identifies it, MARQUET_VERSION, and another that lists its geometry columns,
GEOMETRY_COLUMNS. Each geometry column is an ordinary H5Col column — either a
list column group or a rank-1 column dataset — that carries a small set of
attributes describing its geometries. Every other column of the table, such
as a feature identifier, a name, or a measurement, is an ordinary H5Col column
with all of H5Col’s features. Spatial search indexes live in the table’s
SEARCH_INDEXES group alongside any H5Col search indexes, and they are linked
from the geometry columns they accelerate exactly as H5Col links indexes to
columns. Marquet introduces no new kinds of HDF5 objects below the table
group, so H5Col’s rule that a table group is a self-contained subtree holds
unchanged.
The diagram below shows a table of lakes with three geometry-related columns: a polygon column stored as variable-length WKB, which is the primary geometry column; a column of lake centroids stored as native points; and a covering column holding each polygon’s bounding box. Two spatial search indexes accelerate the polygon column.
The rest of this document specifies the table group (§5), geometry columns and their attributes (§6), the storage forms (§7), coordinate reference systems (§8), edges and orientation (§9), spatial search indexes and covering columns (§10), and the rules for modifying a Marquet table (§11).
5The Marquet table group¶
5.1Identification — the MARQUET_VERSION attribute¶
Every Marquet table group MUST be a conformant H5Col table group and MUST
carry an attribute named MARQUET_VERSION with:
datatype: null-terminated fixed-length ASCII string, sized to hold the value plus a NUL byte,
shape: scalar,
value: the revision of this specification that the table conforms to, which for this revision is
"1.0".
A consumer MUST identify a group as a Marquet table group by the presence of
both an H5Col CLASS attribute equal to COLUMN_TABLE and a
MARQUET_VERSION attribute. A producer MUST NOT write MARQUET_VERSION on a
table group that does not satisfy the rest of this specification. The
strict-write, lenient-read rule that HEP001 applies to its own string tokens
applies to MARQUET_VERSION and to every other Marquet token attribute:
producers write exactly the datatype given here, and consumers SHOULD accept
any HDF5 string datatype whose logical value matches.
MARQUET_VERSION is Marquet’s marker attribute in the sense of HEP001’s naming
rule 7 (HEP001 reserved names). The
other names and tokens that this specification defines have their Marquet
meaning only in a table group that carries it (Reserved names).
A group that carries attributes such as GEOMETRY_COLUMNS but no
MARQUET_VERSION is not a Marquet table, and a consumer MUST NOT interpret
those attributes as Marquet metadata.
MARQUET_VERSION uses the same two-component MAJOR.MINOR scheme as the
H5Col VERSION attribute. MINOR increases with backward-compatible
additions, such as a new geometry encoding that older consumers can recognize
as unsupported without misreading the table, and MAJOR increases with
changes that an existing consumer could misinterpret. Consumers MUST compare
versions numerically. A consumer that encounters a MAJOR greater than the
highest it implements MUST NOT interpret the table’s geometry columns as
geometries, although it MAY still read the table as an ordinary H5Col table.
5.2The GEOMETRY_COLUMNS attribute¶
Every Marquet table group MUST carry a one-dimensional attribute named
GEOMETRY_COLUMNS whose elements are HDF5 object references. Following the
rule HEP001 sets for its own reference attributes
(HEP001 object references),
the attribute’s datatype MUST be the standard reference datatype
H5T_STD_REF, and so MUST the datatype of every other reference attribute
that this specification defines. The attribute MUST have at least one element.
Every element MUST resolve to a column of the table — a column dataset or a
list column group that is a direct child of the table group — and MUST NOT be
a null reference, and the same column MUST NOT be referenced more than once. Every column referenced by
GEOMETRY_COLUMNS is a geometry column and MUST satisfy
§6; conversely, every column that carries
a GEOMETRY_ENCODING attribute MUST be referenced by GEOMETRY_COLUMNS.
The first element of GEOMETRY_COLUMNS designates the table’s primary
geometry column, the counterpart of GeoParquet’s primary_column. When a
table has several geometry columns — for instance a building’s footprint and
its entrance point — consumers SHOULD use the primary geometry column by
default for display, spatial filtering, and spatial joins. The order of the
remaining elements carries no meaning.
The attribute uses object references rather than column names for the same
reason HEP001’s INDEX_COLUMNS does: a reference keeps pointing at the right
column when the column is renamed, and it can never be confused by column
names that happen to contain unusual characters.
5.3Feature identifiers¶
GeoParquet recommends that producers record which column holds the feature
identifiers in metadata of their own choosing. In a Marquet table, this role
is filled by the row labels of the table, declared by the table group’s
INDEX_COLUMNS attribute
(HEP001 row index columns). Producers
SHOULD declare a table’s feature identifier column as its outermost row index
column, INDEX_COLUMNS[0]. A geometry column MUST NOT be referenced by
INDEX_COLUMNS, because a geometry describes where a feature is, not which
feature it is, and so cannot serve as a row label.
Marquet defines no further attributes on the table group. All of H5Col’s
optional table group attributes, such as TITLE, description, and
column-order, keep their meanings, and geometry columns and covering columns
appear in column-order like any other column.
6Geometry columns¶
6.1Common requirements¶
A geometry column is a column of a Marquet table that holds one geometry, or a null value, in each row. Every geometry column:
MUST be a column of the table in the sense of HEP001 — a rank-1 column dataset or a top-level list column group — and MUST be referenced by the table group’s
GEOMETRY_COLUMNSattribute;MUST carry the
GEOMETRY_ENCODINGandGEOMETRY_TYPESattributes;MUST use one of the three storage forms of §7, as determined by its
GEOMETRY_ENCODINGvalue and its HDF5 object type;MAY carry the attributes
CRS,EPOCH,EDGES,ORIENTATION,BBOX, andCOVERING, besides the attributes that HEP001 defines for the column’s HDF5 object —CLASSandKINDon a list column group,SEARCH_INDEX_LIST, and the descriptive attributedescription;MUST NOT carry the H5Col attributes
CATEGORIES,valid_min, orvalid_max, none of which has a meaning for geometries, and SHOULD NOT carryunitsorunits_vocabulary, because the units of coordinates are defined by the coordinate reference system. When a geometry column does carryunits, consumers MUST take coordinate units from the coordinate reference system instead.
All geometries in one geometry column share that column’s coordinate reference system, coordinate epoch, edge interpretation, and orientation guarantee. Different geometry columns of the same table MAY differ in any of them.
The enumerations and compound datatypes that this specification defines are stored with the attributes and datasets that use them. Producers MUST NOT store them as named (committed) datatypes below the table group, which HEP001’s rule that a table group contains only its columns and reserved subgroups would not allow.
The table below summarizes the attributes that Marquet defines for a geometry column. Each is specified in the section given in the last column.
Table 1:Geometry column attributes
| Attribute | HDF5 datatype and shape | Required | GeoParquet counterpart | Section |
|---|---|---|---|---|
GEOMETRY_ENCODING | scalar, fixed-length ASCII token | yes | encoding | §6.2 |
GEOMETRY_TYPES | 1-D, Marquet geometry-type enumeration | yes | geometry_types | §6.3 |
CRS | scalar, fixed-length UTF-8 PROJJSON text, or null dataspace | no | crs | §8.1 |
EPOCH | scalar, floating point | no | epoch | §8.3 |
EDGES | scalar, Marquet edges enumeration | no | edges; GEOGRAPHY algorithm | §9.1 |
ORIENTATION | scalar, Marquet orientation enumeration | no | orientation | §9.2 |
BBOX | scalar, compound of float64 bounds | no | bbox | §6.4 |
COVERING | scalar, H5T_STD_REF object reference | no | covering | §10.5 |
6.2The GEOMETRY_ENCODING attribute¶
Every geometry column MUST carry a scalar, null-terminated, fixed-length
ASCII attribute named GEOMETRY_ENCODING whose value names how the column’s
geometries are encoded. This revision defines two values:
WKB- Each geometry is a WKB value (§7.1). The column is
either a top-level H5Col list column group, in which case it is a
variable-length WKB column (§7.2), or a
column dataset of an
H5T_OPAQUEdatatype, in which case it is a fixed-length WKB column (§7.3). POINT- Each geometry is a point stored as native coordinates. The column is a column dataset of a compound datatype (§7.4).
The encoding names what the stored values mean, and the HDF5 object that
holds them determines the storage form, so a consumer needs no second
attribute to tell the forms apart. Any combination of GEOMETRY_ENCODING
value and HDF5 object other than the three listed above is non-conformant.
A consumer that encounters a GEOMETRY_ENCODING value it does not implement
MUST NOT silently drop the column. It SHOULD present the column as a geometry
column it cannot decode; the column remains readable as ordinary H5Col data.
Future revisions MAY register native encodings for other geometry types; the
tokens LINESTRING, POLYGON, MULTIPOINT, MULTILINESTRING, and
MULTIPOLYGON are reserved for that purpose.
6.3The GEOMETRY_TYPES attribute¶
Every geometry column MUST carry a one-dimensional attribute named
GEOMETRY_TYPES that lists the kinds of geometry the column contains. Its
datatype is the Marquet geometry-type enumeration: an HDF5 enumerated datatype
with base type H5T_STD_U16LE and the 28 members shown in
Table 2. Each member name is the
geometry type string that GeoParquet uses in its geometry_types metadata,
and each member value is the ISO WKB type code that Parquet uses in its
geospatial statistics, so a single attribute carries both vocabularies.
Table 2:Members of the Marquet geometry-type enumeration (member name and value)
| Geometry type | XY | XYZ | XYM | XYZM |
|---|---|---|---|---|
| Point | "Point" = 1 | "Point Z" = 1001 | "Point M" = 2001 | "Point ZM" = 3001 |
| LineString | "LineString" = 2 | "LineString Z" = 1002 | "LineString M" = 2002 | "LineString ZM" = 3002 |
| Polygon | "Polygon" = 3 | "Polygon Z" = 1003 | "Polygon M" = 2003 | "Polygon ZM" = 3003 |
| MultiPoint | "MultiPoint" = 4 | "MultiPoint Z" = 1004 | "MultiPoint M" = 2004 | "MultiPoint ZM" = 3004 |
| MultiLineString | "MultiLineString" = 5 | "MultiLineString Z" = 1005 | "MultiLineString M" = 2005 | "MultiLineString ZM" = 3005 |
| MultiPolygon | "MultiPolygon" = 6 | "MultiPolygon Z" = 1006 | "MultiPolygon M" = 2006 | "MultiPolygon ZM" = 3006 |
| GeometryCollection | "GeometryCollection" = 7 | "GeometryCollection Z" = 1007 | "GeometryCollection M" = 2007 | "GeometryCollection ZM" = 3007 |
Producers MUST write GEOMETRY_TYPES with exactly this enumeration, all 28
members included, so that the datatype is identical in every Marquet file and
in every geometry column. Consumers MUST interpret the attribute’s elements
by member name, not by integer value, and SHOULD accept any enumeration whose
member names are drawn from the table above, whatever its base type. In the
DDL notation emitted by h5dump, an attribute declaring a column of polygons
and multipolygons looks as follows, with most of the enumeration’s members
omitted here for brevity:
ATTRIBUTE "GEOMETRY_TYPES" {
DATATYPE H5T_ENUM {
H5T_STD_U16LE;
"GeometryCollection" 7;
…
"MultiPolygon" 6;
…
"Polygon" 3;
…
}
DATASPACE SIMPLE { ( 2 ) / ( 2 ) }
DATA {
(0): Polygon, MultiPolygon
}
}The attribute’s elements MUST be distinct. An attribute with zero elements
(a one-dimensional dataspace of extent 0) declares that the column’s geometry
types are not known. Otherwise, the attribute MUST list the type and
coordinate dimension of every non-null geometry, empty geometries included,
in rows [0, NROWS) of the column. It is not enough to list MultiPolygon
for a column that also contains polygons; both Polygon and MultiPolygon
must be listed, and three-dimensional points must be listed as Point Z
rather than Point. The types of the geometries inside a GeometryCollection
are not listed; the collection is listed as GeometryCollection.
The list MAY also name types that do not occur in the column. Producers
SHOULD keep it exact where they can, and a producer that only appends rows
normally does. A truncation, an in-place update, or an append interrupted by a
crash, however, can leave the list naming types that no longer occur, and the
list then remains correct (§11). GeoParquet’s
geometry_types must be exact; Mapping to and from GeoParquet describes how an
exporter produces it from this attribute.
For a point column (§7.4) the geometry type is
fixed by the column’s compound datatype. Its GEOMETRY_TYPES attribute MUST
either be empty or contain exactly the one member that matches the column’s
coordinate fields: Point for {x, y}, Point Z for {x, y, z}, Point M
for {x, y, m}, and Point ZM for {x, y, z, m}.
6.4The BBOX attribute¶
A geometry column MAY carry a scalar attribute named BBOX that gives a
bounding box of all its geometries; it corresponds to GeoParquet’s bbox
field (Mapping to and from GeoParquet). Its datatype is a compound datatype whose
fields are those of the GeoArrow box type:
for XY bounds:
xmin,ymin,xmax,ymax;for XYZ bounds:
xmin,ymin,zmin,xmax,ymax,zmax;for XYM bounds:
xmin,ymin,mmin,xmax,ymax,mmax;for XYZM bounds:
xmin,ymin,zmin,mmin,xmax,ymax,zmax,mmax.
Every field MUST be a 64-bit IEEE floating-point value, the fields MUST appear
in the order listed, and no other fields are allowed. Consumers MUST identify
the fields by name. The x and y bounds are always present. Producers MAY
include the z bounds, the m bounds, or both, but only when the column’s
geometries have those dimensions.
The bounds are expressed in the column’s coordinate reference system and in
Marquet’s axis order (§8.2). They MUST contain
every non-null, non-empty geometry in rows [0, NROWS), in the following
sense, which the rest of this specification also uses. A box contains a
geometry when it contains every point of the geometry: every vertex, ignoring
coordinate values that are NaN; every point along every edge, under the
column’s edge interpretation (§9.1); and, for a polygon,
every point of its interior. With planar edges, a box that contains the
vertices contains the whole geometry. With any other edge interpretation it
may not. A geodesic between two vertices bulges toward the nearer pole, beyond
the latitudes of its vertices, and a polygon whose interior includes a pole
contains that pole and every longitude around it, so its box must reach
latitude 90 (or −90) and span all longitudes. A box MAY be larger than
necessary; one that encloses the geometries loosely is still correct
(§11 explains why).
For a column whose coordinate reference system is geographic, a box MAY be
written with xmin greater than xmax, as in GeoJSON (RFC 7946, section 5),
to describe geometries that cross the antimeridian compactly. Such a box covers
the longitudes from xmin eastward through 180 and from −180 eastward to
xmax: a longitude x lies within it when x ≥ xmin or x ≤ xmax, whereas
it lies within an ordinary box when xmin ≤ x ≤ xmax. For any other
coordinate reference system, xmin MUST NOT exceed xmax. A producer SHOULD
omit BBOX when the column holds no non-null, non-empty geometry.
ATTRIBUTE "BBOX" {
DATATYPE H5T_COMPOUND {
H5T_IEEE_F64LE "xmin";
H5T_IEEE_F64LE "ymin";
H5T_IEEE_F64LE "xmax";
H5T_IEEE_F64LE "ymax";
}
DATASPACE SCALAR
DATA {
(0): {
-66.42,
43.38,
-59.68,
47.04
}
}
}The COVERING attribute, which links a geometry column to a column of
per-row bounding boxes, is specified with covering columns in
§10.5.
7Geometry encodings and storage forms¶
A geometry column stores its geometries in one of three storage forms. Two of them hold WKB, the encoding GeoParquet and Parquet use, and differ only in how the bytes of each value are laid out in HDF5. The third holds points as native floating-point coordinates. The figure below shows all three; the subsections that follow specify each one.
7.1Well-known binary¶
A WKB value in Marquet is the ISO variant of the Well-Known Binary
representation defined by the OGC Simple Features Access specification, Part 1
(version 1.2.1), and by ISO/IEC 13249-3:2016, which is also the variant used by
GeoParquet and by Parquet’s native geospatial types. Each value begins with a
byte-order flag (0x00 for big-endian, 0x01 for little-endian), followed by
a 32-bit geometry type code in that byte order and then the counts and
coordinates of the geometry. The type codes are exactly the member values of
the geometry-type enumeration (Table 2):
1 to 7 for two-dimensional geometries, with 1000, 2000, and 3000 added for the
Z, M, and ZM variants.
Every WKB value in a Marquet table MUST encode exactly one geometry of one of the seven geometry types, and so MUST every geometry nested inside a GeometryCollection. A WKB value MUST NOT use the “extended” WKB conventions of some databases, such as an embedded spatial reference identifier or Z and M flags in the high bits of the type code, and MUST NOT be followed by trailing bytes. Producers SHOULD write little-endian WKB; consumers MUST accept both byte orders, including different byte orders in different values of one column and in the nested geometries of one collection. Coordinates follow Marquet’s axis order (§8.2). An empty point is written, as WKB has no other way to express it, as a point whose coordinates are all NaN.
7.2Variable-length WKB columns¶
A variable-length WKB column can hold geometries of any type, of any size, and of mixed types and dimensions, which makes it the general-purpose storage form. It is an H5Col list column (HEP001 list columns) whose elements are the bytes of each row’s WKB value:
The column is a top-level list column group with
CLASS="LIST_COLUMN"andKIND="OFFSETS", carrying the geometry column attributes of §6 withGEOMETRY_ENCODING="WKB".Its
VALUESmember MUST be a rank-1 dataset of datatypeuint8. It MUST NOT be a nested list column or aSTRING_VALUESgroup.The
VALUESdataset MUST NOT declare a user-defined fill value. HEP001 would otherwise read any byte equal to the fill value as a missing list element, and a WKB value has no missing bytes.For every non-null row
i, the bytesVALUES[OFFSETS[i] : OFFSETS[i+1]]MUST form exactly one WKB value. An empty geometry is the WKB value of that empty geometry; an empty slice is never a valid row.A null row is expressed by HEP001’s list-column mask:
MASK[i]isFALSEand, as HEP001 requires, the row’s slice is empty. A column that contains null rows therefore MUST have aMASKmember, and a column without null rows MAY omit it.
To read the geometry of row i, a consumer reads MASK[i] if the mask exists
and returns a null geometry when it is FALSE; otherwise it reads OFFSETS[i]
and OFFSETS[i+1] and decodes the WKB value held by that slice of VALUES.
As HEP001 notes for list columns in general, this takes two dependent reads:
one of the small offsets dataset and one of the value bytes.
Each member dataset chooses its own chunking and filters. The value bytes
compress well with general-purpose compressors such as Zstandard, and a chunk
size of about 1 MiB is a reasonable starting point. The shuffle filter has no
effect on one-byte elements and need not be applied to VALUES.
7.3Fixed-length WKB columns¶
When every WKB value in a column has the same length, the offsets of a list column carry no information, and the values can instead be stored as the elements of an ordinary rank-1 column dataset. This is always the case for points of a single coordinate dimension, whose WKB values are 21 bytes long in two dimensions, 29 bytes with Z or with M, and 37 bytes with both. It can also hold for less common columns whose geometries all share one shape, such as two-vertex line segments (41 bytes in two dimensions) or rectangles stored as five-vertex polygons (93 bytes in two dimensions).
A fixed-length WKB column is a rank-1 H5Col column dataset that satisfies the following:
Its datatype MUST be an HDF5 opaque datatype (
H5T_OPAQUE) whose size equals the length of the column’s WKB values and whose tag is exactly the ASCII stringWKB. HDF5 never byte-swaps opaque data, which is what WKB needs, because each value records its own byte order.It carries the geometry column attributes with
GEOMETRY_ENCODING="WKB".Every element at a row in
[0, NROWS)that is not null MUST be exactly one WKB value occupying all of the element’s bytes. A column whose values would differ in length MUST use the variable-length form instead; padding WKB values to a common length is not allowed. In particular, a column of points whose WKB values differ in length, such as one that mixes two- and three-dimensional points, cannot use this form.As HEP001 requires of every column dataset, the column MUST declare a user-defined fill value, and a row is null exactly when the canonical missing-value test of HEP001 (HEP001 missing values) finds its element equal to that fill value. The fill value MUST NOT be a valid WKB value. Any value whose first byte is neither
0x00nor0x01qualifies, and producers SHOULD use the opaque fill value that HEP001 recommends (HEP001 opaque fill): the ASCII bytesFILLfollowed by an ascending byte ramp. Its first byte,0x46, can never begin a WKB value.
Because the column is a rank-1 column dataset, a consumer reads any row with a
single read, and the column can carry search indexes, including H5Col’s own
CHUNK_BLOOM index for exact-match lookups of WKB values. Converting point
WKB from GeoParquet into this form, or back, is a byte-for-byte copy of each
value.
The shuffle filter, applied to elements of the opaque datatype’s size, gathers each byte position of all elements together, which separates the constant WKB header bytes from the byte planes of each coordinate and usually improves compression considerably for two-dimensional points. For three-dimensional points the benefit varies with the data, and producers should measure it.
7.4Point columns¶
A point column stores each point as native floating-point coordinates rather than as WKB. The coordinates are then ordinary numbers that any HDF5 reader can use without a WKB decoder, that compress as well as any floating-point data, and that consumers can process in bulk — for example, to compute bounding boxes or to transform coordinates — without decoding each geometry. A point column is a rank-1 H5Col column dataset that satisfies the following:
Its datatype MUST be an HDF5 compound datatype whose fields are, in this order,
x,y, an optionalz, and an optionalm. The permitted field sets are{x, y},{x, y, z},{x, y, m}, and{x, y, z, m}, and no other fields are allowed.All fields MUST have the same IEEE floating-point datatype, either 32-bit or 64-bit. Producers SHOULD use 64-bit coordinates; 32-bit coordinates resolve about 2 m in longitude near ±180° and are suitable only for data whose accuracy is coarser than that.
It carries the geometry column attributes with
GEOMETRY_ENCODING="POINT".As HEP001 requires of every column dataset, the column MUST declare a user-defined fill value, and a row is null exactly when its element is bit-for-bit identical to that fill value. The fill value MUST NOT have NaN in any field, because an all-NaN point is an empty point. Producers SHOULD set every field of the fill value to
9.9692099683868690e+36, the floating-point fill value that HEP001 recommends, which is exactly representable in both 32-bit and 64-bit floating point.An empty point has NaN in every field. In a non-null, non-empty point,
xandyMUST NOT be NaN.
In h5dump DDL, a two-dimensional point column with its recommended fill
value looks as follows:
DATASET "location" {
DATATYPE H5T_COMPOUND {
H5T_IEEE_F64LE "x";
H5T_IEEE_F64LE "y";
}
DATASPACE SIMPLE { ( 3 ) / ( 3 ) }
FILLVALUE {
FILL_TIME H5D_FILL_TIME_IFSET
VALUE {
9.96921e+36,
9.96921e+36
}
}
DATA {
(0): {
-88.2434,
40.1164
},
(1): {
9.96921e+36,
9.96921e+36
},
(2): {
nan,
nan
}
}
}Row 0 is a point, row 1 is null, and row 2 is an empty point. The shuffle
filter, applied to the compound’s element size, separates the byte planes of
the coordinate fields in the same way it does for fixed-length WKB, and is
RECOMMENDED. A producer MAY reduce the precision of the coordinates before
compression, for instance by rounding away low-order mantissa bits, either
before writing or through a filter that accepts compound datatypes with
floating-point fields. A producer that does so SHOULD record the precision it
retained in the column’s description attribute.
7.5Null and empty geometries¶
The table below summarizes how each storage form expresses the three kinds of row value.
Table 3:Point, null, and empty values in the three storage forms
| Row value | Variable-length WKB | Fixed-length WKB | Point column |
|---|---|---|---|
| A geometry | its WKB bytes in VALUES | its WKB bytes as one opaque element | {x, y[, z][, m]} |
| Null geometry | MASK[i] is FALSE; the row occupies no bytes | the column’s fill value | the column’s fill value |
| Empty geometry | the WKB value of the empty geometry | the WKB value of the empty geometry | NaN in every field |
Null geometries are excluded from bounding boxes and from spatial search
indexes, so a consumer never finds them through a spatial index. Empty geometries are
likewise excluded from bounding boxes and indexes, because they have no
coordinates, but they are geometries: their types are listed in
GEOMETRY_TYPES, and they are counted separately from nulls by the block
bounding-box index (§10.3).
7.6Choosing a storage form¶
Variable-length WKB is the general form and the only one that accepts values of differing lengths, which in practice makes it the form for lines, polygons, geometry collections, and columns that mix geometry types or dimensions. A producer that converts GeoParquet data can always use it, copying each WKB value unchanged.
For points, the two rank-1 forms are smaller and faster than variable-length WKB, because they need neither an offsets dataset nor a second read per row. Between the two, fixed-length WKB keeps the bytes identical to GeoParquet’s, which makes exchange a straight copy, while a point column exposes the coordinates as named numbers, which suits analysis, bulk coordinate processing, readers without a WKB decoder, and precision reduction before compression. Producers SHOULD use one of the rank-1 forms for point data, and SHOULD prefer a point column unless byte-for-byte WKB compatibility matters more to their users.
8Coordinate reference systems¶
8.1The CRS attribute¶
A geometry column MAY carry a scalar attribute named CRS that defines the
coordinate reference system of its geometries. The attribute takes one of
three states, which correspond one to one with the three states of
GeoParquet’s crs field:
- Absent
- The coordinate reference system is OGC:CRS84: longitude and latitude, in that order, in degrees, on the WGS 84 datum. This is the default in GeoParquet and in Parquet.
- Present with a value
- The value is a PROJJSON document — a single JSON object, encoded in UTF-8, that conforms to the PROJJSON specification — describing the coordinate reference system. The attribute’s datatype MUST be a fixed-length UTF-8 string, null-terminated or null-padded, sized to hold the document. Consumers SHOULD also accept a variable-length string.
- Present with a null dataspace
- An attribute named
CRSwhose dataspace is the HDF5 null dataspace (H5S_NULL) declares that the coordinate reference system is undefined or unknown. This is GeoParquet’s"crs": null. The attribute’s datatype SHOULD be a string datatype; consumers MUST NOT rely on it.
PROJJSON is a JSON encoding of the WKT2:2019 (ISO 19162:2019) representation
of coordinate reference systems, and it can describe any coordinate reference
system that WKT2 can, including projected, compound, and dynamic ones, without
reference to an external registry. GeoParquet requires PROJJSON in its own
metadata for exactly that reason, and Marquet, which has only one place to
record the coordinate reference system, requires it too. A producer MUST NOT
write an authority code such as EPSG:4326, a WKT string, or any other form in
the CRS attribute. When the coordinate reference system has an identifier
assigned by an authority, producers SHOULD include it in the PROJJSON id
member, so that consumers without a full PROJJSON parser can still recognize
common systems.
All geometries of a column share its coordinate reference system; per-row coordinate reference systems are outside the scope of this specification.
8.2Coordinate axis order¶
Coordinates in Marquet are always ordered with easting or longitude as x
and northing or latitude as y, regardless of the axis order that the
coordinate reference system itself declares. This is the long-standing
convention of WKB and the rule of GeoParquet and Parquet, and it applies to WKB
values, point columns, the BBOX attribute, covering columns, and search
indexes alike. One consequence is that EPSG:4326, whose declared axis order is
latitude first, and OGC:CRS84 describe the same coordinates in Marquet.
8.3The EPOCH attribute¶
In a dynamic coordinate reference system, such as one tied to a continuously
updated realization of the International Terrestrial Reference Frame, the
coordinates of a point on the Earth’s surface change slowly with time, so
coordinates are unambiguous only when qualified by the epoch at which they
are valid. A geometry column whose coordinate reference system is dynamic MAY
carry a scalar floating-point attribute named EPOCH giving that epoch as a
decimal year, for example 2021.47. Producers SHOULD write it as a 64-bit
floating-point value. As in GeoParquet, the epoch applies to the whole column;
per-geometry epochs are not supported.
8.4OGC:CRS84¶
The PROJJSON document for OGC:CRS84, the default coordinate reference system, is the one GeoParquet gives:
{
"$schema": "https://proj.org/schemas/v0.5/projjson.schema.json",
"type": "GeographicCRS",
"name": "WGS 84 longitude-latitude",
"datum": {
"type": "GeodeticReferenceFrame",
"name": "World Geodetic System 1984",
"ellipsoid": {
"name": "WGS 84",
"semi_major_axis": 6378137,
"inverse_flattening": 298.257223563
}
},
"coordinate_system": {
"subtype": "ellipsoidal",
"axis": [
{
"name": "Geodetic longitude",
"abbreviation": "Lon",
"direction": "east",
"unit": "degree"
},
{
"name": "Geodetic latitude",
"abbreviation": "Lat",
"direction": "north",
"unit": "degree"
}
]
},
"id": {
"authority": "OGC",
"code": "CRS84"
}
}A consumer that works only with longitude and latitude and cannot fully parse
PROJJSON MAY treat a column as OGC:CRS84 when its CRS attribute is absent,
or when the PROJJSON id member names either OGC / CRS84 or EPSG /
4326; the second is equivalent because of the axis-order rule above.
9Edges and orientation¶
9.1The EDGES attribute¶
The coordinates of a line or polygon define its vertices; the edges between
consecutive vertices also need an interpretation. They can be straight lines in
the coordinate space, which is how most projected data is meant, or geodesics
on the sphere or the ellipsoid, which is how global longitude-latitude data is
often meant. A geometry column MAY carry a scalar attribute named EDGES that
declares the interpretation. Its datatype is the Marquet edges enumeration, an
HDF5 enumerated datatype with base type H5T_STD_U8LE and the members below;
producers MUST write it with exactly these six members, and consumers MUST
interpret it by member name.
Table 4:Members of the Marquet edges enumeration
| Member | Value | Edges between consecutive vertices follow … |
|---|---|---|
PLANAR | 0 | straight lines in the coordinate space (Cartesian interpolation) |
SPHERICAL | 1 | the shortest path on a sphere (a great-circle arc), as in BigQuery and Snowflake geographies and Google’s S2 library |
VINCENTY | 2 | the geodesic on the coordinate reference system’s ellipsoid, computed by Vincenty’s formulae |
THOMAS | 3 | the geodesic on the ellipsoid, computed by Thomas’s 1970 formulae for spheroidal geodesics |
ANDOYER | 4 | the geodesic on the ellipsoid, computed by the Andoyer–Lambert method as given by Thomas (1965) |
KARNEY | 5 | the geodesic on the ellipsoid, computed by Karney’s algorithms (2013) as implemented in GeographicLib |
When the attribute is absent, edges are PLANAR, which matches the default of
GeoParquet and the semantics of Parquet’s GEOMETRY type. Every other member
corresponds to Parquet’s GEOGRAPHY type with the edge-interpolation
algorithm of the same name. A geometry column whose EDGES is not PLANAR
MUST have a geographic coordinate reference system, with longitudes in
[−180, 180] and latitudes in [−90, 90]. The edge interpretation has no effect
on point geometries, and producers SHOULD NOT write EDGES on columns that
hold only points.
A consumer that does not recognize the member name of an EDGES attribute
MUST NOT assume planar edges; it SHOULD report the column’s edges as
unsupported.
9.2The ORIENTATION attribute¶
A polygon’s rings can be listed clockwise or counterclockwise, and for planar
edges the order rarely matters. On the sphere, however, a ring divides the
surface into two regions, and the direction in which the ring is traversed is
what tells which of them is the polygon’s interior. A geometry column MAY carry
a scalar attribute named ORIENTATION that guarantees a winding order. Its
datatype is the Marquet orientation enumeration, an HDF5 enumerated datatype
with base type H5T_STD_U8LE and a single member, COUNTERCLOCKWISE with
value 1; producers MUST write it with exactly this member.
When the attribute is present with the value COUNTERCLOCKWISE, the exterior
ring of every polygon in the column — including every polygon of every
multipolygon and geometry collection — MUST be ordered counterclockwise, with
the polygon’s interior on the left when the ring is traversed, and every
interior ring MUST be ordered clockwise. When the attribute is absent, no
assertion is made about winding order, and consumers that need a particular
order must establish it themselves. As in GeoParquet, it is RECOMMENDED that
producers write ORIENTATION whenever EDGES is not PLANAR, because without it
the meaning of a polygon on the sphere is ambiguous. A consumer that does not
recognize the member name MUST treat the attribute as if it were absent.
10Spatial search indexes and covering columns¶
Most queries against geospatial data begin with a spatial filter: the features inside a map view, along a route, or near a point. Without help, a consumer must decode every geometry in the column to answer such a query. Marquet offers three optional structures that let a consumer skip most of that work. A block bounding-box index summarizes each run of consecutive rows with one bounding box, so whole runs that lie outside the query area can be skipped. A packed Hilbert R-tree finds the individual rows whose bounding boxes meet the query area. And a covering column stores each row’s bounding box next to its geometry, so a row can be tested without decoding its geometry. None of them is required: a consumer MAY ignore all of them and still return correct answers, only more slowly, exactly as HEP001 provides for its own search indexes.
10.1Marquet search indexes within H5Col¶
This specification registers two KIND values with H5Col’s search-index
framework (HEP001 search indexes):
BLOCK_BBOX (§10.3) and PACKED_RTREE
(§10.4). Search-index datasets of both kinds are
H5Col search-index datasets in every respect. They live in the table group’s
SEARCH_INDEXES group, they carry the KIND, SOURCE_GENERATION, and
SOURCE_NROWS attributes, a consumer MUST evaluate H5Col’s validity check
(HEP001 index validity tokens) before
using one, and each is linked from the one geometry column it accelerates
through that column’s SEARCH_INDEX_LIST attribute.
HEP001 permits a kind of search index to be declared applicable to list
columns
(HEP001 search indexes over list columns),
and this specification declares both of its kinds so. They can therefore
accelerate geometry columns in all three storage forms: variable-length WKB
columns, which are list column groups, as well as fixed-length WKB columns and
point columns, which are column datasets. A search index of either kind MUST
be referenced only from the SEARCH_INDEX_LIST of a geometry column, and it
describes that column’s geometries.
HEP001’s own four kinds of search index describe the order or the exact values
of a column’s elements, which carry no spatial meaning for geometries. HEP001
already forbids all four on list columns, and forbids CHUNK_MINMAX,
SORTED_ROWS, and CHUNK_BLOOM on compound columns, which rules them out for
variable-length WKB columns and, apart from BITMAP, for point columns.
Producers SHOULD NOT build BITMAP indexes over point columns, nor
CHUNK_MINMAX, SORTED_ROWS, or BITMAP indexes over fixed-length WKB
columns. A CHUNK_BLOOM index over a fixed-length WKB column MAY be used for
exact-match lookups of WKB values.
Both of Marquet’s index kinds are built from boxes that contain geometries, in
the sense defined for the BBOX attribute (§6.4): a box
contains a geometry when it contains every vertex, every point along every edge
under the column’s edge interpretation, and every point of a polygon’s
interior. Z and M coordinates do not take part in either index, except through
the optional Z and M fields of the block bounding-box index.
10.2Row blocks¶
The block bounding-box index summarizes runs of consecutive rows called row
blocks. For a block length B, a positive integer chosen by the producer and
recorded with the index, row block j consists of rows
[j·B, min((j+1)·B, NROWS)). The table therefore has ceil(NROWS / B) row
blocks, of which only the last may be shorter than B, and none when
NROWS = 0.
Row blocks are defined in terms of rows rather than HDF5 chunks for two
reasons. HEP001 lets every column of a table choose its own chunk shape, so the
columns of a table need not share any chunk boundaries. And a geometry
column’s rows and its storage chunks do not correspond one to one in every
storage form: in a variable-length WKB column, a row’s bytes can fall anywhere
in the VALUES dataset. Because B is recorded with the index rather than
taken from a dataset’s chunk shape, the index also stays correct when the
table’s datasets are rechunked.
Producers SHOULD choose B so that the number of rows in one chunk of every
column dataset of the table, and of the OFFSETS dataset of every
variable-length WKB column, is a multiple of B. Every chunk of those datasets
then holds a whole number of row blocks, so a chunk whose row blocks a query
skips is never read. Chunks whose row counts are powers of two make this easy:
B equal to the smallest of those row counts satisfies the rule, whatever the
other counts are. For other row counts, their greatest common divisor
satisfies it, but a small divisor makes the index large. A smaller B never
lets a query skip fewer rows; it only makes the index larger.
The VALUES dataset of a variable-length WKB column cannot be aligned with row
blocks, because its chunks hold a fixed number of bytes while its rows vary in
length. For each run of consecutive row blocks that a query does not skip, a
consumer reads the VALUES chunks that the run’s bytes span, which costs at
most one partly used chunk at each end of the run. Ordering the rows spatially
(§10.6) keeps such runs few, because the
row blocks that a compact query area touches tend to lie next to each other.
10.3Block bounding-box index (KIND = BLOCK_BBOX)¶
A block bounding-box index records, for each row block, a bounding box of all
the geometries in that block, together with counts of the block’s rows,
null geometries, and empty geometries. It is Marquet’s counterpart of the
per-row-group geospatial statistics that Parquet stores for GEOMETRY and
GEOGRAPHY columns. The index has one entry per row block, and it can be
extended in place when rows are appended. It is
RECOMMENDED for every geometry column whose table has more than a few row
blocks.
The search-index dataset has rank 1, and its first-dimension extent is at
least the number of row blocks, ceil(NROWS / B). As HEP001 provides for every
search index, entries beyond the first ceil(NROWS / B), left over from
preallocation or from a larger earlier state of the table, MAY be present and
MUST be ignored. Its datatype is a
compound datatype with the following fields, in this order:
xmin,ymin— 64-bit floating point;zmin,mmin— 64-bit floating point, both optional, present only when the column’s geometries have that dimension;xmax,ymax— 64-bit floating point;zmax,mmax— 64-bit floating point, present exactly whenzminandmmin, respectively, are present;n—uint64, the number of rows in the block;null_count—uint64, the number of rows in the block whose geometry is null;empty_count—uint64, the number of rows in the block whose geometry is empty.
The box fields follow the field names and order of the BBOX attribute, and
consumers identify all fields by name. For each block, the box MUST contain
every non-null, non-empty geometry in the block, and the Z and M bounds, when
present, MUST contain all of those geometries’ Z and M values, ignoring NaN;
when all of a block’s Z values, or all of its M values, are NaN, the
corresponding minimum holds +∞ and the maximum −∞. The box MAY be larger
than necessary. When every row of
a block is null or empty (null_count + empty_count = n), the box fields MUST
hold +∞ in every minimum and −∞ in every maximum, the convention GeoArrow
uses for an empty box. Such a box intersects nothing, so a consumer that tests
it against a query area skips the block without needing a special case.
For a column whose coordinate reference system is geographic, a block whose
geometries straddle the antimeridian MAY be summarized with xmin greater than
xmax, with the meaning given for the BBOX attribute: the box covers the
longitudes from xmin eastward through 180 and from −180 eastward to xmax.
For any other coordinate reference system, xmin MUST NOT exceed xmax except
in the placeholder box of a block without geometries.
The search-index dataset carries the attributes that HEP001 requires of every
search-index dataset — KIND, with the value BLOCK_BBOX,
SOURCE_GENERATION, and SOURCE_NROWS — and one attribute of its own:
block_length- Scalar
uint64, at least 1. The block lengthBof §10.2.
To evaluate a spatial filter with this index, a consumer first checks the index’s validity tokens, then reads the index, which is small, and compares each block’s box with a box containing the query area. When the query’s predicate can hold only for geometries that intersect the query area, as is the case for predicates such as intersects, within, and contains, the blocks whose boxes do not intersect the query box contain no matching rows and are skipped; the rows of the remaining blocks are read and tested against the exact predicate. The counts let a consumer report how many rows a filter skipped and let it answer simple questions — such as how many geometries are null — from the index alone.
When rows are appended, a producer updates the index incrementally: it recomputes the entry of the block that was the last, partial block before the append, and appends entries for the new blocks, following HEP001’s tokens-before-content rule for appends.
10.4Packed Hilbert R-tree index (KIND = PACKED_RTREE)¶
A block bounding-box index can only skip whole blocks, and it helps most when the table’s rows are ordered so that nearby features sit in nearby rows. A packed R-tree instead finds the individual rows whose bounding boxes meet a query area, whatever the order of the rows, at the cost of storing one entry per row plus a small number of internal nodes. It suits very selective queries over large tables, such as a small map view over a continent-wide dataset. The layout adopted here is the static, packed R-tree used by the FlatGeobuf format, in which the tree is stored level by level in one array and the position of every node’s children can be computed rather than stored as pointers to be chased. The index is OPTIONAL; experience reported by the GeoParquet community suggests that, for tables of up to a few thousand blocks, a block bounding-box index performs about as well.
Items and levels¶
The index has one item for each row in [0, NROWS) whose geometry is
non-null and non-empty; rows with null or empty geometries have no item and
can never be returned by the index. The number of items, n₀, is recorded in
the num_items attribute. Each item’s box contains the row’s geometry
(§6.4) and never wraps around the antimeridian: for a
column with a geographic coordinate reference system, the box of a geometry
that crosses the antimeridian MUST span the full longitude range,
xmin = −180 and xmax = 180.
The items are the tree’s leaves, or level 0. With node size M, recorded in
the node_size attribute, each successive level groups the entries of the
level below into consecutive runs of M. The level sizes are therefore
n₀ = num_items
n_(k+1) = ceil(n_k / M) computed at least once, and repeated until n_(k+1) = 1and the top level, the root, has a single entry. A tree of one item therefore has two levels, a root above a single leaf, as in FlatGeobuf, and a tree of zero items has no levels and no entries.
Dataset layout¶
The search-index dataset has rank 1 and holds every entry of every level,
with the root level first and the leaf level last. If the root is level L,
level k begins at position
start_k = n_L + n_(L−1) + … + n_(k+1), with start_L = 0,and the levels hold T = n₀ + n₁ + … + n_L entries in total. The dataset’s
first-dimension extent is at least T; entries beyond the first T, left over
from an earlier, larger state of the table, MAY be present and MUST be
ignored. The datatype is a compound datatype with the
following fields, in this order:
xmin,ymin,xmax,ymax— 64-bit floating point, the entry’s box;index—uint64.
A leaf entry holds an item’s box, and its index is the item’s row position.
An internal entry, at position start_k + i of a level k ≥ 1, has as its
children the entries of level k − 1 at positions start_(k−1) + i·M through
start_(k−1) + min((i+1)·M, n_(k−1)) − 1. Its box MUST be the smallest box
containing the boxes of those children, and its index MUST equal
start_(k−1) + i·M, the position of its first child. Storing that position,
although it can be computed, lets a reader descend the tree without
recomputing the level layout and lets it check the tree’s integrity.
The leaves MAY appear in any order, and the index is correct whatever the order. Its efficiency, however, depends on leaves that are close in space being close in the array, so that the boxes of internal nodes stay small. Producers SHOULD order the leaves along a Hilbert curve, as FlatGeobuf does: by the Hilbert index of each item box’s centre, computed on a grid of 2¹⁶ × 2¹⁶ cells spanning the bounding box of all items, with ties broken by increasing row position.
Attributes¶
The search-index dataset carries the attributes that HEP001 requires of every
search-index dataset — KIND, with the value PACKED_RTREE,
SOURCE_GENERATION, and SOURCE_NROWS — and the following attributes of its
own:
node_size- Scalar
uint16, at least 2. The node sizeM. Producers SHOULD use 16 unless they have measured a better value for their data. num_items- Scalar
uint64. The number of itemsn₀, from which the sizes and positions of all levels follow.
Searching¶
To find the rows whose bounding boxes intersect a query box, a consumer
starts from the root entry, at position 0. For every entry whose box
intersects the query box, it either reports the entry’s index as a
candidate row, when the entry belongs to the leaf level, or visits the entry’s
children, when it does not. The candidate rows are then tested against the
query’s exact predicate. Because the upper levels are small and come first in
the dataset, producers SHOULD chunk the dataset so that the upper levels fall
within its first chunk or chunks; a consumer reading over a network can then
fetch them with a single request and descend to the leaves with a few more.
A packed R-tree cannot be updated incrementally. When rows are appended, truncated, or modified, a producer rebuilds the index, or leaves it to be disabled by H5Col’s validity check. As HEP001 requires of every search index, a producer rebuilds it in place, resizing and rewriting the existing dataset, rather than deleting and recreating it.
10.5Bounding-box covering columns¶
A covering column holds, for each row, a bounding box of that row’s geometry.
It is Marquet’s counterpart of GeoParquet’s covering.bbox column, and it lets
a consumer test rows against a query box, or compute simple spatial
statistics, without decoding a single geometry. It is most useful for
variable-length WKB columns of lines and polygons, whose geometries are
comparatively expensive to read and decode. For columns that hold only
points, a covering column would merely repeat the coordinates, and producers
SHOULD NOT create one.
A geometry column MAY carry a scalar attribute named COVERING whose value is
an HDF5 object reference, of datatype H5T_STD_REF, to its covering column.
The covering column:
MUST be a rank-1 column dataset of the same table, appearing in the table’s
column-orderlike any other column, and MUST NOT itself be a geometry column;MUST have a compound datatype whose fields are
xmin,ymin,xmax,ymax, in that order, or, for geometries with Z coordinates,xmin,ymin,zmin,xmax,ymax,zmax— the fields GeoParquet requires, in the order GeoArrow uses, which for six fields is also the order GeoParquet requires;MUST use one IEEE floating-point datatype, 32-bit or 64-bit, for all fields. When it uses 32-bit values, each minimum MUST be rounded down and each maximum rounded up, so that the box still contains the geometry;
MUST be referenced by the
COVERINGattribute of exactly one geometry column.
For each row whose geometry is non-null and non-empty, the covering column
holds a box that contains the geometry (§6.4), with Z
bounds that contain its Z values when the Z fields are present. For a column with a geographic coordinate reference system, a box
MAY wrap around the antimeridian with xmin greater than xmax, as GeoParquet
allows. A row whose geometry is empty holds the empty box, +∞ in each minimum
and −∞ in each maximum. A row whose geometry is null holds the covering
column’s fill value, which, as for every H5Col column dataset, MUST be declared
explicitly; producers SHOULD set every field of it to 9.9692099683868690e+36,
HEP001’s recommended floating-point fill value. Conversely, a row of the
covering column holds the fill value only when the geometry of that row is
null.
A covering column is an ordinary column. Marquet’s index kinds do not apply to it, and HEP001’s order-based kinds and Bloom filters do not apply to compound columns.
10.6Spatial ordering of rows¶
Block bounding boxes help only when the rows of each block lie close together in space; when the rows of a table are in arbitrary order, almost every block spans the whole dataset and almost none can be skipped. GeoParquet’s experience is that spatially ordering the rows before writing them is the single most effective way to make spatial filters fast, and Marquet tables behave the same way. Producers SHOULD therefore order the rows of a table spatially by its primary geometry column, for example along a Hilbert curve through the centres of the geometries’ bounding boxes, unless another order matters more to the table’s users. This specification does not record the order in which rows were sorted; a proposal to standardize a spatial ordering key was still at an early stage in GeoParquet when this draft was written, and it is left to a future revision.
11Writing and appending data¶
A Marquet table is modified exactly as any H5Col table is, following HEP001’s
rules for appending rows, preallocating storage, truncating, and updating
values in place (HEP001 writing and appending data).
Those rules keep the table’s columns and search indexes consistent, including
across a crash, by publishing appended rows only when NROWS is committed and
by disabling stale search indexes through the validity tokens. Marquet’s own
search indexes are covered by those rules without change. This section adds
what is specific to geometry columns.
11.1Keeping summary attributes correct¶
The BBOX and GEOMETRY_TYPES attributes summarize the whole column. Unlike
search indexes, they carry no validity tokens: a consumer cannot tell whether
a summary attribute is out of date, so a producer MUST NOT let it fall behind
the data. Marquet makes this practical by defining both attributes
conservatively. BBOX may enclose more than the geometries, and
GEOMETRY_TYPES may, after some kinds of change, list types that no longer
occur (§6.3). A summary that has only ever
grown remains correct, so a producer keeps it correct by widening it before
the data it must cover becomes visible to readers:
When appending rows, the producer MUST widen
BBOXto enclose the new geometries and add any new geometry types toGEOMETRY_TYPESbefore it commits the newNROWS(step 6 of HEP001’s append procedure). If the producer crashes before that commit, the attributes are merely wider than necessary, which is still correct.When updating geometries in place, the producer MUST widen both attributes to cover the new values before it writes the values (between steps 1 and 2 of HEP001’s in-place update procedure). When the column has a covering column, the producer MUST first write, for each updated row, a covering box that contains both the old and the new geometry, then write the new geometry, and only then MAY it tighten the covering box to the new geometry alone. In-place writes are visible to readers at once, and this order keeps every row’s covering box correct throughout.
When truncating the table, the producer need not change either attribute.
A producer that has rewritten or scanned a whole column MAY tighten both attributes to the exact values. Producers that only ever append rows keep the attributes exact as a matter of course, unless an append is interrupted.
These rules mean that a producer that does not implement this specification
cannot safely modify a Marquet table. An H5Col tool that knows nothing of
Marquet and appends rows would leave BBOX, GEOMETRY_TYPES, and any
covering column behind the data, and no consumer could notice. A producer that
does not implement this specification MUST NOT append rows to a Marquet table
or update its geometry or covering columns in place. It MAY truncate the table
and update its other columns, which leaves every Marquet structure correct or,
in the case of search indexes, detectably stale.
11.2Constraints of the storage forms¶
Two of the storage forms restrict the values that can be appended or written
in place. Every new value in a fixed-length WKB column has to have exactly the
column’s element size, and every new value in a point column has to have the
column’s coordinate fields. A producer that needs to store a value that does
not fit, such as a three-dimensional point in a two-dimensional point column
or a polygon in a fixed-length column of points, first replaces the column
with one in a suitable form. The same applies when a column’s coordinates are
transformed to another coordinate reference system, because the CRS
attribute and the stored coordinates have to change together.
HDF5 cannot replace one column with another atomically, and HEP001 leaves the swapping of columns to a future revision, so a replacement passes through a brief state in which the table does not satisfy requirement 3 of §12. Producers SHOULD keep that state as brief as possible by replacing a geometry column in the following order:
Write the new column in full, with its covering column if it is to have one, and with every geometry column attribute except
GEOMETRY_ENCODING. Until the next step, the new column is an ordinary H5Col column.Write the new column’s
GEOMETRY_ENCODING, and then rewriteGEOMETRY_COLUMNSso that it references the new column in place of the old one, at the same position. Between these two attribute writes, the table violates requirement 3.Build the new column’s search indexes, if any.
Delete the old column, together with its covering column and its search indexes, and update
column-order.
A consumer that finds a column carrying GEOMETRY_ENCODING that is not
referenced by GEOMETRY_COLUMNS SHOULD treat only the columns that
GEOMETRY_COLUMNS references as geometry columns.
12Consistency requirements¶
A conformant Marquet table satisfies all of the following at all times, in addition to every consistency requirement of HEP001:
The table group is a conformant H5Col table group and carries a
MARQUET_VERSIONattribute (§5.1).The table group carries a
GEOMETRY_COLUMNSattribute with at least one element, whose elements are non-nullH5T_STD_REFobject references to distinct columns of the table (§5.2).Every column referenced by
GEOMETRY_COLUMNScarriesGEOMETRY_ENCODINGandGEOMETRY_TYPES, and every column that carriesGEOMETRY_ENCODINGis referenced byGEOMETRY_COLUMNS(§6.1).No geometry column is referenced by the table group’s
INDEX_COLUMNSattribute, and no geometry column carriesCATEGORIES,valid_min, orvalid_max(§5.3, §6.1).Each geometry column’s
GEOMETRY_ENCODINGvalue and HDF5 object form one of the three storage forms:WKBwith a top-level list column group,WKBwith a column dataset of an opaque datatype taggedWKB, orPOINTwith a column dataset of a compound datatype (§6.2).Each geometry column’s
GEOMETRY_TYPESattribute has the Marquet geometry-type enumeration as its datatype and distinct elements, and it is either empty or lists the type of every non-null geometry in rows[0, NROWS). For a point column it is either empty or holds exactly the one type that matches the column’s coordinate fields (§6.3).Every WKB value of a geometry column is ISO WKB encoding exactly one geometry of the seven geometry types, without extensions or trailing bytes (§7.1).
In every variable-length WKB column, the
VALUESmember is a rank-1uint8dataset without a user-defined fill value; every non-null row’s slice holds exactly one WKB value; and every null row is markedFALSEin the column’sMASKmember (§7.2).In every fixed-length WKB column, every non-null element is exactly one WKB value occupying all of the element’s bytes, and the column’s fill value is not a valid WKB value (§7.3).
In every point column, the compound fields are
x,y, and optionallyzandm, in that order and of one floating-point datatype; the fill value has no NaN field; and every non-null row is either an empty point with NaN in every field or a point whosexandyare not NaN (§7.4).Every
CRSattribute is either a PROJJSON document or has a null dataspace (§8.1).Every
EDGESandORIENTATIONattribute has the Marquet edges or orientation enumeration as its datatype, and every geometry column whoseEDGESattribute is notPLANARhas a geographic coordinate reference system (§9.1, §9.2).In every geometry column that carries
ORIENTATION, every polygon’s rings are ordered as that attribute states (§9.2).Every
BBOXattribute has the fields and field order of §6.4, contains every non-null, non-empty geometry of its column, and hasxminno greater thanxmaxunless the column’s coordinate reference system is geographic.Every
COVERINGattribute references a covering column that satisfies §10.5, and no covering column is referenced by more than one geometry column.Every search-index dataset of kind
BLOCK_BBOXorPACKED_RTREEcarries the attributes its kind requires, is referenced only from theSEARCH_INDEX_LISTof a geometry column, and, when its validity check passes, correctly describes that column’s rows[0, NROWS)as specified in §10.3 and §10.4.No datatype defined by this specification is stored as a named datatype below the table group (§6.1).
A producer that modifies a Marquet table MUST follow §11 in addition to HEP001’s rules for writing.
13Reserved names¶
Marquet follows HEP001’s naming rules
(HEP001 reserved names): names that
carry contractual meaning are written in fixed-length uppercase ASCII with
underscores between words, and attributes private to one kind of search index
are written in lowercase snake_case. Under rule 7 of those rules, the names
and tokens in the catalog below are scoped to Marquet tables. In a table group
that carries MARQUET_VERSION, and in its columns, list column groups, and
search-index datasets, each of them has the meaning that this specification
gives it, and producers MUST NOT use it there for any other purpose, including
as the name of a column, just as HEP001’s rule 2 provides for HEP001’s own
names. In a table group without MARQUET_VERSION, the same names have no
Marquet meaning: producers may use them for their own purposes, another layered
HEP may define them differently, and a Marquet consumer MUST NOT interpret
them. None of them collides with a name that HEP001 reserves.
MARQUET_VERSION itself is the exception, because it decides which table
groups Marquet applies to. As HEP001’s rule 7 requires of every marker
attribute, no other layered HEP may define it, and producers MUST NOT write it
on a table group that is not a Marquet table
(§5.1). A Marquet table MAY also carry the
marker attribute of another layered HEP, but only as that rule allows: when the
other HEP builds on Marquet, or when the two HEPs define no name or KIND
value in common.
Three kinds of name are documented with the structures that define them but
are not reserved, even in Marquet tables. The attributes private to one kind of
search index (block_length on BLOCK_BBOX indexes, node_size and
num_items on PACKED_RTREE indexes) fall under HEP001’s rule 5, which places
such attributes outside the reserved-name contract. The member names of Marquet’s
enumerations and the field names of its compound datatypes are parts of
datatype definitions rather than names of HDF5 objects or attributes, so rule 7
does not reach them. None of these names constrains anything outside the
datasets, attributes, and datatypes in which it appears.
13.1Reserved name catalog¶
- Table group attributes
MARQUET_VERSION,GEOMETRY_COLUMNS.- Geometry column attributes
GEOMETRY_ENCODING,GEOMETRY_TYPES,CRS,EPOCH,EDGES,ORIENTATION,BBOX,COVERING.GEOMETRY_ENCODINGvaluesWKBandPOINT, defined by this revision;LINESTRING,POLYGON,MULTIPOINT,MULTILINESTRING, andMULTIPOLYGON, reserved for future native encodings.- Opaque datatype tag
WKB, the tag of the opaque datatype of a fixed-length WKB column.KINDvaluesBLOCK_BBOXandPACKED_RTREE, both declared to apply to list columns.
14Mapping to and from GeoParquet¶
The tables below give the correspondence between GeoParquet and Marquet, in
both directions, for GeoParquet 2.0 files, whose metadata is split between
the native Parquet GEOMETRY and GEOGRAPHY logical types and the optional
GeoParquet geo metadata. Non-geometry columns convert between Parquet and H5Col in the
ordinary way and are not covered here.
14.1From GeoParquet to Marquet¶
Table 5:Converting GeoParquet 2.0 to Marquet
| GeoParquet or Parquet item | Marquet counterpart |
|---|---|
| A file, or a table | A Marquet table group with MARQUET_VERSION |
Geometry columns (columns keys, or columns of logical type GEOMETRY or GEOGRAPHY) | GEOMETRY_COLUMNS |
primary_column | GEOMETRY_COLUMNS[0]; without geo metadata, the first geometry column |
WKB values in a BYTE_ARRAY column | GEOMETRY_ENCODING="WKB"; the values are copied unchanged into a variable-length WKB column, or into a fixed-length WKB column when all have one length |
A null value in an optional column | A null geometry (§7.5) |
A required column | A column without null geometries; a variable-length WKB column then needs no MASK |
geometry_types | GEOMETRY_TYPES, by member name; without geo metadata, the union of the geospatial statistics’ type codes over all row groups, by member value, or empty when a row group lacks them. A code that is not a member value of Table 2 means the column cannot be converted |
crs absent, and Parquet crs absent | CRS absent |
crs as PROJJSON | CRS with the same PROJJSON document |
crs: null, or Parquet crs of srid:0 | CRS with a null dataspace |
Parquet crs as authority:code, srid:N, or projjson:key, without geo metadata | CRS with the PROJJSON document resolved from it. A converter that cannot resolve the identifier MUST NOT guess; it either stops or, with its user’s agreement, records the coordinate reference system as unknown |
edges absent or planar; Parquet GEOMETRY | EDGES absent |
edges other than planar; Parquet GEOGRAPHY with algorithm | EDGES with the member of the same name |
Parquet GEOGRAPHY without algorithm, and no edges | EDGES = SPHERICAL, Parquet’s default for GEOGRAPHY |
orientation: "counterclockwise" | ORIENTATION = COUNTERCLOCKWISE |
bbox | BBOX, with the array positions mapped to named fields according to the array’s length |
epoch | EPOCH |
covering.bbox and its struct column | COVERING and a covering column, with the struct’s fields as compound fields in Marquet’s order, null values replaced by the covering column’s fill value, and the boxes of empty geometries replaced by the empty box |
Per-row-group GeospatialStatistics | May seed the boxes of a BLOCK_BBOX index when the row order is kept and every row group but the last has the same number of rows; the null counts can come from the column’s ordinary statistics, but the empty counts require a pass over the geometries |
Feature identifier recorded in custom metadata (for example, gdal:schema) | INDEX_COLUMNS[0] |
14.2From Marquet to GeoParquet¶
Table 6:Converting Marquet to GeoParquet 2.0
| Marquet item | GeoParquet or Parquet counterpart |
|---|---|
| A WKB geometry column, in either form | A BYTE_ARRAY column holding the WKB values unchanged, with logical type GEOMETRY, or GEOGRAPHY when EDGES is not PLANAR; encoding: "WKB" |
| A point column | The same, with each point encoded as ISO WKB, little-endian, and an empty point as a point whose coordinates are all NaN |
| A null geometry | A null value in an optional column |
GEOMETRY_COLUMNS[0] | primary_column |
GEOMETRY_TYPES | geometry_types, by member name; GeoParquet requires the list to be exact, so an exporter that cannot vouch for the attribute recomputes it from the geometries |
CRS absent | crs absent; Parquet crs absent |
CRS with a PROJJSON document | crs with the same document; Parquet crs with the same document, or with an authority:code string taken from its id member |
CRS with a null dataspace | crs: null; Parquet crs of srid:0 |
EDGES absent or PLANAR | edges absent or planar; Parquet GEOMETRY |
EDGES other than PLANAR | edges, lowercased; Parquet GEOGRAPHY with the algorithm of the same name |
ORIENTATION | orientation: "counterclockwise" |
BBOX | bbox, ordered as GeoParquet requires; GeoParquet’s bbox holds M bounds only together with Z bounds, so M bounds without Z bounds are dropped. An exporter that needs a tight box recomputes it |
EPOCH | epoch |
COVERING and its covering column | covering.bbox and a struct column with the same fields, of Parquet type FLOAT or DOUBLE, holding a null value wherever the covering column holds its fill value |
BLOCK_BBOX and PACKED_RTREE indexes | No counterpart; the Parquet writer computes row-group geospatial statistics itself |
INDEX_COLUMNS[0] | A feature identifier recorded in custom metadata, if the exporter wishes |
14.3GeoParquet 1.0 and 1.1¶
GeoParquet 1.0 and 1.1 files carry all of their geospatial metadata in the
geo metadata and store geometries as plain BYTE_ARRAY columns, so they
convert to Marquet like a GeoParquet 2.0 file whose native logical types are
absent. GeoParquet 1.1 also allowed geometries in native encodings derived from
GeoArrow, as nested lists of coordinate structs. A converter maps the point
encoding, a struct of x, y, and optionally z doubles, field for field to
a point column, and encodes the other native encodings — linestring, polygon,
multipoint, multilinestring, and multipolygon — as WKB, since this
revision of Marquet has no native encodings for them.
15Worked examples¶
The examples use the compact notation of HEP001’s worked examples, listing each HDF5 object with its datatype, shape, and attributes.
15.1One point in three storage forms¶
The table below holds the same three rows — a point, a null geometry, and an
empty point — in each of the three storage forms. A real table would use one
form; the three side by side show how each expresses the same values. The
point is POINT (-88.2434 40.1164) in longitude and latitude, and since no
column carries a CRS attribute, its coordinate reference system is
OGC:CRS84. Its 21-byte little-endian WKB value reads as follows:
01 byte order: little-endian
01 00 00 00 geometry type 1 = Point
2b f6 97 dd 93 0f 56 c0 x = -88.2434
90 a0 f8 31 e6 0e 44 40 y = 40.1164/stations (Group)
CLASS = "COLUMN_TABLE" (ASCII, fixed length)
VERSION = "1.0" (ASCII, fixed length)
NROWS = 3 (uint64, scalar)
MARQUET_VERSION = "1.0" (ASCII, fixed length)
GEOMETRY_COLUMNS = [ref(location), ref(location_wkb), ref(location_wkb_list)]
column-order = ["location", "location_wkb", "location_wkb_list"]
/stations/location (Dataset, compound {x: float64, y: float64}, shape (3,))
fill value = {9.9692099683868690e+36, 9.9692099683868690e+36}
GEOMETRY_ENCODING = "POINT" (ASCII, fixed length)
GEOMETRY_TYPES = [Point] (1-D, geometry-type enumeration)
BBOX = {xmin: -88.2434, ymin: 40.1164, xmax: -88.2434, ymax: 40.1164}
values = {-88.2434, 40.1164}, {9.9692e+36, 9.9692e+36}, {NaN, NaN}
/stations/location_wkb (Dataset, opaque, 21 bytes, tag "WKB", shape (3,))
fill value = 46 49 4c 4c 01 02 03 … 11 ("FILL" and a byte ramp)
GEOMETRY_ENCODING = "WKB"
GEOMETRY_TYPES = [Point]
BBOX = {xmin: -88.2434, ymin: 40.1164, xmax: -88.2434, ymax: 40.1164}
values = 01 01000000 2bf697dd930f56c0 90a0f831e60e4440 (the point)
46 494c4c01 0203040506070809 0a0b0c0d0e0f1011 (null: the fill value)
01 01000000 000000000000f87f 000000000000f87f (empty: POINT (NaN NaN))
/stations/location_wkb_list (Group)
CLASS = "LIST_COLUMN" (ASCII, fixed length)
KIND = "OFFSETS" (ASCII, fixed length)
GEOMETRY_ENCODING = "WKB"
GEOMETRY_TYPES = [Point]
BBOX = {xmin: -88.2434, ymin: 40.1164, xmax: -88.2434, ymax: 40.1164}
/stations/location_wkb_list/OFFSETS (Dataset, uint64, shape (4,)) values 0, 21, 21, 42
/stations/location_wkb_list/MASK (Dataset, bool enum, shape (3,)) values TRUE, FALSE, TRUE
/stations/location_wkb_list/VALUES (Dataset, uint8, shape (42,))
bytes 0–20 hold the point; row 1 is null and occupies no bytes;
bytes 21–41 hold POINT (NaN NaN)15.2A table of lakes with spatial search indexes¶
This example is the table of §4. It describes N
lakes in a projected coordinate reference system with Z coordinates. The
shorelines are polygons and multipolygons stored as variable-length WKB, with
a guaranteed winding order, a covering column, and both kinds of spatial search
index. A second geometry column holds each lake’s centroid as a native point.
The lake identifier serves as the feature identifier. No shoreline is null, so
the shoreline column has no MASK member. Fill values are shown only for the
geometry-related columns, and W is the total length of the shorelines’ WKB
values.
/lakes (Group)
CLASS = "COLUMN_TABLE"
VERSION = "1.0"
NROWS = N
GENERATION = g
MARQUET_VERSION = "1.0"
GEOMETRY_COLUMNS = [ref(shoreline), ref(centroid)]
INDEX_COLUMNS = [ref(lake_id)]
_index = "lake_id"
column-order = ["lake_id", "name", "area", "shoreline",
"shoreline_bbox", "centroid"]
/lakes/lake_id (Dataset, uint64, shape (N,))
/lakes/name (Dataset, fixed UTF-8, shape (N,))
/lakes/area (Dataset, float64, shape (N,))
units = "m2"
units_vocabulary = "UDUNITS-2"
/lakes/shoreline (Group)
CLASS = "LIST_COLUMN"
KIND = "OFFSETS"
GEOMETRY_ENCODING = "WKB"
GEOMETRY_TYPES = [Polygon Z, MultiPolygon Z]
CRS = '{"type": "ProjectedCRS", "name": "NAD83(CSRS) / UTM zone 20N", …,
"id": {"authority": "EPSG", "code": 2961}}' (fixed-length UTF-8)
ORIENTATION = COUNTERCLOCKWISE (orientation enumeration)
BBOX = {xmin: 237100.0, ymin: 4810400.0, zmin: 0.0,
xmax: 776800.0, ymax: 5235700.0, zmax: 520.0}
COVERING = ref(shoreline_bbox)
SEARCH_INDEX_LIST = [ref(SEARCH_INDEXES/shoreline__block_bbox),
ref(SEARCH_INDEXES/shoreline__rtree)]
/lakes/shoreline/OFFSETS (Dataset, uint64, shape (N+1,))
/lakes/shoreline/VALUES (Dataset, uint8, shape (W,))
/lakes/shoreline_bbox (Dataset, compound {xmin, ymin, zmin, xmax, ymax, zmax: float64},
shape (N,))
fill value = all fields 9.9692099683868690e+36
/lakes/centroid (Dataset, compound {x: float64, y: float64}, shape (N,))
fill value = {9.9692099683868690e+36, 9.9692099683868690e+36}
GEOMETRY_ENCODING = "POINT"
GEOMETRY_TYPES = [Point]
CRS = (the same PROJJSON document as the shoreline column)
/lakes/SEARCH_INDEXES (Group)
/lakes/SEARCH_INDEXES/shoreline__block_bbox
(Dataset, compound {xmin, ymin, zmin, xmax, ymax, zmax: float64,
n, null_count, empty_count: uint64}, shape (ceil(N/B),))
KIND = "BLOCK_BBOX"
block_length = B (uint64)
SOURCE_GENERATION = g
SOURCE_NROWS = N
/lakes/SEARCH_INDEXES/shoreline__rtree
(Dataset, compound {xmin, ymin, xmax, ymax: float64,
index: uint64}, shape (T,))
KIND = "PACKED_RTREE"
node_size = 16 (uint16)
num_items = N (uint64; every shoreline is non-null and non-empty)
SOURCE_GENERATION = g
SOURCE_NROWS = NWith N = 10,000 lakes and B = 4,096, the block bounding-box index has three
entries. With a node size of 16, the R-tree has levels of 10,000, 625, 40, 3,
and 1 entries, T = 10,669 entries in all, with the root at position 0, the
three entries of the next level at positions 1 to 3, and the leaves at
positions 669 to 10,668.
16Relationship to HEP001¶
Marquet is a layered HEP in the sense of HEP001’s naming rule 7, with
MARQUET_VERSION as its marker attribute: it gives H5Col table groups
additional meaning without changing what they are. A
Marquet table remains a conformant H5Col table, so every H5Col tool can read,
copy, and validate it, although only a producer that implements this
specification may append rows to it or update its geometries
(§11). Marquet relies on HEP001 for all of the
following:
the table group, its
CLASS,VERSION, andNROWSattributes, and its self-contained subtree;column datasets with independent chunking and filters, and HEP001’s fill-value rules for missing values, including the recommended floating-point and opaque fill values;
list columns, their offsets and masks, and their rule against variable-length datatypes, which variable-length WKB columns inherit;
HEP001’s boolean datatype for list-column masks, and its standard object reference datatype for
GEOMETRY_COLUMNSandCOVERING;row index columns, which serve as feature identifiers;
the search-index framework — the
SEARCH_INDEXESgroup,KIND,SEARCH_INDEX_LIST, the validity tokens, and the write ordering — which Marquet’s two index kinds join;the procedures for appending, preallocating, truncating, and updating, and the reserved-name rules.
Designing Marquet exposed two gaps in HEP001, and HEP001 was amended
alongside this proposal to close them. First, HEP001 had forbidden list column
groups to carry search indexes, which would have left variable-length WKB
columns, the general storage form, without any spatial index. HEP001 now
allows a list column to reference search indexes of kinds that are declared to
apply to list columns
(HEP001 search indexes over list columns),
and Marquet declares both of its kinds so. Second, HEP001 had no rule for
names defined by other HEPs. Nothing stopped a later revision of HEP001 from
claiming a name such as CRS or BBOX for another purpose, and nothing said
in which tables such a name has Marquet’s meaning. HEP001’s new naming rule 7
scopes the names that a layered HEP defines to the table groups that carry its
marker attribute, here MARQUET_VERSION. Other tables and other layered HEPs
remain free to use the same names, and later revisions of HEP001 will not
define them. Both HEPs are drafts. This
revision of Marquet requires the revision of HEP001 that includes both
amendments, and HEP001’s version 1.0 will include them.
Other gaps that Marquet works around without changing HEP001 are worth recording for future revisions of both:
HEP001 defines no general binary column, so WKB is stored as a list of bytes.
The leaf values of a list column must be a single rank-1 dataset. A future native encoding for lines and polygons therefore could not store each coordinate axis in its own dataset, a layout that compressed 4–11 % better than a compound datatype in the measurements behind this proposal.
HEP001 protects only search indexes with validity tokens. Marquet’s column-level summary attributes have no such protection and rely instead on the conservative maintenance rules of §11.1.
HEP001 deliberately defines no way to find all table groups in a file without traversing it, and the same holds for Marquet tables.
17Security considerations¶
The considerations of HEP001 (HEP001 security considerations) apply to Marquet tables. In particular, Marquet’s search indexes are derivative data that an adversary can falsify as easily as H5Col’s: a tampered block bounding box or R-tree can make a consumer skip rows that do satisfy a query. Consumers SHOULD offer a mode that verifies spatial indexes against the geometries or ignores them.
WKB values and PROJJSON documents read from a file are untrusted input. A WKB decoder MUST check every count it reads against the number of bytes that remain in the value, so that a value cannot make it read past its end or allocate memory far beyond the value’s size, and SHOULD limit the nesting of geometry collections. A consumer SHOULD limit the size and nesting depth of the PROJJSON documents it parses. A coordinate reference system library may be configured to download transformation grids from the network when it processes a coordinate reference system; consumers processing untrusted files SHOULD disable such network access.
Before descending a packed R-tree, a consumer MUST check that node_size is
at least 2, that num_items does not exceed NROWS, and that the total number
of entries T computed from them does not exceed the dataset’s extent. While
descending, it MUST check that every internal entry’s index equals the
position the layout prescribes and that every leaf’s index is a row position
below NROWS. An index that fails any of these checks MUST be treated as
invalid. Without
these checks, a malformed tree could make the consumer read out of bounds or
loop indefinitely.
18References¶
HEP001: H5Col, column-oriented tabular data in HDF5. HEP001
GeoParquet specification, version 2.0.0-rc.1, and the development version on the
mainbranch of the GeoParquet repository. https://geoparquet .org /releases /v2 .0 .0 -rc .1/, https:// github .com /opengeospatial /geoparquet GeoParquet specification, version 1.1.0. https://
geoparquet .org /releases /v1 .1 .0/ Apache Parquet geospatial definitions (logical types
GEOMETRYandGEOGRAPHY, and geospatial statistics). Geospatial.mdGeoArrow memory layout specification. format.md
OpenGIS Implementation Specification for Geographic information — Simple feature access — Part 1: Common architecture, version 1.2.1, OGC 06-103r4. https://
www .ogc .org /standard /sfa/ ISO/IEC 13249-3:2016, Information technology — Database languages — SQL multimedia and application packages — Part 3: Spatial.
PROJJSON specification. https://
proj .org /specifications /projjson .html OGC 18-010r7 / ISO 19162:2019, Geographic information — Well-known text representation of coordinate reference systems (WKT2:2019). https://
docs .ogc .org /is /18 -010r7 /18 -010r7 .html OGC:CRS84 definition. https://
www .opengis .net /def /crs /OGC /1 .3 /CRS84 RFC 7946, The GeoJSON Format. H. Butler et al., 2016. https://
datatracker .ietf .org /doc /html /rfc7946 FlatGeobuf, including its packed Hilbert R-tree spatial index. https://
github .com /flatgeobuf /flatgeobuf T. Vincenty, “Direct and inverse solutions of geodesics on the ellipsoid with application of nested equations,” Survey Review 23(176), 88–93, 1975.
P. D. Thomas, Mathematical Models for Navigation Systems, U.S. Naval Oceanographic Office, 1965.
P. D. Thomas, Spheroidal Geodesics, Reference Systems, and Local Geometry, U.S. Naval Oceanographic Office, 1970.
C. F. F. Karney, “Algorithms for geodesics,” Journal of Geodesy 87, 43–55, 2013. DOI: 10.1007/s00190-012-0578-z
GeographicLib. https://
geographiclib .sourceforge .io/ RFC 2119 — Key words for use in RFCs to Indicate Requirement Levels. S. Bradner, 1997. https://
datatracker .ietf .org /doc /html /rfc2119 RFC 8174 — Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words. B. Leiba, 2017. https://
datatracker .ietf .org /doc /html /rfc8174