Skip to content

Commit 65eaf58

Browse files
anthonyccrironq
authored andcommitted
GEOMESA-457 Optimize sorting of results
* Sorts results based on SortBy parameters
1 parent 9b12f5a commit 65eaf58

File tree

4 files changed

+208
-132
lines changed

4 files changed

+208
-132
lines changed

geomesa-core/src/main/scala/org/locationtech/geomesa/core/data/AccumuloFeatureSource.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ trait AccumuloAbstractFeatureSource extends AbstractFeatureSource {
5656
override def isOffsetSupported = false
5757
override def isReliableFIDSupported = true
5858
override def isUseProvidedFIDSupported = true
59-
override def supportsSorting(sortAttributes: Array[SortBy]) = false
59+
override def supportsSorting(sortAttributes: Array[SortBy]) = true
6060
}
6161

6262
protected def getFeaturesNoCache(query: Query): SimpleFeatureCollection = {

geomesa-core/src/main/scala/org/locationtech/geomesa/core/index/QueryPlanner.scala

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ import org.locationtech.geomesa.core.util.CloseableIterator._
3333
import org.locationtech.geomesa.core.util.{CloseableIterator, SelfClosingIterator}
3434
import org.locationtech.geomesa.utils.geotools.SimpleFeatureTypes
3535
import org.opengis.feature.simple.{SimpleFeature, SimpleFeatureType}
36+
import org.opengis.filter.sort.{SortBy, SortOrder}
37+
38+
import scala.reflect.ClassTag
3639

3740
object QueryPlanner {
3841
val iteratorPriority_RowRegex = 0
@@ -180,10 +183,37 @@ case class QueryPlanner(schema: String,
180183
DensityIterator.expandFeature(decoder.decode(kv.getValue))
181184
}
182185
} else {
183-
accumuloIterator.map { kv => decoder.decode(kv.getValue) }
186+
val features = accumuloIterator.map { kv => decoder.decode(kv.getValue) }
187+
if(query.getSortBy != null && query.getSortBy.length > 0) sort(features, query.getSortBy)
188+
else features
189+
}
190+
}
191+
192+
private def sort(features: CloseableIterator[SimpleFeature],
193+
sortBy: Array[SortBy]): CloseableIterator[SimpleFeature] = {
194+
val sortOrdering = sortBy.map {
195+
case SortBy.NATURAL_ORDER => Ordering.by[SimpleFeature, String](_.getID)
196+
case SortBy.REVERSE_ORDER => Ordering.by[SimpleFeature, String](_.getID).reverse
197+
case sb =>
198+
val prop = sb.getPropertyName.getPropertyName
199+
val ord = attributeToComparable(prop)
200+
if(sb.getSortOrder == SortOrder.DESCENDING) ord.reverse
201+
else ord
184202
}
203+
val comp: (SimpleFeature, SimpleFeature) => Boolean =
204+
if(sortOrdering.length == 1) {
205+
// optimized case for one ordering
206+
val ret = sortOrdering.head
207+
(l, r) => ret.compare(l, r) < 0
208+
} else {
209+
(l, r) => sortOrdering.map(_.compare(l, r)).find(_ != 0).getOrElse(0) < 0
210+
}
211+
CloseableIterator(features.toList.sortWith(comp).iterator)
185212
}
186213

214+
def attributeToComparable[T <: Comparable[T]](prop: String)(implicit ct: ClassTag[T]): Ordering[SimpleFeature] =
215+
Ordering.by[SimpleFeature, T](_.getAttribute(prop).asInstanceOf[T])
216+
187217
// This function calculates the SimpleFeatureType of the returned SFs.
188218
private def getReturnSFT(query: Query): SimpleFeatureType =
189219
query match {

0 commit comments

Comments
 (0)