You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
MergeQueue is slow for some query range sets #2358
On a different subject, I think I have found an geotrellis issue/bug. I am trying to query a geotrellis layer (hadoop) with a multipolygon made up of about 1600 polys. It looks like MergeQueue isn't up to the task. The layer is indexed with Z3SpaceTimeKey and the query ends up with about 600K index ranges. MergeQueue ends up attempting to insert into the middle of an array 600K times. When it returns, it usually takes >10mins. Often it doesn't return. Perhaps having MergeQueue backed by an array isn't ideal as the query gets large. Any suggestions?
For what its worth, the problem seems to be fixed if the sequence of index ranges is presorted before going into the MergeQueue.
Offending line is here:
I've experienced similar slowdowns when including time large time ranges against our azavea-datahub Landsat8 2016 layer (used in the FOSS4G 2017 workshop).
As @lossyrob mentioned in Gitter, the appropriate fix is to sort by start value in the MergeQueue.apply method prior to inserting the index ranges. The fix will then get picked up by all the modules that use the MergeQueue. Pre-sorting should allow one to do the merging in a single pass through the array. I would also consider replacing the array that backs MergeQueue with something that at least provides constant time insertion/deletion. This should make the complexity O(nlogn) instead of what it is now - O(n^2) or perhaps worse.
Here is a candidate for a long-term fix. I get the same answer as the original for our big 1600+ polygon query. It needs some more rigorous testing and profiling though:
objectMergeQueue {
defapply(ranges: TraversableOnce[(Long, Long)]):Seq[(Long, Long)] = {
varmerged:List[(Long, Long)] =Nil
ranges.toSeq.sortBy(_._1).foreach(r => {
merged = merged match {
case a :: rest if (r._1 -1<= a._2) => (a._1, Math.max(a._2, r._2)) :: rest
case _ => r :: merged
}
})
merged.reverse
}
}
Presorting allows a single pass through the data and greatly simplifies the logic. Should be O(nlogn).
Issues:
Although the object is binary compatible, the underlying MergeQueue class is gone, which happens to be public, so I guess this is a breaking change.
Given that this causes a breaking change, I would then change the signature of the apply method to:
It looks like Z2 and Z3 internally use on the MergeQueue class directly, so will not benefit from the pre-sort. The presort still helps significantly in the RDDReader classes. For now I would suggest simply adding @lossyrob's suggested fix as implemented here:
Activity
metasim commentedon Sep 8, 2017
Do we need #2348 addressed first (or at least the tech stack decided on)?
Per @mteldridge's comments, changing the line above to
significantly improves performance in our use case.
mteldridge commentedon Sep 8, 2017
As @lossyrob mentioned in Gitter, the appropriate fix is to sort by start value in the MergeQueue.apply method prior to inserting the index ranges. The fix will then get picked up by all the modules that use the MergeQueue. Pre-sorting should allow one to do the merging in a single pass through the array. I would also consider replacing the array that backs MergeQueue with something that at least provides constant time insertion/deletion. This should make the complexity O(nlogn) instead of what it is now - O(n^2) or perhaps worse.
mteldridge commentedon Sep 8, 2017
Here is a candidate for a long-term fix. I get the same answer as the original for our big 1600+ polygon query. It needs some more rigorous testing and profiling though:
Presorting allows a single pass through the data and greatly simplifies the logic. Should be O(nlogn).
Issues:
applymethod to:which would allow me to call
sortBydirectly onrangesIf you don't want any breaking changes right now, I would suggest simply doing the presort in the current
MergeQueue.applymethod.mteldridge commentedon Sep 11, 2017
It looks like Z2 and Z3 internally use on the MergeQueue class directly, so will not benefit from the pre-sort. The presort still helps significantly in the RDDReader classes. For now I would suggest simply adding @lossyrob's suggested fix as implemented here:
mteldridge@dc7d737
In the long term, one could look into something like this that includes updates to Z2 and Z3.
mteldridge@51cf29f
mteldridge commentedon Sep 13, 2017
Also, here is a test that isolates the problem. The test will hang at the call to
MergeQueue.applyhttps://github.com/locationtech/geotrellis/compare/master...mteldridge:merge-queue-test?expand=1
echeipesh commentedon Oct 4, 2017
Resolved by #2400