Skip to content

Commit

Permalink
Merge pull request #567 from gisaia/feature/boundingbox_geocentroid
Browse files Browse the repository at this point in the history
Add geobbox and geocentroid metrics in the _compute endpoint
  • Loading branch information
MohamedHamouGisaia authored Jan 2, 2020
2 parents 9dd5e38 + 1a4692b commit d60b8f4
Show file tree
Hide file tree
Showing 9 changed files with 90 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ public class Documentation {

public static final String COMPUTE_OPERATION = "Computes the given metric on a field in the collection, given the filters";
public static final String COMPUTE_FIELD = "The field on which the metric is calculated.";
public static final String COMPUTE_METRIC = "The metric to compute : `max, min, avg, sum, cardinality, spanning`.";
public static final String COMPUTE_METRIC = "The metric to compute : `max, min, avg, sum, cardinality, spanning, geobbox, geocentroid`.";


}
10 changes: 10 additions & 0 deletions arlas-core/src/main/java/io/arlas/server/core/FluidSearch.java
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ public class FluidSearch {
public static final String FIELD_AVG_VALUE = "field_avg_value";
public static final String FIELD_SUM_VALUE = "field_sum_value";
public static final String FIELD_CARDINALITY_VALUE = "field_cardinality_value";
public static final String FIELD_GEOBBOX_VALUE = "field_bbox_value";
public static final String FIELD_GEOCENTROID_VALUE = "field_centroid_value";


public static final String RANDOM_GEOMETRY = "random_geometry";
Expand Down Expand Up @@ -586,6 +588,14 @@ public FluidSearch compute(String field, ComputationEnum metric) {
maxAggregationBuilder = AggregationBuilders.max(FIELD_MAX_VALUE).field(field);
searchRequestBuilder = searchRequestBuilder.setSize(0).addAggregation(minAggregationBuilder).addAggregation(maxAggregationBuilder);
break;
case GEOBBOX:
GeoBoundsAggregationBuilder geoBoundsAggregationBuilder = AggregationBuilders.geoBounds(FIELD_GEOBBOX_VALUE).field(field);
searchRequestBuilder = searchRequestBuilder.setSize(0).addAggregation(geoBoundsAggregationBuilder);
break;
case GEOCENTROID:
GeoCentroidAggregationBuilder geoCentroidAggregationBuilder = AggregationBuilders.geoCentroid(FIELD_GEOCENTROID_VALUE).field(field);
searchRequestBuilder = searchRequestBuilder.setSize(0).addAggregation(geoCentroidAggregationBuilder);
break;
}
return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import java.util.Arrays;

public enum ComputationEnum {
AVG("avg"), MAX("max"), MIN("min"), SUM("sum"), CARDINALITY("cardinality"), SPANNING("spanning");
AVG("avg"), MAX("max"), MIN("min"), SUM("sum"), CARDINALITY("cardinality"), SPANNING("spanning"), GEOBBOX("geobbox"), GEOCENTROID("geocentroid");

private final String value;
private static final String INVALID_COMPUTATION_METRIC = "Invalid metric : must be one of ";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@
package io.arlas.server.model.response;

import io.arlas.server.model.enumerations.ComputationEnum;
import org.geojson.GeoJsonObject;

public class ComputationResponse extends OperationInfo {
public String field;
public ComputationEnum metric;
public double value;
public Double value;
public GeoJsonObject geometry;
}
Original file line number Diff line number Diff line change
Expand Up @@ -165,14 +165,16 @@ public ComputationResponse compute(MixedRequest request, CollectionReference col
computationResponse.metric = metric;
computationResponse.totalnb = response.getHits().getTotalHits().value;
List<org.elasticsearch.search.aggregations.Aggregation> aggregations = response.getAggregations().asList();
computationResponse.value = null;
computationResponse.geometry = null;

if (computationResponse.totalnb > 0) {
switch (metric) {
case AVG:
computationResponse.value = ((Avg)aggregations.get(0)).getValue();
break;
case CARDINALITY:
computationResponse.value = ((Cardinality)aggregations.get(0)).getValue();
computationResponse.value = new Double(((Cardinality)aggregations.get(0)).getValue());
break;
case MAX:
computationResponse.value = ((Max)aggregations.get(0)).getValue();
Expand All @@ -195,6 +197,13 @@ public ComputationResponse compute(MixedRequest request, CollectionReference col
case SUM:
computationResponse.value = ((Sum)aggregations.get(0)).getValue();
break;
case GEOBBOX:
computationResponse.geometry = createBox(((GeoBounds)aggregations.get(0)));
break;
case GEOCENTROID:
GeoPoint centroid = ((GeoCentroid) aggregations.get(0)).centroid();
computationResponse.geometry = new Point(centroid.getLon(), centroid.getLat());
break;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,13 @@ public static void checkComputationRequest(Request request, CollectionReference
if (computationRequest.metric == null) {
throw new InvalidParameterException(INVALID_COMPUTE_REQUEST + INVALID_COMPUTE_METRIC);
}
/** Except for CARDINALITY, the field on which the metric is computed should be numeric or date**/
if (!computationRequest.metric.equals(ComputationEnum.CARDINALITY)) {
if (computationRequest.metric.equals(ComputationEnum.GEOBBOX) || computationRequest.metric.equals(ComputationEnum.GEOCENTROID)) {
ElasticType fieldType = CollectionReferenceManager.getInstance().getType(collectionReference, computationRequest.field, false);
if (!ElasticType.GEO_POINT.equals(fieldType) && !ElasticType.UNKNOWN.equals(fieldType)) {
throw new InvalidParameterException(INVALID_COMPUTE_REQUEST + "`" + computationRequest.metric + "` must be applied on a geo-point field");
}
} else if (!computationRequest.metric.equals(ComputationEnum.CARDINALITY)) {
/** Except for CARDINALITY, GEOBBOX and GEOCENTROID, the field on which the metric is computed should be numeric or date**/
ElasticType fieldType = CollectionReferenceManager.getInstance().getType(collectionReference, computationRequest.field, false);
if (!ElasticType.getComputableTypes().contains(fieldType)) {
throw new InvalidParameterException(INVALID_COMPUTE_REQUEST + "`" + computationRequest.metric + "` must be applied on a numeric or date field");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,19 @@ public void testComputeRequest() throws Exception {
handleComputationRequest(post(computationRequest), 271, 374900);
handleComputationRequest(get(computationRequest.field, computationRequest.metric.value()), 271, 374900);

/** GEOCENTROID **/
computationRequest.filter.f = Arrays.asList(new MultiValueFilter<>(new Expression("geo_params.geometry", OperatorEnum.within, "-20,-20,30,30")));
computationRequest.field = "geo_params.centroid";
computationRequest.metric = ComputationEnum.GEOCENTROID;
handleGeocentroidComputationRequest(post(computationRequest), 16, 4.9f, 4.9f, 5, 5);
handleGeocentroidComputationRequest(get(computationRequest.field, computationRequest.metric.value(), "f", computationRequest.filter.f.get(0).get(0).toString()), 16, 4.9f, 4.9f, 5, 5);

/** GEOBBOX **/
computationRequest.field = "geo_params.centroid";
computationRequest.metric = ComputationEnum.GEOBBOX;
handleGeoboxComputationRequest(post(computationRequest), 16, -11, -11, 20, 20);
handleGeoboxComputationRequest(get(computationRequest.field, computationRequest.metric.value(), "f", computationRequest.filter.f.get(0).get(0).toString()), 16, -11, -11, 20, 20);


/** EMPTY RESPONSE : RESTRICTIVE FILTER**/
computationRequest.filter.f = Arrays.asList(new MultiValueFilter<>(new Expression("params.startdate", OperatorEnum.lt, "0")));
Expand Down Expand Up @@ -109,9 +122,20 @@ public void testInvalidComputationRequest() throws Exception {
computationRequest.metric = ComputationEnum.MAX;
handleInvalidComputationRequest(post(computationRequest));
handleInvalidComputationRequest(get(computationRequest.field, computationRequest.metric.value()));

computationRequest.field = "geo_params.geometry";
computationRequest.metric = ComputationEnum.GEOBBOX;
handleInvalidComputationRequest(post(computationRequest));
handleInvalidComputationRequest(get(computationRequest.field, computationRequest.metric.value()));

computationRequest.metric = ComputationEnum.GEOCENTROID;
handleInvalidComputationRequest(post(computationRequest));
handleInvalidComputationRequest(get(computationRequest.field, computationRequest.metric.value()));
}

protected abstract void handleComputationRequest(ValidatableResponse then, int count, float value) throws Exception;
protected abstract void handleGeoboxComputationRequest(ValidatableResponse then, int count, float west, float south, float east, float north) throws Exception;
protected abstract void handleGeocentroidComputationRequest(ValidatableResponse then, int count, float west, float south, float east, float north) throws Exception;
protected abstract void handleComputationEmptyResponse(ValidatableResponse then) throws Exception;
protected abstract void handleInvalidComputationRequest(ValidatableResponse then) throws Exception;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import org.hamcrest.Matcher;

import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.*;

public class ComputeServiceIT extends AbstractComputationTest {

Expand All @@ -41,6 +41,27 @@ protected void handleComputationRequest(ValidatableResponse then, int count, flo
.body("value", equalTo(value));
}

@Override
protected void handleGeoboxComputationRequest(ValidatableResponse then, int count, float west, float south, float east, float north) throws Exception {
then.statusCode(200)
.body("totalnb", equalTo(count))
.body("geometry.coordinates", hasItem(everyItem(hasItem(greaterThanOrEqualTo(west)))))
.body("geometry.coordinates", hasItem(everyItem(hasItem(greaterThanOrEqualTo(south)))))
.body("geometry.coordinates", hasItem(everyItem(hasItem(lessThanOrEqualTo(east)))))
.body("geometry.coordinates", hasItem(everyItem(hasItem(lessThanOrEqualTo(north)))));
}

@Override
protected void handleGeocentroidComputationRequest(ValidatableResponse then, int count, float west, float south, float east, float north) throws Exception {
then.statusCode(200)
.body("totalnb", equalTo(count))
.body("geometry.coordinates", hasItem((greaterThanOrEqualTo(west))))
.body("geometry.coordinates", hasItem(greaterThanOrEqualTo(south)))
.body("geometry.coordinates", hasItem(lessThanOrEqualTo(east)))
.body("geometry.coordinates", hasItem(lessThanOrEqualTo(north)));
}


@Override
protected void handleInvalidComputationRequest(ValidatableResponse then) throws Exception {
then.statusCode(400);
Expand All @@ -50,7 +71,7 @@ protected void handleInvalidComputationRequest(ValidatableResponse then) throws
protected void handleComputationEmptyResponse(ValidatableResponse then) throws Exception {
then.statusCode(200)
.body("totalnb", equalTo(0))
.body("value", equalTo(0f));
.body("value", isEmptyOrNullString());
}

@Override
Expand Down
12 changes: 11 additions & 1 deletion docs/arlas-api-exploration.md
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,17 @@ The `compute` url part is used in `_range` and `_compute` services.
| Parameter | Default value | Values | Description | Multiple |
| ---------- | ------------- | ------------ | -------------------- | -------- |
| **field** | `false` | `true,false` | The field on which the metric is calculated | false |
| **flat** | `false` | `true,false` | The metric to compute | false |
| **metric** | `` | `max, min, avg, sum, cardinality, spanning, geobbox, geocentroid` | The metric to compute | false |

!!! note 'Note'
- `max` : the maximum value of the given field. Field should be numeric or date.
- `min` : the minimum value of the given field. Field should be numeric or date.
- `avg` : the average of the given field values. Field should be numeric or date.
- `sum` : the sum of the given field values. Field should be numeric or date.
- `cardinality` : the number of distinct values of the given field.
- `spanning` : the range value (max-min) of the given field. Field should be numeric or date.
- `geobbox` : the extend of data based on the given geo-point field.
- `geocentroid` : the centroid of data based on the given geo-point field.

!!! info '_range is deprecated'
Starting from v12.7.0, `_range` endpoint is deprecated. You can use the new endpoint `_compute`.
Expand Down

0 comments on commit d60b8f4

Please sign in to comment.