diff --git a/Gopkg.lock b/Gopkg.lock index bf224bfa..84f75a23 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -227,7 +227,7 @@ [[projects]] branch = "master" - digest = "1:6fc1b77dedecd24d417a38c4ffc580c0c4de1540b60453efee44f1a41b205d27" + digest = "1:4be7626fb8f801eb85aa7494ce3a504c9b4121a07f4ec19d7d204185bd6397d5" name = "github.com/tidwall/geojson" packages = [ ".", @@ -235,7 +235,7 @@ "geometry", ] pruneopts = "" - revision = "581e33d25c96a70d4006cbeca5fcd716caad7766" + revision = "928ede3da18d831dea0af0bb26adeb025145c23b" [[projects]] digest = "1:3ddca2bd5496c6922a2a9e636530e178a43c2a534ea6634211acdc7d10222794" diff --git a/internal/controller/search.go b/internal/controller/search.go index 09016136..9e5d468c 100644 --- a/internal/controller/search.go +++ b/internal/controller/search.go @@ -24,7 +24,6 @@ type liveFenceSwitches struct { obj geojson.Object cmd string roam roamSwitches - knn bool groups map[string]string } @@ -119,19 +118,6 @@ func (c *Controller) cmdSearchArgs( err = errInvalidNumberOfArguments return } - umeters := true - if vs, smeters, ok = tokenval(vs); !ok || smeters == "" { - umeters = false - if cmd == "nearby" { - // possible that this is KNN search - s.knn = s.searchScanBaseTokens.ulimit && // must be true - !s.searchScanBaseTokens.usparse // must be false - } - if !s.knn { - err = errInvalidArgument(slat) - return - } - } var lat, lon, meters float64 if lat, err = strconv.ParseFloat(slat, 64); err != nil { err = errInvalidArgument(slat) @@ -141,7 +127,25 @@ func (c *Controller) cmdSearchArgs( err = errInvalidArgument(slon) return } - if umeters { + // radius is optional for nearby, but mandatory for others + if cmd == "nearby" { + if vs, smeters, ok = tokenval(vs); ok && smeters != "" { + if meters, err = strconv.ParseFloat(smeters, 64); err != nil { + err = errInvalidArgument(smeters) + return + } + if meters < 0 { + err = errInvalidArgument(smeters) + return + } + } else { + meters = -1 + } + } else { + if vs, smeters, ok = tokenval(vs); !ok || smeters == "" { + err = errInvalidNumberOfArguments + return + } if meters, err = strconv.ParseFloat(smeters, 64); err != nil { err = errInvalidArgument(smeters) return @@ -151,12 +155,7 @@ func (c *Controller) cmdSearchArgs( return } } - if s.knn { - s.obj = geojson.NewPoint(geometry.Point{X: lon, Y: lat}) - } else { - s.obj = geojson.NewCircle(geometry.Point{X: lon, Y: lat}, - meters, defaultCircleSteps) - } + s.obj = geojson.NewCircle(geometry.Point{X: lon, Y: lat}, meters, defaultCircleSteps) case "object": if s.clip { err = errInvalidArgument("cannnot clip with object") @@ -388,21 +387,10 @@ func (c *Controller) cmdNearby(msg *server.Message) (res resp.Value, err error) fields: fields, distance: distance, noLock: true, - ignoreGlobMatch: s.knn, - }) - } - if s.knn { - c.nearestNeighbors(&s, sw, s.obj, &matched, iter) - } else { - sw.col.Intersects(s.obj, s.sparse, func( - id string, o geojson.Object, fields []float64, - ) bool { - if c.hasExpired(s.key, id) { - return true - } - return iter(id, o, fields, nil) + ignoreGlobMatch: true, }) } + c.nearestNeighbors(&s, sw, s.obj.(*geojson.Circle), &matched, iter) } sw.writeFoot() if msg.OutputType == server.JSON { @@ -420,7 +408,7 @@ type iterItem struct { } func (c *Controller) nearestNeighbors( - s *liveFenceSwitches, sw *scanWriter, target geojson.Object, matched *uint32, + 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) @@ -437,6 +425,9 @@ func (c *Controller) nearestNeighbors( return true } dist := o.Distance(target) + if target.Meters() > 0 && dist > target.Meters() { + return false + } items = append(items, iterItem{id: id, o: o, fields: fields, dist: dist}) if !keepGoing { return false diff --git a/tests/keys_search_test.go b/tests/keys_search_test.go index 88480615..ba532adb 100644 --- a/tests/keys_search_test.go +++ b/tests/keys_search_test.go @@ -1,6 +1,8 @@ package tests -import "testing" +import ( + "testing" +) func subTestSearch(t *testing.T, mc *mockServer) { runStep(t, mc, "KNN", keys_KNN_test) @@ -17,16 +19,10 @@ func keys_KNN_test(mc *mockServer) error { {"SET", "mykey", "3", "POINT", 12, 19}, {"OK"}, {"SET", "mykey", "4", "POINT", -5, 5}, {"OK"}, {"SET", "mykey", "5", "POINT", 33, 21}, {"OK"}, - {"NEARBY", "mykey", "LIMIT", 10, "DISTANCE", "POINTS", "POINT", 20, 20}, { - "" + - "[0 [" + - ("" + - "[2 [19 19] 152808.67164036975] " + - "[3 [12 19] 895945.1409106685] " + - "[5 [33 21] 1448929.5916252395] " + - "[1 [5 5] 2327116.1069888202] " + - "[4 [-5 5] 3227402.6159841116]") + - "]]"}, + {"NEARBY", "mykey", "LIMIT", 10, "POINTS", "POINT", 20, 20}, { + "[0 [[2 [19 19]] [3 [12 19]] [5 [33 21]] [1 [5 5]] [4 [-5 5]]]]"}, + {"NEARBY", "mykey", "LIMIT", 10, "IDS", "POINT", 20, 20, 4000000}, {"[0 [2 3 5 1 4]]"}, + {"NEARBY", "mykey", "LIMIT", 10, "IDS", "POINT", 20, 20, 1500000}, {"[0 [2 3 5]]"}, }) } diff --git a/vendor/github.com/tidwall/geojson/circle.go b/vendor/github.com/tidwall/geojson/circle.go index 8f528351..12de3dc6 100644 --- a/vendor/github.com/tidwall/geojson/circle.go +++ b/vendor/github.com/tidwall/geojson/circle.go @@ -70,3 +70,11 @@ func (g *Circle) JSON() string { func (g *Circle) String() string { return string(g.AppendJSON(nil)) } + +func (g *Circle) Meters() float64 { + return g.meters +} + +func (g *Circle) Center() geometry.Point { + return g.center +}