Move iterating up to the cursor before any tests.

This commit is contained in:
Alex Roitman 2018-10-31 15:01:55 -07:00
parent f45d81d692
commit b94f3685b6
4 changed files with 62 additions and 25 deletions

View File

@ -497,14 +497,21 @@ func (c *Collection) geoSparseInner(
// Within returns all object that are fully contained within an object or
// bounding box. Set obj to nil in order to use the bounding box.
func (c *Collection) Within(
obj geojson.Object, sparse uint8,
obj geojson.Object,
offset uint64,
sparse uint8,
iter func(id string, obj geojson.Object, fields []float64) bool,
) bool {
var count uint64
if sparse > 0 {
return c.geoSparse(obj, sparse,
func(id string, o geojson.Object, fields []float64) (
match, ok bool,
) {
count++
if count <= offset {
return false, true
}
if match = o.Within(obj); match {
ok = iter(id, o, fields)
}
@ -514,6 +521,10 @@ func (c *Collection) Within(
}
return c.geoSearch(obj.Rect(),
func(id string, o geojson.Object, fields []float64) bool {
count++
if count <= offset {
return true
}
if o.Within(obj) {
return iter(id, o, fields)
}
@ -525,14 +536,21 @@ func (c *Collection) Within(
// Intersects returns all object that are intersect an object or bounding box.
// Set obj to nil in order to use the bounding box.
func (c *Collection) Intersects(
obj geojson.Object, sparse uint8,
obj geojson.Object,
offset uint64,
sparse uint8,
iter func(id string, obj geojson.Object, fields []float64) bool,
) bool {
var count uint64
if sparse > 0 {
return c.geoSparse(obj, sparse,
func(id string, o geojson.Object, fields []float64) (
match, ok bool,
) {
count++
if count <= offset {
return false, true
}
if match = o.Intersects(obj); match {
ok = iter(id, o, fields)
}
@ -542,6 +560,10 @@ func (c *Collection) Intersects(
}
return c.geoSearch(obj.Rect(),
func(id string, o geojson.Object, fields []float64) bool {
count++
if count <= offset {
return true
}
if o.Intersects(obj) {
return iter(id, o, fields)
}
@ -553,14 +575,20 @@ func (c *Collection) Intersects(
// Nearby returns the nearest neighbors
func (c *Collection) Nearby(
target geojson.Object,
offset uint64,
iter func(id string, obj geojson.Object, fields []float64) bool,
) bool {
alive := true
center := target.Center()
var count uint64
c.index.Nearby(
[]float64{center.X, center.Y},
[]float64{center.X, center.Y},
func(_, _ []float64, itemv interface{}) bool {
count++
if count <= offset {
return true
}
item := itemv.(*itemT)
alive = iter(item.id, item.obj, c.getFieldValues(item.id))
return alive

View File

@ -364,7 +364,7 @@ func fenceMatchRoam(
prevNearbys := fence.roam.nearbys[tid]
var newNearbys map[string]bool
col.Intersects(obj, 0, func(
col.Intersects(obj, 0, 0, func(
id string, obj2 geojson.Object, fields []float64,
) bool {
if c.hasExpired(fence.roam.key, id) {

View File

@ -68,6 +68,7 @@ type ScanWriterParams struct {
noLock bool
ignoreGlobMatch bool
clip geojson.Object
skipTesting bool
}
func (c *Server) newScanWriter(
@ -324,28 +325,38 @@ func (sw *scanWriter) globMatch(id string, o geojson.Object) (ok, keepGoing bool
return true, true
}
// ok is whether the object passes the test and should be written
// keepGoing is whether there could be more objects to test
func (sw *scanWriter) testObject(id string, o geojson.Object, fields []float64, ignoreGlobMatch bool) (
ok, keepGoing bool, fieldVals []float64) {
if !ignoreGlobMatch {
match, kg := sw.globMatch(id, o)
if !match {
return true, kg, fieldVals
}
}
nf, ok := sw.fieldMatch(fields, o)
return ok,true, nf
}
//id string, o geojson.Object, fields []float64, noLock bool
func (sw *scanWriter) writeObject(opts ScanWriterParams) bool {
if !opts.noLock {
sw.mu.Lock()
defer sw.mu.Unlock()
}
var fieldVals []float64
var ok bool
keepGoing := true
if !opts.ignoreGlobMatch {
var match bool
match, keepGoing = sw.globMatch(opts.id, opts.o)
if !match {
return true
if opts.skipTesting {
fieldVals = sw.fvals
} else {
ok, keepGoing, fieldVals = sw.testObject(opts.id, opts.o, opts.fields, opts.ignoreGlobMatch)
if !ok {
return keepGoing
}
}
nfields, ok := sw.fieldMatch(opts.fields, opts.o)
if !ok {
return true
}
sw.count++
if sw.count <= sw.cursor {
return true
}
if sw.output == outputCount {
return sw.count < sw.limit
}
@ -382,7 +393,7 @@ func (sw *scanWriter) writeObject(opts ScanWriterParams) bool {
} else if len(sw.farr) > 0 {
jsfields = `,"fields":[`
for i, field := range nfields {
for i, field := range fieldVals {
if i > 0 {
jsfields += ","
}

View File

@ -383,6 +383,7 @@ func (server *Server) cmdNearby(msg *Message) (res resp.Value, err error) {
distance: distance,
noLock: true,
ignoreGlobMatch: true,
skipTesting: true,
})
}
server.nearestNeighbors(&s, sw, s.obj.(*geojson.Circle), &matched, iter)
@ -406,18 +407,15 @@ func (server *Server) nearestNeighbors(
s *liveFenceSwitches, sw *scanWriter, target *geojson.Circle, matched *uint32,
iter func(id string, o geojson.Object, fields []float64, dist *float64,
) bool) {
limit := int(sw.cursor + sw.limit)
maxDist := target.Haversine()
limit := int(sw.limit)
var items []iterItem
sw.col.Nearby(target, func(id string, o geojson.Object, fields []float64) bool {
sw.col.Nearby(target, sw.cursor, func(id string, o geojson.Object, fields []float64) bool {
if server.hasExpired(s.key, id) {
return true
}
if _, ok := sw.fieldMatch(fields, o); !ok {
return true
}
match, keepGoing := sw.globMatch(id, o)
if !match {
ok, keepGoing, _ := sw.testObject(id, o, fields,true)
if !ok {
return true
}
dist := target.HaversineTo(o.Center())
@ -483,7 +481,7 @@ func (server *Server) cmdWithinOrIntersects(cmd string, msg *Message) (res resp.
sw.writeHead()
if sw.col != nil {
if cmd == "within" {
sw.col.Within(s.obj, s.sparse, func(
sw.col.Within(s.obj, s.cursor, s.sparse, func(
id string, o geojson.Object, fields []float64,
) bool {
if server.hasExpired(s.key, id) {
@ -497,7 +495,7 @@ func (server *Server) cmdWithinOrIntersects(cmd string, msg *Message) (res resp.
})
})
} else if cmd == "intersects" {
sw.col.Intersects(s.obj, s.sparse, func(
sw.col.Intersects(s.obj, s.cursor, s.sparse, func(
id string,
o geojson.Object,
fields []float64,