All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.elasticsearch.search.aggregations.bucket.geogrid.GeoTileCellIdSource Maven / Gradle / Ivy

There is a newer version: 8.14.0
Show newest version
/*
 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
 * or more contributor license agreements. Licensed under the Elastic License
 * 2.0 and the Server Side Public License, v 1; you may not use this file except
 * in compliance with, at your election, the Elastic License 2.0 or the Server
 * Side Public License, v 1.
 */
package org.elasticsearch.search.aggregations.bucket.geogrid;

import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.SortedNumericDocValues;
import org.elasticsearch.common.geo.GeoBoundingBox;
import org.elasticsearch.geometry.Rectangle;
import org.elasticsearch.index.fielddata.MultiGeoPointValues;
import org.elasticsearch.index.fielddata.SortedBinaryDocValues;
import org.elasticsearch.index.fielddata.SortedNumericDoubleValues;
import org.elasticsearch.search.aggregations.support.ValuesSource;

/**
 * Class to help convert {@link MultiGeoPointValues}
 * to GeoTile bucketing.
 */
public class GeoTileCellIdSource extends ValuesSource.Numeric {
    private final GeoPoint valuesSource;
    private final int precision;
    private final GeoBoundingBox geoBoundingBox;

    public GeoTileCellIdSource(GeoPoint valuesSource, int precision, GeoBoundingBox geoBoundingBox) {
        this.valuesSource = valuesSource;
        this.precision = precision;
        this.geoBoundingBox = geoBoundingBox;
    }

    public int precision() {
        return precision;
    }

    @Override
    public boolean isFloatingPoint() {
        return false;
    }

    @Override
    public SortedNumericDocValues longValues(LeafReaderContext ctx) {
        return geoBoundingBox.isUnbounded()
            ? new UnboundedCellValues(valuesSource.geoPointValues(ctx), precision)
            : new BoundedCellValues(valuesSource.geoPointValues(ctx), precision, geoBoundingBox);
    }

    @Override
    public SortedNumericDoubleValues doubleValues(LeafReaderContext ctx) {
        throw new UnsupportedOperationException();
    }

    @Override
    public SortedBinaryDocValues bytesValues(LeafReaderContext ctx) {
        throw new UnsupportedOperationException();
    }

    private static class UnboundedCellValues extends CellValues {

        UnboundedCellValues(MultiGeoPointValues geoValues, int precision) {
            super(geoValues, precision);
        }

        @Override
        int advanceValue(org.elasticsearch.common.geo.GeoPoint target, int valuesIdx) {
            values[valuesIdx] = GeoTileUtils.longEncode(target.getLon(), target.getLat(), precision);
            return valuesIdx + 1;
        }
    }

    private static class BoundedCellValues extends CellValues {

        private final boolean crossesDateline;
        private final long tiles;
        private final int minX, maxX, minY, maxY;

        protected BoundedCellValues(MultiGeoPointValues geoValues, int precision, GeoBoundingBox bbox) {
            super(geoValues, precision);
            this.crossesDateline = bbox.right() < bbox.left();
            this.tiles = 1L << precision;
            // compute minX, minY
            final int minX = GeoTileUtils.getXTile(bbox.left(), this.tiles);
            final int minY = GeoTileUtils.getYTile(bbox.top(), this.tiles);
            final Rectangle minTile = GeoTileUtils.toBoundingBox(minX, minY, precision);
            // touching tiles are excluded, they need to share at least one interior point
            this.minX = minTile.getMaxX() == bbox.left() ? minX + 1 : minX;
            this.minY = minTile.getMinY() == bbox.top() ? minY + 1 : minY;
            // compute maxX, maxY
            final int maxX = GeoTileUtils.getXTile(bbox.right(), this.tiles);
            final int maxY = GeoTileUtils.getYTile(bbox.bottom(), this.tiles);
            final Rectangle maxTile = GeoTileUtils.toBoundingBox(maxX, maxY, precision);
            // touching tiles are excluded, they need to share at least one interior point
            this.maxX = maxTile.getMinX() == bbox.right() ? maxX - 1 : maxX;
            this.maxY = maxTile.getMaxY() == bbox.bottom() ? maxY - 1 : maxY;
        }

        @Override
        int advanceValue(org.elasticsearch.common.geo.GeoPoint target, int valuesIdx) {
            final int x = GeoTileUtils.getXTile(target.getLon(), this.tiles);
            final int y = GeoTileUtils.getYTile(target.getLat(), this.tiles);
            if (validTile(x, y)) {
                values[valuesIdx] = GeoTileUtils.longEncodeTiles(precision, x, y);
                return valuesIdx + 1;
            }
            return valuesIdx;
        }

        private boolean validTile(int x, int y) {
            if (maxY >= y && minY <= y) {
                if (crossesDateline) {
                    return maxX >= x || minX <= x;
                } else {
                    return maxX >= x && minX <= x;
                }
            }
            return false;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy