Skip to content

Commit

Permalink
refactor inner geogrid classes to own class files (#37596)
Browse files Browse the repository at this point in the history
To make further refactoring of GeoGrid aggregations
easier (related: #30320), splitting out these inner
class dependencies into their own files makes it
easier to map the relationship between classes
  • Loading branch information
talevy authored Jan 18, 2019
1 parent 88b9810 commit 106f900
Show file tree
Hide file tree
Showing 7 changed files with 262 additions and 204 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.search.aggregations.bucket.geogrid;

import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.SortedNumericDocValues;
import org.elasticsearch.common.geo.GeoHashUtils;
import org.elasticsearch.index.fielddata.AbstractSortingNumericDocValues;
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;

import java.io.IOException;

/**
* Wrapper class to help convert {@link MultiGeoPointValues}
* to numeric long values for bucketing.
*/
class CellIdSource extends ValuesSource.Numeric {
private final ValuesSource.GeoPoint valuesSource;
private final int precision;

CellIdSource(GeoPoint valuesSource, int precision) {
this.valuesSource = valuesSource;
//different GeoPoints could map to the same or different geohash cells.
this.precision = precision;
}

public int precision() {
return precision;
}

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

@Override
public SortedNumericDocValues longValues(LeafReaderContext ctx) {
return new CellValues(valuesSource.geoPointValues(ctx), precision);
}

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

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

private static class CellValues extends AbstractSortingNumericDocValues {
private MultiGeoPointValues geoValues;
private int precision;

protected CellValues(MultiGeoPointValues geoValues, int precision) {
this.geoValues = geoValues;
this.precision = precision;
}

@Override
public boolean advanceExact(int docId) throws IOException {
if (geoValues.advanceExact(docId)) {
resize(geoValues.docValueCount());
for (int i = 0; i < docValueCount(); ++i) {
org.elasticsearch.common.geo.GeoPoint target = geoValues.nextValue();
values[i] = GeoHashUtils.longEncode(target.getLon(), target.getLat(),
precision);
}
sort();
return true;
} else {
return false;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,13 @@

package org.elasticsearch.search.aggregations.bucket.geogrid;

import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.SortedNumericDocValues;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.geo.GeoHashUtils;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.geo.GeoUtils;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.ObjectParser;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.fielddata.AbstractSortingNumericDocValues;
import org.elasticsearch.index.fielddata.MultiGeoPointValues;
import org.elasticsearch.index.fielddata.SortedBinaryDocValues;
import org.elasticsearch.index.fielddata.SortedNumericDoubleValues;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregatorFactories.Builder;
import org.elasticsearch.search.aggregations.AggregatorFactory;
Expand Down Expand Up @@ -207,65 +199,5 @@ public String getType() {
return NAME;
}

private static class CellValues extends AbstractSortingNumericDocValues {
private MultiGeoPointValues geoValues;
private int precision;

protected CellValues(MultiGeoPointValues geoValues, int precision) {
this.geoValues = geoValues;
this.precision = precision;
}

@Override
public boolean advanceExact(int docId) throws IOException {
if (geoValues.advanceExact(docId)) {
resize(geoValues.docValueCount());
for (int i = 0; i < docValueCount(); ++i) {
GeoPoint target = geoValues.nextValue();
values[i] = GeoHashUtils.longEncode(target.getLon(), target.getLat(),
precision);
}
sort();
return true;
} else {
return false;
}
}
}

static class CellIdSource extends ValuesSource.Numeric {
private final ValuesSource.GeoPoint valuesSource;
private final int precision;

CellIdSource(ValuesSource.GeoPoint valuesSource, int precision) {
this.valuesSource = valuesSource;
//different GeoPoints could map to the same or different geohash cells.
this.precision = precision;
}

public int precision() {
return precision;
}

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

@Override
public SortedNumericDocValues longValues(LeafReaderContext ctx) {
return new CellValues(valuesSource.geoPointValues(ctx), precision);
}

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

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

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.search.aggregations.bucket.geogrid;

import org.elasticsearch.common.geo.GeoHashUtils;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.InternalAggregation;
import org.elasticsearch.search.aggregations.InternalAggregations;
import org.elasticsearch.search.aggregations.InternalMultiBucketAggregation;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

class GeoGridBucket extends InternalMultiBucketAggregation.InternalBucket implements GeoHashGrid.Bucket, Comparable<GeoGridBucket> {

protected long geohashAsLong;
protected long docCount;
protected InternalAggregations aggregations;

GeoGridBucket(long geohashAsLong, long docCount, InternalAggregations aggregations) {
this.docCount = docCount;
this.aggregations = aggregations;
this.geohashAsLong = geohashAsLong;
}

/**
* Read from a stream.
*/
GeoGridBucket(StreamInput in) throws IOException {
geohashAsLong = in.readLong();
docCount = in.readVLong();
aggregations = InternalAggregations.readAggregations(in);
}

@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeLong(geohashAsLong);
out.writeVLong(docCount);
aggregations.writeTo(out);
}

@Override
public String getKeyAsString() {
return GeoHashUtils.stringEncode(geohashAsLong);
}

@Override
public GeoPoint getKey() {
return GeoPoint.fromGeohash(geohashAsLong);
}

@Override
public long getDocCount() {
return docCount;
}

@Override
public Aggregations getAggregations() {
return aggregations;
}

@Override
public int compareTo(GeoGridBucket other) {
if (this.geohashAsLong > other.geohashAsLong) {
return 1;
}
if (this.geohashAsLong < other.geohashAsLong) {
return -1;
}
return 0;
}

public GeoGridBucket reduce(List<? extends GeoGridBucket> buckets, InternalAggregation.ReduceContext context) {
List<InternalAggregations> aggregationsList = new ArrayList<>(buckets.size());
long docCount = 0;
for (GeoGridBucket bucket : buckets) {
docCount += bucket.docCount;
aggregationsList.add(bucket.aggregations);
}
final InternalAggregations aggs = InternalAggregations.reduce(aggregationsList, context);
return new GeoGridBucket(geohashAsLong, docCount, aggs);
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field(Aggregation.CommonFields.KEY.getPreferredName(), getKeyAsString());
builder.field(Aggregation.CommonFields.DOC_COUNT.getPreferredName(), docCount);
aggregations.toXContentInternal(builder, params);
builder.endObject();
return builder;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GeoGridBucket bucket = (GeoGridBucket) o;
return geohashAsLong == bucket.geohashAsLong &&
docCount == bucket.docCount &&
Objects.equals(aggregations, bucket.aggregations);
}

@Override
public int hashCode() {
return Objects.hash(geohashAsLong, docCount, aggregations);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ public class GeoHashGridAggregator extends BucketsAggregator {

private final int requiredSize;
private final int shardSize;
private final GeoGridAggregationBuilder.CellIdSource valuesSource;
private final CellIdSource valuesSource;
private final LongHash bucketOrds;

GeoHashGridAggregator(String name, AggregatorFactories factories, GeoGridAggregationBuilder.CellIdSource valuesSource,
GeoHashGridAggregator(String name, AggregatorFactories factories, CellIdSource valuesSource,
int requiredSize, int shardSize, SearchContext aggregationContext, Aggregator parent,
List<PipelineAggregator> pipelineAggregators, Map<String, Object> metaData) throws IOException {
super(name, factories, aggregationContext, parent, pipelineAggregators, metaData);
Expand Down Expand Up @@ -96,7 +96,7 @@ public void collect(int doc, long bucket) throws IOException {
}

// private impl that stores a bucket ord. This allows for computing the aggregations lazily.
static class OrdinalBucket extends InternalGeoHashGrid.Bucket {
static class OrdinalBucket extends GeoGridBucket {

long bucketOrd;

Expand Down Expand Up @@ -125,7 +125,7 @@ public InternalGeoHashGrid buildAggregation(long owningBucketOrdinal) throws IOE
spare = (OrdinalBucket) ordered.insertWithOverflow(spare);
}

final InternalGeoHashGrid.Bucket[] list = new InternalGeoHashGrid.Bucket[ordered.size()];
final GeoGridBucket[] list = new GeoGridBucket[ordered.size()];
for (int i = ordered.size() - 1; i >= 0; --i) {
final OrdinalBucket bucket = (OrdinalBucket) ordered.pop();
bucket.aggregations = bucketAggregations(bucket.bucketOrd);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import org.elasticsearch.search.aggregations.AggregatorFactory;
import org.elasticsearch.search.aggregations.InternalAggregation;
import org.elasticsearch.search.aggregations.NonCollectingAggregator;
import org.elasticsearch.search.aggregations.bucket.geogrid.GeoGridAggregationBuilder.CellIdSource;
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
import org.elasticsearch.search.aggregations.support.ValuesSource;
import org.elasticsearch.search.aggregations.support.ValuesSource.GeoPoint;
Expand Down Expand Up @@ -56,7 +55,7 @@ public class GeoHashGridAggregatorFactory extends ValuesSourceAggregatorFactory<
protected Aggregator createUnmapped(Aggregator parent, List<PipelineAggregator> pipelineAggregators, Map<String, Object> metaData)
throws IOException {
final InternalAggregation aggregation = new InternalGeoHashGrid(name, requiredSize,
Collections.<InternalGeoHashGrid.Bucket> emptyList(), pipelineAggregators, metaData);
Collections.emptyList(), pipelineAggregators, metaData);
return new NonCollectingAggregator(name, context, parent, pipelineAggregators, metaData) {
@Override
public InternalAggregation buildEmptyAggregation() {
Expand Down
Loading

0 comments on commit 106f900

Please sign in to comment.