knn overscan ordering (#195)

This commit is contained in:
Josh Baker 2017-07-25 20:23:21 -07:00
parent 14cc6cedf7
commit 90f87bc3fb
2 changed files with 47 additions and 6 deletions

View File

@ -279,9 +279,8 @@ func (sw *scanWriter) writeObject(opts ScanWriterParams) bool {
return true return true
} }
if sw.output == outputCount { if sw.output == outputCount {
return true return sw.count < sw.limit
} }
switch sw.msg.OutputType { switch sw.msg.OutputType {
case server.JSON: case server.JSON:
var wr bytes.Buffer var wr bytes.Buffer

View File

@ -2,6 +2,7 @@ package controller
import ( import (
"bytes" "bytes"
"sort"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -304,14 +305,18 @@ func (c *Controller) cmdNearby(msg *server.Message) (res string, err error) {
} }
sw.writeHead() sw.writeHead()
if sw.col != nil { if sw.col != nil {
iter := func(id string, o geojson.Object, fields []float64) bool { iter := func(id string, o geojson.Object, fields []float64, dist *float64) bool {
if c.hasExpired(s.key, id) { if c.hasExpired(s.key, id) {
return true return true
} }
// Calculate distance if we need to // Calculate distance if we need to
distance := 0.0 distance := 0.0
if s.distance { if s.distance {
distance = o.CalculatedPoint().DistanceTo(geojson.Position{X: s.lon, Y: s.lat, Z: 0}) if dist != nil {
distance = *dist
} else {
distance = o.CalculatedPoint().DistanceTo(geojson.Position{X: s.lon, Y: s.lat, Z: 0})
}
} }
return sw.writeObject(ScanWriterParams{ return sw.writeObject(ScanWriterParams{
id: id, id: id,
@ -321,9 +326,13 @@ func (c *Controller) cmdNearby(msg *server.Message) (res string, err error) {
}) })
} }
if s.knn { if s.knn {
sw.col.NearestNeighbors(s.lat, s.lon, iter) nearestNeighbors(sw, s.lat, s.lon, iter)
} else { } else {
sw.col.Nearby(s.sparse, s.lat, s.lon, s.meters, minZ, maxZ, iter) sw.col.Nearby(s.sparse, s.lat, s.lon, s.meters, minZ, maxZ,
func(id string, o geojson.Object, fields []float64) bool {
return iter(id, o, fields, nil)
},
)
} }
} }
sw.writeFoot() sw.writeFoot()
@ -333,6 +342,39 @@ func (c *Controller) cmdNearby(msg *server.Message) (res string, err error) {
return string(wr.Bytes()), nil return string(wr.Bytes()), nil
} }
type iterItem struct {
id string
o geojson.Object
fields []float64
dist float64
}
func nearestNeighbors(sw *scanWriter, lat, lon float64, iter func(id string, o geojson.Object, fields []float64, dist *float64) bool) {
limit := sw.limit * 10
if limit > limitItems*10 {
limit = limitItems * 10
}
k := sw.cursor + limit
var items []iterItem
sw.col.NearestNeighbors(lat, lon, func(id string, o geojson.Object, fields []float64) bool {
if k == 0 {
return false
}
dist := o.CalculatedPoint().DistanceTo(geojson.Position{X: lon, Y: lat, Z: 0})
items = append(items, iterItem{id: id, o: o, fields: fields, dist: dist})
k--
return true
})
sort.Slice(items, func(i, j int) bool {
return items[i].dist < items[j].dist
})
for _, item := range items {
if !iter(item.id, item.o, item.fields, &item.dist) {
return
}
}
}
func (c *Controller) cmdWithin(msg *server.Message) (res string, err error) { func (c *Controller) cmdWithin(msg *server.Message) (res string, err error) {
return c.cmdWithinOrIntersects("within", msg) return c.cmdWithinOrIntersects("within", msg)
} }