Skip to content

Commit

Permalink
Merge pull request #94 from aodn/feature/6053-query-dataset-with-filter
Browse files Browse the repository at this point in the history
Feature/6053 query dataset with filter
  • Loading branch information
utas-raymondng authored Nov 20, 2024
2 parents c061c22 + 46c4746 commit 4cd47fc
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package au.org.aodn.ogcapi.server.core.model;

import au.org.aodn.ogcapi.features.model.*;
import au.org.aodn.ogcapi.features.model.FeatureCollectionGeoJSON;
import au.org.aodn.ogcapi.features.model.FeatureGeoJSON;
import au.org.aodn.ogcapi.features.model.PointGeoJSON;
import au.org.aodn.ogcapi.server.core.model.enumeration.FeatureProperty;
import lombok.Getter;
import au.org.aodn.ogcapi.server.core.util.DatasetSummarizer;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

@Getter
public class DatasetSearchResult {

private final FeatureCollectionGeoJSON dataset;
Expand All @@ -24,6 +25,12 @@ private void initDataset() {
dataset.setFeatures(new ArrayList<>());
}

public FeatureCollectionGeoJSON getSummarizedDataset() {
var summarizer = new DatasetSummarizer(dataset);
summarizer.summarizeDataset();
return summarizer.getSummarizedDataset();
}

public void addDatum(DatumModel datum) {

if (datum == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ public enum FeatureProperty {
TIME("time"),
DEPTH("depth"),
COUNT("count"),
UUID("uuid")
UUID("uuid"),
START_TIME("startTime"),
END_TIME("endTime"),
COORDINATE_ACCURACY("coordinateAccuracy"),
;

private final String value;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
package au.org.aodn.ogcapi.server.core.util;

import au.org.aodn.ogcapi.features.model.FeatureCollectionGeoJSON;
import au.org.aodn.ogcapi.features.model.FeatureGeoJSON;
import au.org.aodn.ogcapi.features.model.PointGeoJSON;
import au.org.aodn.ogcapi.server.core.model.enumeration.FeatureProperty;
import lombok.Getter;

import java.time.YearMonth;
import java.util.HashMap;
import java.util.Map;

public class DatasetSummarizer {

private final FeatureCollectionGeoJSON dataset;

@Getter
private final FeatureCollectionGeoJSON summarizedDataset;

public DatasetSummarizer(FeatureCollectionGeoJSON dataset) {
this.dataset = dataset;
this.summarizedDataset = new FeatureCollectionGeoJSON();
this.summarizedDataset.setType(FeatureCollectionGeoJSON.TypeEnum.FEATURECOLLECTION);
summarizeDataset();
}


public void summarizeDataset() {
for (var feature : dataset.getFeatures()) {
var sameLocationFeature = getSameLocationFeature(feature);
if (sameLocationFeature == null) {
summarizedDataset
.getFeatures()
.add(generateNewSummarizedFeature(feature));
continue;
}
var newFeature = aggregateFeature(sameLocationFeature, feature);
summarizedDataset.getFeatures().remove(sameLocationFeature);
summarizedDataset.getFeatures().add(newFeature);
}
}

@SuppressWarnings("unchecked")
private FeatureGeoJSON aggregateFeature(FeatureGeoJSON existingFeature, FeatureGeoJSON featureToAdd) {
var aggregatedFeature = new FeatureGeoJSON();
aggregatedFeature.setType(FeatureGeoJSON.TypeEnum.FEATURE);
aggregatedFeature.setGeometry(existingFeature.getGeometry());

try{
var existingProperties = (Map<String, Object>) existingFeature.getProperties();

var newTimeStr = getTime(featureToAdd);
var timeUpdatedProperties = updateTimeRange(existingProperties, newTimeStr);

var newCount = getCount(featureToAdd);
var timeAndCountUpdatedProperties = updateCount(timeUpdatedProperties, newCount);

aggregatedFeature.setProperties(timeAndCountUpdatedProperties);
} catch (ClassCastException e) {
throw new RuntimeException("Feature properties is not a map", e);
}
return aggregatedFeature;
}

private Map<String, Object> updateCount(Map<String, Object> existingProperties, Long newCount) {
var existingCount = (Long) existingProperties.get(FeatureProperty.COUNT.getValue());
var updatedProperties = new HashMap<>(existingProperties);
updatedProperties.put(FeatureProperty.COUNT.getValue(), existingCount + newCount);
return updatedProperties;
}

private Map<String, Object> updateTimeRange(Map<String, Object> existingProperties, String newTimeStr) {

var startTimeStr = (String) existingProperties.get(FeatureProperty.START_TIME.getValue());
var endTimeStr = (String) existingProperties.get(FeatureProperty.END_TIME.getValue());

var updatedProperties = new HashMap<>(existingProperties);
updatedProperties.remove(FeatureProperty.TIME.getValue());
if (newTimeStr != null) {
var newTime = YearMonth.parse(newTimeStr);
var startTime = YearMonth.parse(startTimeStr);
var endTime = YearMonth.parse(endTimeStr);
if (newTime.isBefore(startTime)) {
startTimeStr = newTimeStr;
} else if (newTime.isAfter(endTime)) {
endTimeStr = newTimeStr;
}
updatedProperties.put(FeatureProperty.START_TIME.getValue(), startTimeStr);
updatedProperties.put(FeatureProperty.END_TIME.getValue(), endTimeStr);
}
return updatedProperties;
}


private FeatureGeoJSON generateNewSummarizedFeature(FeatureGeoJSON feature) {
var summarizedFeature = new FeatureGeoJSON();
summarizedFeature.setType(FeatureGeoJSON.TypeEnum.FEATURE);
summarizedFeature.setGeometry(feature.getGeometry());
summarizedFeature.setProperties(feature.getProperties());
var time = getTime(feature);
setPropertyToFeature(feature, FeatureProperty.START_TIME , time);
setPropertyToFeature(feature, FeatureProperty.END_TIME , time);

return summarizedFeature;
}

@SuppressWarnings("unchecked")
private void setPropertyToFeature(
FeatureGeoJSON feature, FeatureProperty propertyType, String value
) {
try{
var properties = (Map<String, Object>) feature.getProperties();
properties.put(propertyType.getValue(), value);
} catch (ClassCastException e) {
throw new RuntimeException("Feature properties is not a map", e);
}
}

@SuppressWarnings("unchecked")
private Object getPropertyFromFeature(FeatureGeoJSON feature, FeatureProperty propertyType) {
try{
var properties = (Map<String, Object>) feature.getProperties();
return properties.get(propertyType.getValue());
} catch (ClassCastException e) {
throw new RuntimeException("Feature properties is not a map", e);
}
}

private Long getCount(FeatureGeoJSON feature) {
try {
return (Long) getPropertyFromFeature(feature, FeatureProperty.COUNT);
} catch (Exception e) {
throw new RuntimeException("failed to get count from feature", e);
}
}

private String getTime(FeatureGeoJSON feature) {
try {
return (String) getPropertyFromFeature(feature, FeatureProperty.TIME);
} catch (Exception e) {
throw new RuntimeException("failed to get time from feature", e);
}
}


private FeatureGeoJSON getSameLocationFeature(FeatureGeoJSON feature) {
for (var f : summarizedDataset.getFeatures()) {
try {
var existingCoordinates = ((PointGeoJSON) f.getGeometry()).getCoordinates();
var newCoordinates = ((PointGeoJSON) feature.getGeometry()).getCoordinates();
if (existingCoordinates.get(0).equals(newCoordinates.get(0)) && existingCoordinates.get(1).equals(newCoordinates.get(1))) {
return f;
}
} catch (ClassCastException e) {
throw new RuntimeException("Feature geometry is not a point", e);
}
}
return null;
}


}

// following are values from experience. can change
//1 decimal place: ~11.1 kilometers
//2 decimal places: ~1.1 kilometers
//3 decimal places: ~110 meters
//4 decimal places: ~11 meters
//5 decimal places: ~1.1 meters

// zoom level less than 7.3, 1 decimal place
// zoom level less than 4, integer
// zoom level less than 1.2, 10
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,12 @@ public ResponseEntity<FeatureCollectionGeoJSON> getFeatures(

@PathVariable("collectionId") String collectionId,
@RequestParam(value = "start_datetime", required = false) String startDate,
@RequestParam(value = "end_datetime", required = false) String endDate
@RequestParam(value = "end_datetime", required = false) String endDate,
// keep these two parameters for future usage
@RequestParam(value= "zoom", required = false) Double zoomLevel,
@RequestParam(value="bbox", required = false) List<BigDecimal> bbox
) {
return featuresService.getDataset(collectionId, startDate, endDate);
return featuresService.getSummarizedDataset(collectionId, startDate, endDate);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ public ResponseEntity<Collection> getCollection(String id, String sortBy) throws
}
}

public ResponseEntity<FeatureCollectionGeoJSON> getDataset(
public ResponseEntity<FeatureCollectionGeoJSON> getSummarizedDataset(
String collectionId,
String startDate,
String endDate
) {
try {
var result = search.searchDataset(collectionId, startDate, endDate);
return ResponseEntity.ok()
.body(result.getDataset());
.body(result.getSummarizedDataset());
} catch (Exception e) {
log.error("Error while getting dataset", e);
return ResponseEntity.internalServerError().build();
Expand Down

0 comments on commit 4cd47fc

Please sign in to comment.