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

View File

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

View File

@ -68,6 +68,7 @@ type ScanWriterParams struct {
noLock bool noLock bool
ignoreGlobMatch bool ignoreGlobMatch bool
clip geojson.Object clip geojson.Object
skipTesting bool
} }
func (c *Server) newScanWriter( func (c *Server) newScanWriter(
@ -324,28 +325,38 @@ func (sw *scanWriter) globMatch(id string, o geojson.Object) (ok, keepGoing bool
return true, true 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 //id string, o geojson.Object, fields []float64, noLock bool
func (sw *scanWriter) writeObject(opts ScanWriterParams) bool { func (sw *scanWriter) writeObject(opts ScanWriterParams) bool {
if !opts.noLock { if !opts.noLock {
sw.mu.Lock() sw.mu.Lock()
defer sw.mu.Unlock() defer sw.mu.Unlock()
} }
var fieldVals []float64
var ok bool
keepGoing := true keepGoing := true
if !opts.ignoreGlobMatch { if opts.skipTesting {
var match bool fieldVals = sw.fvals
match, keepGoing = sw.globMatch(opts.id, opts.o) } else {
if !match { ok, keepGoing, fieldVals = sw.testObject(opts.id, opts.o, opts.fields, opts.ignoreGlobMatch)
return true if !ok {
return keepGoing
} }
} }
nfields, ok := sw.fieldMatch(opts.fields, opts.o)
if !ok {
return true
}
sw.count++ sw.count++
if sw.count <= sw.cursor {
return true
}
if sw.output == outputCount { if sw.output == outputCount {
return sw.count < sw.limit return sw.count < sw.limit
} }
@ -382,7 +393,7 @@ func (sw *scanWriter) writeObject(opts ScanWriterParams) bool {
} else if len(sw.farr) > 0 { } else if len(sw.farr) > 0 {
jsfields = `,"fields":[` jsfields = `,"fields":[`
for i, field := range nfields { for i, field := range fieldVals {
if i > 0 { if i > 0 {
jsfields += "," jsfields += ","
} }

View File

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