diff --git a/Makefile b/Makefile index f127b13..8fc8846 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ GOTEST=$(GOCMD) test -count=1 GOGET=$(GOCMD) get GOMOD=$(GOCMD) mod GOFMT=$(GOCMD) fmt +GODOC=godoc .PHONY: all test coverage all: test coverage examples @@ -34,6 +35,7 @@ examples: get @echo "Building the examples..." $(GOBUILD) ./examples/redisearch_quickstart/. $(GOBUILD) ./examples/redisearch_auth/. + $(GOBUILD) ./examples/redisearch_geo/. $(GOBUILD) ./examples/redisearch_tls_client/. $(GOBUILD) ./examples/redisearch_temporary_index/. ./redisearch_tls_client --tls-cert-file $(TLS_CERT) \ @@ -53,3 +55,8 @@ test: get fmt coverage: get $(GOTEST) -race -coverprofile=coverage.txt -covermode=atomic ./redisearch +godoc: + $(GOGET) -u golang.org/x/tools/... + echo "Open browser tab on localhost:6060" + $(GODOC) + diff --git a/examples/redisearch_geo/redisearch_geo.go b/examples/redisearch_geo/redisearch_geo.go index 942fadd..92a5eb1 100644 --- a/examples/redisearch_geo/redisearch_geo.go +++ b/examples/redisearch_geo/redisearch_geo.go @@ -7,18 +7,18 @@ import ( ) /** + * This example maps to https://redis.io/commands/geoadd#examples of Georadius search * This demo should be updated in RediSearch.io if changed * Update at: https://github.com/RediSearch/RediSearch/blob/master/docs/go_client.md */ func main() { // Create a client. By default a client is schemaless // unless a schema is provided when creating the index - c := redisearch.NewClient("localhost:6379", "myIndex") + c := redisearch.NewClient("localhost:6379", "cityIndex") // Create a schema sc := redisearch.NewSchema(redisearch.DefaultOptions). - AddField(redisearch.NewTextField("body")). - AddField(redisearch.NewTextFieldOptions("title", redisearch.TextFieldOptions{Weight: 5.0, Sortable: true})). + AddField(redisearch.NewTextField("city")). AddField(redisearch.NewGeoField("location")) // Drop an existing index. If the index does not exist an error is returned @@ -29,31 +29,57 @@ func main() { log.Fatal(err) } - // Create a document with an id and given score - // Note While Specifying location you should specify in following order -> latitude and longitude - doc := redisearch.NewDocument("doc1", 1.0) - doc.Set("title", "Hello world"). - Set("body", "foo bar"). - Set("location", "23.147782245408465,80.0566448028139") + // Create the city docs + // Note While Specifying location you should specify in following order -> longitude,latitude + // Same look and feel as GEOADD https://redis.io/commands/geoadd + // This example maps to https://redis.io/commands/geoadd#examples + docPalermo := redisearch.NewDocument("doc:Palermo", 1.0) + docPalermo.Set("name", "Palermo"). + Set("location", "13.361389,38.115556") - // Index the document. The API accepts multiple documents at a time - if err := c.IndexOptions(redisearch.DefaultIndexingOptions, doc); err != nil { + docCatania := redisearch.NewDocument("doc:Catania", 1.0) + docCatania.Set("name", "Catania"). + Set("location", "15.087269,37.502669") + + // Index the documents. The API accepts multiple documents at a time + if err := c.IndexOptions(redisearch.DefaultIndexingOptions, docPalermo, docCatania); err != nil { log.Fatal(err) } - // Searching with limit and sorting - docs, total, err := c.Search(redisearch.NewQuery("*").AddFilter( + // Searching for 100KM radius should only output Catania + docs, _, _ := c.Search(redisearch.NewQuery("*").AddFilter( redisearch.Filter{ Field: "location", Options: redisearch.GeoFilterOptions{ - Lon: 23.147690778131295, - Lat: 80.0564903169592, + Lon: 15, + Lat: 37, Radius: 100, - Unit: redisearch.METERS, + Unit: redisearch.KILOMETERS, }, }, ).Limit(0, 2)) - fmt.Println(docs, total, err) - // Output: doc1 Hello world 1 + fmt.Println("100KM Radius search from longitude 15 latitude 37") + fmt.Println(docs[0]) + // Output: 100KM Radius search from longitude 15 latitude 37 + // Output: {doc:Catania 1 [] map[location:15.087269,37.502669 name:Catania]} + + // Searching for 200KM radius should output Catania and Palermo + docs, _, _ = c.Search(redisearch.NewQuery("*").AddFilter( + redisearch.Filter{ + Field: "location", + Options: redisearch.GeoFilterOptions{ + Lon: 15, + Lat: 37, + Radius: 200, + Unit: redisearch.KILOMETERS, + }, + }, + ).Limit(0, 2).SetSortBy("location", true)) + fmt.Println("200KM Radius search from longitude 15 latitude 37") + fmt.Println(docs[0]) + fmt.Println(docs[1]) + // Output: 100KM Radius search from longitude 15 latitude 37 + // Output: {doc:Palermo 1 [] map[location:13.361389,38.115556 name:Palermo]} + // Output: {doc:Catania 1 [] map[location:15.087269,37.502669 name:Catania]} } diff --git a/go.mod b/go.mod index e67971e..b789095 100644 --- a/go.mod +++ b/go.mod @@ -5,4 +5,10 @@ go 1.12 require ( github.com/gomodule/redigo v1.8.3 github.com/stretchr/testify v1.6.1 + github.com/yuin/goldmark v1.3.5 // indirect + golang.org/x/mod v0.4.2 // indirect + golang.org/x/net v0.0.0-20210421230115-4e50805a0758 // indirect + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect + golang.org/x/sys v0.0.0-20210421221651-33663a62ff08 // indirect + golang.org/x/tools v0.1.0 // indirect ) diff --git a/go.sum b/go.sum index 4c8c7e9..1316a01 100644 --- a/go.sum +++ b/go.sum @@ -4,12 +4,55 @@ github.com/gomodule/redigo v1.8.3 h1:HR0kYDX2RJZvAup8CsiJwxB4dTCSC0AaUq6S4SiLwUc github.com/gomodule/redigo v1.8.3/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5 h1:dPmz1Snjq0kmkz159iL7S6WzdahUTHnHB5M56WFVifs= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758 h1:aEpZnXcAmXkd6AvLb2OPt+EN1Zu/8Ne3pCqPjja5PXY= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210421221651-33663a62ff08 h1:qyN5bV+96OX8pL78eXDuz6YlDPzCYgdW74H5yE9BoSU= +golang.org/x/sys v0.0.0-20210421221651-33663a62ff08/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/redisearch/example_client_test.go b/redisearch/example_client_test.go index db9ea3c..733a691 100644 --- a/redisearch/example_client_test.go +++ b/redisearch/example_client_test.go @@ -290,6 +290,86 @@ func ExampleNewClientFromPool_ssl() { c.Drop() } +// The following example illustrates geospatial search using RediSearch. +// This examples maps to the Redis vanilla example showcased on https://redis.io/commands/georadius#examples. +// We'll start by adding two docs ( one for each city ) and then do a georadius search based on a starting point +// and 2 distinct radius: +// 1)- First query with 100KM radius centered at long,lat 15,37 that should only output the city named "Catania"; +// 2)- Second query with 200KM radius centered at long,lat 15,37 that should output the cities named "Palermo" and "Catania"; +func ExampleClient_Search() { + // Create a client. By default a client is schemaless + // unless a schema is provided when creating the index + c := redisearch.NewClient("localhost:6379", "cityIndex") + + // Create a schema + sc := redisearch.NewSchema(redisearch.DefaultOptions). + AddField(redisearch.NewTextField("city")). + AddField(redisearch.NewGeoField("location")) + + // Drop an existing index. If the index does not exist an error is returned + c.Drop() + + // Create the index with the given schema + if err := c.CreateIndex(sc); err != nil { + log.Fatal(err) + } + + // Create the city docs + // Note While Specifying location you should specify in following order -> longitude,latitude + // Same look and feel as GEOADD https://redis.io/commands/geoadd + // This example maps to https://redis.io/commands/geoadd#examples + docPalermo := redisearch.NewDocument("doc:Palermo", 1.0) + docPalermo.Set("name", "Palermo"). + Set("location", "13.361389,38.115556") + + docCatania := redisearch.NewDocument("doc:Catania", 1.0) + docCatania.Set("name", "Catania"). + Set("location", "15.087269,37.502669") + + // Index the documents. The API accepts multiple documents at a time + if err := c.IndexOptions(redisearch.DefaultIndexingOptions, docPalermo, docCatania); err != nil { + log.Fatal(err) + } + + // Searching for 100KM radius should only output Catania + docs, _, _ := c.Search(redisearch.NewQuery("*").AddFilter( + redisearch.Filter{ + Field: "location", + Options: redisearch.GeoFilterOptions{ + Lon: 15, + Lat: 37, + Radius: 100, + Unit: redisearch.KILOMETERS, + }, + }, + ).Limit(0, 2)) + + fmt.Println("100KM Radius search from longitude 15 latitude 37") + fmt.Println(docs[0]) + + // Searching for 200KM radius should output Catania and Palermo + docs, _, _ = c.Search(redisearch.NewQuery("*").AddFilter( + redisearch.Filter{ + Field: "location", + Options: redisearch.GeoFilterOptions{ + Lon: 15, + Lat: 37, + Radius: 200, + Unit: redisearch.KILOMETERS, + }, + }, + ).Limit(0, 2).SetSortBy("location", true)) + fmt.Println("200KM Radius search from longitude 15 latitude 37") + fmt.Println(docs[0]) + fmt.Println(docs[1]) + + // Output: 100KM Radius search from longitude 15 latitude 37 + // {doc:Catania 1 [] map[location:15.087269,37.502669 name:Catania]} + // 200KM Radius search from longitude 15 latitude 37 + // {doc:Palermo 1 [] map[location:13.361389,38.115556 name:Palermo]} + // {doc:Catania 1 [] map[location:15.087269,37.502669 name:Catania]} +} + func getConnectionDetails() (host string, password string) { value, exists := os.LookupEnv("REDISEARCH_TEST_HOST") host = "localhost:6379"