Skip to content

Commit 4f21474

Browse files
committed
PARQUET-2471: Add support for geometry logical type
1 parent 9d04cf3 commit 4f21474

File tree

13 files changed

+879
-1
lines changed

13 files changed

+879
-1
lines changed

parquet-column/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@
7575
<artifactId>slf4j-api</artifactId>
7676
<version>${slf4j.version}</version>
7777
</dependency>
78+
<dependency>
79+
<groupId>org.locationtech.jts</groupId>
80+
<artifactId>jts-core</artifactId>
81+
<version>${jts.version}</version>
82+
</dependency>
7883

7984
<dependency>
8085
<groupId>com.carrotsearch</groupId>
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.parquet.column.statistics;
20+
21+
import org.apache.parquet.Preconditions;
22+
import org.apache.parquet.column.statistics.geometry.BoundingBox;
23+
import org.apache.parquet.column.statistics.geometry.Covering;
24+
import org.apache.parquet.column.statistics.geometry.GeometryTypes;
25+
import org.apache.parquet.io.api.Binary;
26+
import org.locationtech.jts.geom.Geometry;
27+
import org.locationtech.jts.io.ParseException;
28+
import org.locationtech.jts.io.WKBReader;
29+
30+
public class GeometryStatistics {
31+
32+
private final BoundingBox boundingBox;
33+
private final Covering covering;
34+
private final GeometryTypes geometryTypes;
35+
private final WKBReader reader = new WKBReader();
36+
37+
public GeometryStatistics(BoundingBox boundingBox, Covering covering, GeometryTypes geometryTypes) {
38+
this.boundingBox = boundingBox;
39+
this.covering = covering;
40+
this.geometryTypes = geometryTypes;
41+
}
42+
43+
public BoundingBox getBoundingBox() {
44+
return boundingBox;
45+
}
46+
47+
public Covering getCovering() {
48+
return covering;
49+
}
50+
51+
public GeometryTypes getGeometryTypes() {
52+
return geometryTypes;
53+
}
54+
55+
public void update(Binary value) {
56+
if (value == null) {
57+
return;
58+
}
59+
try {
60+
Geometry geom = reader.read(value.getBytes());
61+
update(geom);
62+
} catch (ParseException e) {
63+
abort();
64+
}
65+
}
66+
67+
public void update(Geometry geom) {
68+
boundingBox.update(geom);
69+
covering.update(geom);
70+
geometryTypes.update(geom);
71+
}
72+
73+
public void merge(GeometryStatistics other) {
74+
Preconditions.checkArgument(other != null, "Cannot merge with null GeometryStatistics");
75+
boundingBox.merge(other.boundingBox);
76+
covering.merge(other.covering);
77+
geometryTypes.merge(other.geometryTypes);
78+
}
79+
80+
public void reset() {
81+
boundingBox.reset();
82+
covering.reset();
83+
geometryTypes.reset();
84+
}
85+
86+
public void abort() {
87+
boundingBox.abort();
88+
covering.abort();
89+
geometryTypes.abort();
90+
}
91+
92+
@Override
93+
public String toString() {
94+
return "GeometryStatistics{" +
95+
"boundingBox=" + boundingBox +
96+
", covering=" + covering +
97+
", geometryTypes=" + geometryTypes +
98+
'}';
99+
}
100+
}
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.parquet.column.statistics.geometry;
20+
21+
import org.apache.parquet.Preconditions;
22+
import org.locationtech.jts.geom.Coordinate;
23+
import org.locationtech.jts.geom.Geometry;
24+
25+
public class BoundingBox {
26+
27+
private double xMin = Double.MAX_VALUE;
28+
private double xMax = Double.MIN_VALUE;
29+
private double yMin = Double.MAX_VALUE;
30+
private double yMax = Double.MIN_VALUE;
31+
private double zMin = Double.MAX_VALUE;
32+
private double zMax = Double.MIN_VALUE;
33+
private double mMin = Double.MAX_VALUE;
34+
private double mMax = Double.MIN_VALUE;
35+
36+
public BoundingBox(double xMin, double xMax, double yMin, double yMax, double zMin, double zMax, double mMin,
37+
double mMax) {
38+
this.xMin = xMin;
39+
this.xMax = xMax;
40+
this.yMin = yMin;
41+
this.yMax = yMax;
42+
this.zMin = zMin;
43+
this.zMax = zMax;
44+
this.mMin = mMin;
45+
this.mMax = mMax;
46+
}
47+
48+
public double getXMin() {
49+
return xMin;
50+
}
51+
52+
public double getXMax() {
53+
return xMax;
54+
}
55+
56+
public double getYMin() {
57+
return yMin;
58+
}
59+
60+
public double getYMax() {
61+
return yMax;
62+
}
63+
64+
public double getZMin() {
65+
return zMin;
66+
}
67+
68+
public double getZMax() {
69+
return zMax;
70+
}
71+
72+
public double getMMin() {
73+
return mMin;
74+
}
75+
76+
public double getMMax() {
77+
return mMax;
78+
}
79+
80+
public void update(Geometry geom) {
81+
if (geom == null || geom.isEmpty()) {
82+
return;
83+
}
84+
Coordinate[] coordinates = geom.getCoordinates();
85+
for (Coordinate coordinate : coordinates) {
86+
update(coordinate.getX(), coordinate.getY(), coordinate.getZ(), coordinate.getM());
87+
}
88+
}
89+
90+
public void update(double x, double y, double z, double m) {
91+
xMin = Math.min(xMin, x);
92+
xMax = Math.max(xMax, x);
93+
yMin = Math.min(yMin, y);
94+
yMax = Math.max(yMax, y);
95+
zMin = Math.min(zMin, z);
96+
zMax = Math.max(zMax, z);
97+
mMin = Math.min(mMin, m);
98+
mMax = Math.max(mMax, m);
99+
}
100+
101+
public void merge(BoundingBox other) {
102+
Preconditions.checkArgument(other != null, "Cannot merge with null bounding box");
103+
xMin = Math.min(xMin, other.xMin);
104+
xMax = Math.max(xMax, other.xMax);
105+
yMin = Math.min(yMin, other.yMin);
106+
yMax = Math.max(yMax, other.yMax);
107+
zMin = Math.min(zMin, other.zMin);
108+
zMax = Math.max(zMax, other.zMax);
109+
mMin = Math.min(mMin, other.mMin);
110+
mMax = Math.max(mMax, other.mMax);
111+
}
112+
113+
public void reset() {
114+
xMin = Double.MAX_VALUE;
115+
xMax = Double.MIN_VALUE;
116+
yMin = Double.MAX_VALUE;
117+
yMax = Double.MIN_VALUE;
118+
zMin = Double.MAX_VALUE;
119+
zMax = Double.MIN_VALUE;
120+
mMin = Double.MAX_VALUE;
121+
mMax = Double.MIN_VALUE;
122+
}
123+
124+
public void abort() {
125+
xMin = Double.NaN;
126+
xMax = Double.NaN;
127+
yMin = Double.NaN;
128+
yMax = Double.NaN;
129+
zMin = Double.NaN;
130+
zMax = Double.NaN;
131+
mMin = Double.NaN;
132+
mMax = Double.NaN;
133+
}
134+
135+
@Override
136+
public String toString() {
137+
return "BoundingBox{" +
138+
"xMin=" + xMin +
139+
", xMax=" + xMax +
140+
", yMin=" + yMin +
141+
", yMax=" + yMax +
142+
", zMin=" + zMin +
143+
", zMax=" + zMax +
144+
", mMin=" + mMin +
145+
", mMax=" + mMax +
146+
'}';
147+
}
148+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.parquet.column.statistics.geometry;
20+
21+
import java.nio.ByteBuffer;
22+
import org.apache.parquet.Preconditions;
23+
import org.apache.parquet.schema.LogicalTypeAnnotation;
24+
import org.locationtech.jts.geom.Geometry;
25+
import org.locationtech.jts.io.ParseException;
26+
import org.locationtech.jts.io.WKBReader;
27+
import org.locationtech.jts.io.WKBWriter;
28+
29+
public class Covering {
30+
31+
protected final LogicalTypeAnnotation.Edges edges;
32+
protected ByteBuffer geometry;
33+
34+
public Covering(ByteBuffer geometry, LogicalTypeAnnotation.Edges edges) {
35+
Preconditions.checkArgument(geometry != null, "Geometry cannot be null");
36+
Preconditions.checkArgument(edges != null, "Edges cannot be null");
37+
this.geometry = geometry;
38+
this.edges = edges;
39+
}
40+
41+
public ByteBuffer getGeometry() {
42+
return geometry;
43+
}
44+
45+
public LogicalTypeAnnotation.Edges getEdges() {
46+
return edges;
47+
}
48+
49+
public void update(Geometry geom) {
50+
geometry = ByteBuffer.wrap(new WKBWriter().write(geom));
51+
}
52+
53+
public void merge(Covering other) {
54+
throw new UnsupportedOperationException("Merge is not supported for " + this.getClass().getSimpleName());
55+
}
56+
57+
public void reset() {
58+
throw new UnsupportedOperationException("Reset is not supported for " + this.getClass().getSimpleName());
59+
}
60+
61+
public void abort() {
62+
throw new UnsupportedOperationException("Abort is not supported for " + this.getClass().getSimpleName());
63+
}
64+
65+
@Override
66+
public String toString() {
67+
String geomText;
68+
try {
69+
geomText = new WKBReader().read(geometry.array()).toText();
70+
} catch (ParseException e) {
71+
geomText = "Invalid Geometry";
72+
}
73+
74+
return "Covering{" +
75+
"geometry=" + geomText +
76+
", edges=" + edges +
77+
'}';
78+
}
79+
}

0 commit comments

Comments
 (0)