Skip to content

Commit

Permalink
[GEOS-8600] GetTimeSeries slowness against multi-band coverage views
Browse files Browse the repository at this point in the history
  • Loading branch information
aaime committed Feb 27, 2018
1 parent 5e001b4 commit f684dd5
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,8 @@

package org.geoserver.wms.ncwms;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.TreeSet;

import net.opengis.wfs.FeatureCollectionType;
import net.opengis.wfs.WfsFactory;
import org.geoserver.catalog.CoverageInfo;
import org.geoserver.platform.GeoServerExtensions;
import org.geoserver.platform.ServiceException;
Expand All @@ -20,7 +15,6 @@
import org.geoserver.wms.MapLayerInfo;
import org.geoserver.wms.WMS;
import org.geoserver.wms.featureinfo.LayerIdentifier;
import org.geotools.data.DataUtilities;
import org.geotools.data.Query;
import org.geotools.data.collection.ListFeatureCollection;
import org.geotools.feature.FeatureCollection;
Expand All @@ -34,8 +28,12 @@
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;

import net.opengis.wfs.FeatureCollectionType;
import net.opengis.wfs.WfsFactory;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.TreeSet;

/**
* Implements the methods of the NcWMS service which are not included on the WMS standard. For the moment, only GetTimeSeries method is supported.
Expand Down Expand Up @@ -131,6 +129,13 @@ public FeatureCollectionType getTimeSeries(GetFeatureInfoRequest request) {
"The GetTimeSeries operation is only defined for coverage layers");
}

// we'll just pick the first band anyways, no need to read them all
if (request.getPropertyNames() == null || request.getPropertyNames().size() == 0 || request.getPropertyNames
().get(0).isEmpty()) {
String firstBand = coverage.getDimensions().get(0).getName();
request.setPropertyNames(Arrays.asList(Arrays.asList(firstBand)));
}

// control how much time we spend doing queries to gather times and values
int maxRenderingTime = wms.getMaxRenderingTime(request.getGetMapRequest());
CountdownClock countdownClock = new CountdownClock(maxRenderingTime);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,27 @@
*/
package org.geoserver.catalog;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.geoserver.catalog.CoverageView.CoverageBand;
import org.geoserver.feature.CompositeFeatureCollection;
import org.geotools.coverage.grid.io.DimensionDescriptor;
import org.geotools.coverage.grid.io.GranuleSource;
import org.geotools.coverage.grid.io.GranuleStore;
import org.geotools.coverage.grid.io.HarvestedSource;
import org.geotools.coverage.grid.io.StructuredGridCoverage2DReader;
import org.geotools.data.DataUtilities;
import org.geotools.data.Query;
import org.geotools.data.Transaction;
import org.geotools.data.collection.ListFeatureCollection;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.factory.Hints;
import org.geotools.feature.SchemaException;
import org.geotools.feature.collection.AbstractFeatureVisitor;
import org.geotools.gce.imagemosaic.Utils;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.util.DefaultProgressListener;
import org.opengis.feature.Feature;
import org.opengis.feature.Property;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.feature.type.Name;
import org.opengis.filter.Filter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* A coverageView reader using a structured coverage readers implementation
*
Expand All @@ -49,6 +37,12 @@ public class StructuredCoverageViewReader extends CoverageViewReader implements
private final static Logger LOGGER = org.geotools.util.logging.Logging
.getLogger(StructuredCoverageViewReader.class);

/**
* Pass this hint to {@link #getGranules(String, boolean)} in order to get back information from
* a single band of the coverage view
*/
public static Hints.Key QUERY_FIRST_BAND = new Hints.Key(Boolean.class);

