ajantha-bhat commented on a change in pull request #3481:
[CARBONDATA-3548]Geospatial Support: add hash id create,query condition analyze
and generate hash id list
URL: https://github.com/apache/carbondata/pull/3481#discussion_r356550716
##########
File path: geo/src/main/java/org/apache/carbondata/geo/GeoHashImpl.java
##########
@@ -168,20 +238,151 @@ public String generate(List<?> sources) throws
Exception {
if (!(sources.get(0) instanceof Long) || !(sources.get(1) instanceof
Long)) {
throw new RuntimeException("Source columns must be of Long type.");
}
- //TODO: generate geohashId
- return String.valueOf(0);
+ Long longitude = (Long) sources.get(0);
+ Long latitude = (Long) sources.get(1);
+ // generate the hash code
+ int[] gridPoint = calculateID(longitude, latitude);
+ Long hashId = createHashID(gridPoint[0], gridPoint[1]);
+ return String.valueOf(hashId);
}
/**
* Query processor for GeoHash.
- * @param polygon
+ * example: (`LONGITUDE`, `LATITUDE`, '116270714,40112476;116217155,40028403;
+ *
116337318,39927378;116459541,39966859;116447868,40076233;116385384,40129279;')
+ * @param polygon a group of pints, close out to form an area
* @return Returns list of ranges of GeoHash IDs
* @throws Exception
*/
@Override
public List<Long[]> query(String polygon) throws Exception {
- List<Long[]> rangeList = new ArrayList<Long[]>();
- // TODO: process the polygon coordinates and generate the list of ranges
of GeoHash IDs
- return rangeList;
+ String[] pointList = polygon.split(";");
+ if (3 > pointList.length) {
+ throw new RuntimeException("polygon need at least 3 points, really has "
+ pointList.length);
+ } else {
+ List<double[]> queryList = new ArrayList<>();
+ for (String str: pointList) {
+ String[] points = str.split(",");
+ if (2 != points.length) {
+ throw new RuntimeException("longitude and latitude is a pair need 2
data");
+ } else {
+ try {
+ queryList.add(new double[] {Double.valueOf(points[0]),
Double.valueOf(points[1])});
+ } catch (NumberFormatException e) {
+ throw new RuntimeException("can not covert the string data to
double", e);
+ }
+ }
+ }
+ if (3 > queryList.size()) {
+ throw new RuntimeException("polygon list size" + queryList.size() + "
less than three");
+ } else {
+ List<Long[]> rangeList = getPolygonRangeList(queryList);
+ return rangeList;
+ }
+ }
+ }
+
+ /**
+ * use query polygon condition to get the hash id list, the list is merged
and sorted.
+ * @param queryList polygon points close out to form an area
+ * @return hash id list
+ * @throws Exception
+ */
+ private List<Long[]> getPolygonRangeList(List<double[]> queryList) throws
Exception {
+ QuadTreeCls qTreee = new QuadTreeCls(userDefineMinLongitude,
userDefineMinLatitude,
+ CalculateMaxLongitude, CalculateMaxLatitude, cutLevel);
+ qTreee.insert(queryList);
+ return qTreee.getNodesData();
+ }
+
+ /**
+ * After necessary attributes, perform necessary calculation
+ * @throws Exception
+ */
+ private void calculateData() throws Exception {
+ // Angular to radian, radians = (Math.PI / 180) * degrees
+ // Cosine value of latitude angle of origin
+ this.mCos = Math.cos(this.oriLatitude / this.conversionRatio * Math.PI /
CONVERT_FACTOR);
+ // get δx=L∗360/(2πR∗cos(lat))
+ this.deltaX = (this.gridSize * 360) / (2 * Math.PI * EARTH_RADIUS *
this.mCos);
+ this.deltaXByRatio = this.deltaX * this.conversionRatio;
+ // get δy=L∗360/2πR
+ this.deltaY = (this.gridSize * 360) / (2 * Math.PI * EARTH_RADIUS);
+ this.deltaYByRatio = this.deltaY * this.conversionRatio;
+ LOGGER.info("after spatial calculate delta X is: " + String.format("%f",
this.deltaX)
+ + "the delta Y is: " + String.format("%f", this.deltaY));
+ LOGGER.info("after spatial calculate X ByRatio is: " + String.format("%f",
this.deltaXByRatio)
+ + "the Y ByRatio is: " + String.format("%f",
this.deltaYByRatio));
+ // Calculate the complement area and grid i,j for grid number
+ // Xmax = x0+(2^n∗δx) Ymax = y0+(2^n∗δx) Where n is the number of cut
+ // Where x0, Y0 are the minimum x, y coordinates of a given region,
+ // Xmax >= maxLongitude Ymax >= maxLatitude
+ // In the calculation process, first substitute maxlongitude and
maxlatitude to calculate n.
+ // if n is not an integer, then take the next integer of N, and then
substitute to find
+ // xmax and ymax。
+ this.calculateArea();
+ }
+
+ /**
+ * Calculate the complement area, including the range of the complement
area, t
+ * he number of knives cut and the depth of the quad tree
+ */
+ private void calculateArea() {
+ // step 1 calculate xn, yn by using maxLongitude, maxLatitude,
minLongitude, minLatitude
+ // substitution formula
+ // Here, the user's given area is mostly rectangle, which needs to be
extended to
+ // square processing to find the maximum value of XN and yn
+ // n=log_2 (Xmax−X0)/δx, log_2 (Ymax−Y0)/δy
+ double Xn = Math.log((userDefineMaxLongitude - userDefineMinLongitude) /
deltaX)
+ / Math.log(2);
+ double Yn = Math.log((userDefineMaxLatitude - userDefineMinLatitude) /
deltaY)
+ / Math.log(2);
+ double doubleMax = Math.max(Xn, Yn);
+ this.cutLevel = doubleMax % 1 == 0 ? (int) doubleMax : (int) (doubleMax +
1);
+ // setep 2 recalculate the region according to the number of segmentation
+ this.CalculateMaxLongitude = userDefineMinLongitude + Math.pow(2,
this.cutLevel)
+ * deltaX;
+ this.CalculateMaxLatitude = userDefineMinLatitude + Math.pow(2,
this.cutLevel)
+ * deltaY;
+ LOGGER.info("After spatial calculate the cut level is: " +
String.format("%d", this.cutLevel));
+ LOGGER.info("the min longitude is: " + String.format("%f",
this.userDefineMinLongitude) +
+ " the max longitude is: " + String.format("%f",
this.CalculateMaxLongitude));
+ LOGGER.info("the min latitude is: " + String.format("%f",
this.userDefineMinLatitude) +
+ " the max latitude is: " + String.format("%f",
this.CalculateMaxLatitude));
+ }
+
+ /**
+ * Through grid index coordinates and calculation of hashid, grid latitude
and longitude
+ * coordinates can be transformed by latitude and longitude
+ * @param longitude Longitude, the actual longitude and latitude are
processed by * coefficient,
+ * and the floating-point calculation is converted to
integer calculation
+ * @param latitude Latitude, the actual longitude and latitude are processed
by * coefficient,
+ * and the floating-point calculation is converted to
integer calculation.
+ * @return Grid ID value [row, column] column starts from 1
+ */
+ private int[] calculateID(long longitude, long latitude) throws Exception {
+ try {
+ int row = (int) ((longitude - this.lon0ByRation) / this.deltaXByRatio);
+ int column = (int) ((latitude - this.lat0ByRation) / this.deltaYByRatio);
+ return new int[]{row, column};
+ } catch (ArithmeticException e) {
+ throw new RuntimeException("can not divide by zero.");
+ }
+ }
+
+ /**
+ * Calculate the corresponding hashid value from the grid coordinates
+ * @param row Gridded row index
+ * @param column Gridded column index
+ * @return hash id
+ */
+ private long createHashID(long row, long column) {
+ long index = 0L;
+ for (int i = 0; i < cutLevel + 1; i++) {
+ long x = (row >> i) & 1; //取第i位
Review comment:
please use english comment
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]
With regards,
Apache Git Services