From 40d651bfe9eb2774641ed0e4d7bd8f6030aa1b07 Mon Sep 17 00:00:00 2001 From: Yuxuan HU Date: Mon, 12 Jan 2026 11:52:34 +1100 Subject: [PATCH 1/2] add key in feature properties --- .../server/core/service/ElasticSearch.java | 35 ++++++++++++++++++- .../server/service/ElasticSearchTest.java | 30 ++++++++++++++-- 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/ElasticSearch.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/ElasticSearch.java index af5d6647..b6ad7fe4 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/ElasticSearch.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/ElasticSearch.java @@ -650,7 +650,40 @@ public SearchResult searchFeatureSummary(String collectionId, Li for (var hit : response.hits().hits()) { EsFeatureCollectionModel hitFeatureCollection = hit.source(); if (hitFeatureCollection != null && hitFeatureCollection.getFeatures() != null) { - features.addAll(hitFeatureCollection.toFeatureCollectionGeoJSON().getFeatures()); + // A collectionID may map to several dataset key. So we need to group features by dataset keys. TO get a dataset key which sits in hit.properties.key. For example: + // "properties": { + // "date": "2011-04", + // "collection": "4d3d4aca-472e-4616-88a5-df0f5ab401ba", + // "key": "mooring_acidification_realtime_qc.parquet" + // } + String datasetKey = null; + if (hitFeatureCollection.getProperties() != null) { + Object keyObj = hitFeatureCollection.getProperties().get("key"); + if (keyObj != null) { + datasetKey = keyObj.toString(); + } + } + + List documentFeatures = + hitFeatureCollection.toFeatureCollectionGeoJSON().getFeatures(); + + for (FeatureGeoJSON feature : documentFeatures) { + // add key in property field for each feature + if (datasetKey != null) { + Object featurePropsObj = feature.getProperties(); + + if (featurePropsObj instanceof Map) { + @SuppressWarnings("unchecked") + Map featurePropsMap = (Map) featurePropsObj; + featurePropsMap.put("key", datasetKey); + } else { + Map newPropsMap = new HashMap<>(); + newPropsMap.put("key", datasetKey); + feature.setProperties(newPropsMap); + } + } + features.add(feature); + } } } diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/service/ElasticSearchTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/service/ElasticSearchTest.java index 7447e40a..77248c12 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/service/ElasticSearchTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/service/ElasticSearchTest.java @@ -13,6 +13,7 @@ import co.elastic.clients.elasticsearch.core.search.HitsMetadata; import co.elastic.clients.elasticsearch.core.search.TotalHits; import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -25,8 +26,10 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.*; +@Slf4j public class ElasticSearchTest { private ElasticsearchClient mockClient; private ElasticSearch elasticSearch; @@ -61,10 +64,22 @@ public void searchFeatureSummaryTest() throws IOException { featureCollectionProperties.put("key", "satellite_ghrsst_l4_gamssa_1day_multi_sensor_world.zarr"); esFeatureCollection.setProperties(featureCollectionProperties); var coords = new ArrayList>>(); + var esFeature = new EsFeatureModel(); + + // mock a single point [147.338884, -43.190779] + List> ring = new ArrayList<>(); + List point = List.of( + new BigDecimal("147.338884"), + new BigDecimal("-43.190779") + ); + ring.add(point); + coords.add(ring); + var polygon = new EsPolygonModel(); polygon.setCoordinates(coords); - var esFeature = new EsFeatureModel(); + esFeature.setGeometry(polygon); + esFeatureCollection.setFeatures(List.of(esFeature)); when(hit.source()).thenReturn(esFeatureCollection); @@ -88,7 +103,18 @@ public void searchFeatureSummaryTest() throws IOException { assertNotNull(result); assertEquals(1, result.getCollections().size()); assertEquals(1L, result.getTotal()); - assertEquals(esFeature.toFeatureGeoJSON(), result.getCollections().get(0)); + // validate geometry keeps same after adding key property + assertEquals(esFeature.toFeatureGeoJSON().getGeometry(), + result.getCollections().get(0).getGeometry()); + + // validate key is in properties + FeatureGeoJSON returnedFeature = result.getCollections().get(0); + @SuppressWarnings("unchecked") + Map featureProps = (Map) returnedFeature.getProperties(); + + assertTrue(featureProps.containsKey("key")); + assertEquals("satellite_ghrsst_l4_gamssa_1day_multi_sensor_world.zarr", + featureProps.get("key")); } From d16151dd8c95c32dca94298361c96b036f214e64 Mon Sep 17 00:00:00 2001 From: Yuxuan HU Date: Mon, 12 Jan 2026 11:55:47 +1100 Subject: [PATCH 2/2] minor refactor code --- .../au/org/aodn/ogcapi/server/core/service/ElasticSearch.java | 2 +- .../au/org/aodn/ogcapi/server/service/ElasticSearchTest.java | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/ElasticSearch.java b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/ElasticSearch.java index b6ad7fe4..315d9571 100644 --- a/server/src/main/java/au/org/aodn/ogcapi/server/core/service/ElasticSearch.java +++ b/server/src/main/java/au/org/aodn/ogcapi/server/core/service/ElasticSearch.java @@ -650,7 +650,7 @@ public SearchResult searchFeatureSummary(String collectionId, Li for (var hit : response.hits().hits()) { EsFeatureCollectionModel hitFeatureCollection = hit.source(); if (hitFeatureCollection != null && hitFeatureCollection.getFeatures() != null) { - // A collectionID may map to several dataset key. So we need to group features by dataset keys. TO get a dataset key which sits in hit.properties.key. For example: + // A collectionID may map to several dataset key. So we need to identify features with dataset keys. TO get a dataset key which sits in hit.properties.key. For example: // "properties": { // "date": "2011-04", // "collection": "4d3d4aca-472e-4616-88a5-df0f5ab401ba", diff --git a/server/src/test/java/au/org/aodn/ogcapi/server/service/ElasticSearchTest.java b/server/src/test/java/au/org/aodn/ogcapi/server/service/ElasticSearchTest.java index 77248c12..919e2b49 100644 --- a/server/src/test/java/au/org/aodn/ogcapi/server/service/ElasticSearchTest.java +++ b/server/src/test/java/au/org/aodn/ogcapi/server/service/ElasticSearchTest.java @@ -13,7 +13,6 @@ import co.elastic.clients.elasticsearch.core.search.HitsMetadata; import co.elastic.clients.elasticsearch.core.search.TotalHits; import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -29,7 +28,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.*; -@Slf4j public class ElasticSearchTest { private ElasticsearchClient mockClient; private ElasticSearch elasticSearch;