static class GranuleStoreView implements GranuleStore {

private StructuredGridCoverage2DReader reader;
Expand All @@ -73,11 +67,16 @@ public SimpleFeatureCollection getGranules(Query q) throws IOException {
List<CoverageBand> bands = coverageView.getCoverageBands();
Query renamedQuery = q != null ? new Query(q) : new Query();
List<SimpleFeatureCollection> collections = new ArrayList<>();
boolean returnOnlyFirst = Boolean.TRUE.equals(renamedQuery.getHints().getOrDefault(QUERY_FIRST_BAND, false));
for (CoverageBand band : bands) {
String coverageName = band.getInputCoverageBands().get(0).getCoverageName();
renamedQuery.setTypeName(coverageName);
SimpleFeatureCollection collection = reader.getGranules(coverageName, readOnly).getGranules(renamedQuery);
collections.add(collection);

if (returnOnlyFirst) {
break;
}
}
// aggregate and return
if (collections.size() == 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.util.logging.Level;
import java.util.logging.Logger;

import org.geoserver.catalog.StructuredCoverageViewReader;
import org.geoserver.ows.kvp.TimeParser;
import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
import org.geotools.coverage.grid.io.DimensionDescriptor;
Expand All @@ -35,6 +36,7 @@
import org.geotools.coverage.grid.io.StructuredGridCoverage2DReader;
import org.geotools.data.Query;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.factory.Hints;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.visitor.UniqueVisitor;
import org.geotools.util.Converters;
Expand Down Expand Up @@ -400,6 +402,8 @@ private TreeSet<Object> getDimensionValuesInRange(String dimensionName, Range ra
FF.literal(range.getMinValue()), FF.literal(range.getMaxValue()));
query.setFilter(rangeFilter);
query.setMaxFeatures(maxEntries);
query.setPropertyNames(new String [] {descriptor.getStartAttribute()});
query.setHints(new Hints(StructuredCoverageViewReader.QUERY_FIRST_BAND, true));

FeatureCollection collection = gs.getGranules(query);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,8 @@
*/
package org.geoserver.wms.featureinfo;

import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.awt.image.RenderedImage;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.media.jai.PlanarImage;

import com.sun.org.apache.xml.internal.utils.XMLChar;
import com.vividsolutions.jts.geom.Coordinate;
import org.geoserver.catalog.CoverageInfo;
import org.geoserver.catalog.ProjectionPolicy;
import org.geoserver.wms.FeatureInfoRequestParameters;
Expand All @@ -39,6 +29,7 @@
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geometry.DirectPosition2D;
import org.geotools.geometry.TransformedDirectPosition;
import org.geotools.ows.ServiceException;
import org.geotools.parameter.Parameter;
import org.geotools.referencing.CRS;
import org.geotools.resources.geometry.XRectangle2D;
Expand All @@ -54,16 +45,25 @@
import org.opengis.filter.sort.SortBy;
import org.opengis.geometry.DirectPosition;
import org.opengis.parameter.GeneralParameterValue;
import org.opengis.referencing.ReferenceIdentifier;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.crs.GeographicCRS;
import org.opengis.referencing.datum.PixelInCell;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;

import com.sun.org.apache.xml.internal.utils.XMLChar;
import com.vividsolutions.jts.geom.Coordinate;


import javax.media.jai.PlanarImage;
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.awt.image.RenderedImage;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;


/**
Expand Down Expand Up @@ -188,7 +188,7 @@ requestedCRS, targetCRS, new Hints(Hints.LENIENT_DATUM_SHIFT,
// original range
final Rectangle2D.Double rasterArea = new Rectangle2D.Double();
rasterArea.setFrameFromCenter(rasterMid.getOrdinate(0), rasterMid.getOrdinate(1),
rasterMid.getOrdinate(0) + 10, rasterMid.getOrdinate(1) + 10);
rasterMid.getOrdinate(0) + 2, rasterMid.getOrdinate(1) + 2);
final Rectangle integerRasterArea = rasterArea.getBounds();
final GridEnvelope gridEnvelope = reader.getOriginalGridRange();
final Rectangle originalArea = (gridEnvelope instanceof GridEnvelope2D) ? (GridEnvelope2D) gridEnvelope
Expand All @@ -199,25 +199,45 @@ requestedCRS, targetCRS, new Hints(Hints.LENIENT_DATUM_SHIFT,
if (integerRasterArea.isEmpty()) {
return null;
}
// now set the grid geometry for this request

// now set the extra request parameters for this request
String[] propertyNames = params.getPropertyNames();
for (int k = 0; k < parameters.length; k++) {
if (!(parameters[k] instanceof Parameter<?>))
if (!(parameters[k] instanceof Parameter<?>)) {
continue;
}

final Parameter<?> parameter = (Parameter<?>) parameters[k];
if (parameter.getDescriptor().getName()
.equals(AbstractGridFormat.READ_GRIDGEOMETRY2D.getName())) {
ReferenceIdentifier name = parameter.getDescriptor().getName();
if (name.equals(AbstractGridFormat.READ_GRIDGEOMETRY2D.getName())) {
//
// create a suitable geometry for this request reusing the getmap (we
// could probably optimize)
//
parameter.setValue(new GridGeometry2D(new GridEnvelope2D(integerRasterArea), reader
.getOriginalGridToWorld(PixelInCell.CELL_CENTER), reader.getCoordinateReferenceSystem()));
} else if (propertyNames != null && propertyNames.length > 0 && name.equals(AbstractGridFormat.BANDS.getName())) {
int[] bands = new int[propertyNames.length];
Set<String> requestedNames = new HashSet<>(Arrays.asList(propertyNames));
List<String> dimensionNames = cinfo.getDimensions().stream().map(d -> d.getName()).collect(Collectors.toList());
for (int i = 0, j = 0; i < dimensionNames.size() && !requestedNames.isEmpty(); i++) {
String dimensionName = dimensionNames.get(i);
if (requestedNames.remove(dimensionName)) {
bands[j++] = i;
}
}
if (!requestedNames.isEmpty()) {
String availableNames = dimensionNames.stream().collect(Collectors.joining(", "));
throw new ServiceException("Could not find the following requested properties " + requestedNames
+ ", available property names are " + availableNames,
org.geoserver.platform.ServiceException.INVALID_PARAMETER_VALUE, "PropertyName");
}
parameter.setValue(bands);
}

}

final GridCoverage2D coverage = (GridCoverage2D) reader.read(parameters);
final GridCoverage2D coverage = reader.read(parameters);
if (coverage == null) {
if (LOGGER.isLoggable(Level.FINE))
LOGGER.fine("Unable to load raster data for this request.");
Expand Down

0 comments on commit f684dd5

Please sign in to comment.