-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
GH-45522: [Parquet][C++] Proof-of-concept Parquet GEOMETRY and GEOGRAPHY logical type implementations #45459
base: main
Are you sure you want to change the base?
GH-45522: [Parquet][C++] Proof-of-concept Parquet GEOMETRY and GEOGRAPHY logical type implementations #45459
Conversation
Co-authored-by: Gang Wu <[email protected]>
@wgtmac This is ready for a first look! I've noted a few things about scope that could be dropped from this PR to the Description...I'm happy to do this in any order you'd like. Let me know! |
|
} | ||
}; | ||
|
||
class WKBBuffer { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please try to document classes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a great point! I'll circle back to this one this evening.
return *data_++; | ||
} | ||
|
||
::arrow::Result<uint32_t> ReadUInt32(bool swap) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there a reason all class implementations are in the header? (holdover from templating)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm happy to pull out the implementations into a .cc file although I wonder if this is slightly easier to drop in to the 3 or 4 other C++ Parquet implementations if kept together. I would also wonder if the compiler benefits from seeing the implementations (but I'm no expert here!).
} | ||
|
||
uint32_t value = ::arrow::util::SafeLoadAs<uint32_t>(data_); | ||
data_ += sizeof(uint32_t); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the data_ and size_updates seem to be sprinkled around in a lot of different places I wonder it it would pay to make a generic method like `template T UnsafeConsume() {
T t = SafeLoadAs(data_, sizeof(T))
data_ += sizeof(T);
size_ -= sizeof(T);
}
template Result Consume() {
if (sizeof(T) > size_) {
... return error
}
return UnsafeConsume();
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added versions of these! (I went with ReadXXX
but I'm not particularly attached 🙂 )
}; | ||
|
||
static ::arrow::Result<geometry_type> FromWKB(uint32_t wkb_geometry_type) { | ||
switch (wkb_geometry_type % 1000) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can 1000 be made a nemonic constant? (is there a pointer to the spec on why 1000?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's because ISO WKB defined geometry types such that / 1000
and % 1000
can be used to separate the geometry type and dimensions component. I moved the / 1000
and % 1000
next to eachother and added a comment because I wasn't sure what exactly to name the constant but I'm open to suggestions!
} | ||
}; | ||
|
||
struct GeometryType { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure what is standard in Geo Naming, but could this be called Geometry and the nested enum by called type
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or maybe not nest this in a struct and just have the static methods here as top level functions? then GeometryType could be the enum?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was designed to mimic how enums are defined in types.h
(e.g., TimeUnit::unit
), but I agree that a normal enum
is way better. I removed the functions that weren't essential and moved FromWKB into the WKB bounder where it's more clear what it's doing!
} | ||
} | ||
|
||
template <typename Coord, typename Func> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: please document non trivial functions. A better name for Func might be Consume
or CoordConsumer consumer
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I saw Visit
in an Arrow header so I changed it to that (but happy to use something else if it's more clear!)
I will circle back to documentation this evening (it's a great point that there isn't any 😬 )
|
||
void UpdateXYZ(std::array<double, 3> coord) { UpdateInternal(coord); } | ||
|
||
void UpdateXYM(std::array<double, 3> coord) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it might be worth passing array > 3 byte reference (or more generally most of them by reference). I guess without a benchmark it might be hard to tell.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved them all to be by reference here (I would be surprised if a compiler didn't inline these calls either way but I'm also not an expert!)
|
||
::arrow::Status ReadSequence(WKBBuffer* src, Dimensions::dimensions dimensions, | ||
uint32_t n_coords, bool swap) { | ||
using XY = std::array<double, 2>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
defining these within a class or struct and commenting them, then using them in other UpdateXYZ methods might make some of the code more readable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved these into BoundingBox::XY[Z[M]]
!
WKBGeometryBounder() = default; | ||
WKBGeometryBounder(const WKBGeometryBounder&) = default; | ||
|
||
::arrow::Status ReadGeometry(WKBBuffer* src, bool record_wkb_type = true) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
from an API perspective is it intended to let callers change record_wkb_type? If not consider make ReadGeometry without this parameter then move this implementation to a private helper?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved this to be internal!
Rationale for this change
The GEOMETRY and GEOGRAPHY logical types are being proposed as an addition to the Parquet format.
What changes are included in this PR?
This is a continuation of @Kontinuation 's initial PR (#43977) implementing apache/parquet-format#240 , which included:
Changes after this were:
In order to write test files, I also:
Those last two are probably a bit much for this particular PR, and I'm happy to move them.
Some things that aren't in this PR (but should be in this one or a future PR):
max > min
(and generally make sure the stats for geography are written for trivial cases)Are these changes tested?
Yes!
Are there any user-facing changes?
Yes!
Example from the included Python bindings: