-
Notifications
You must be signed in to change notification settings - Fork 61
Add: Redis Geospatial Command Stages #328
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 7 commits
0a0d12b
e7f7f51
314fced
ea695bb
974c132
98b4c6e
fabccb8
78d1c0f
e5ff7a8
db308e3
f613c8f
eac6dc4
7a6f6b0
bbf188f
f4af75c
29e33a1
9a6ec4c
87c039a
43bd469
af148c6
bccffba
21b4c0c
182e0d2
ae84812
c1e00ac
fdda190
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -127,6 +127,18 @@ extensions: | |||||
[redis-pub-sub]: https://redis.io/docs/latest/develop/pubsub/ | ||||||
[subscribe-command]: https://redis.io/docs/latest/commands/subscribe/ | ||||||
[publish-command]: https://redis.io/docs/latest/commands/publish/ | ||||||
|
||||||
- slug: "geospatial" | ||||||
name: "Geospatial Commands" | ||||||
description_markdown: | | ||||||
In this challenge extension you'll add support for [Geospatial Commands][geospatial-commands] to your Redis implementation. | ||||||
|
||||||
Along the way, you'll learn commands like [GEOADD][geoadd-command], [GEOSEARCH][geosearch-command], and more. | ||||||
|
||||||
[geospatial-commands]: https://redis.io/docs/latest/develop/data-types/geospatial/ | ||||||
[geoadd-command]: https://redis.io/docs/latest/commands/geoadd/ | ||||||
[geosearch-command]: https://redis.io/docs/latest/commands/geosearch/ | ||||||
|
||||||
rohitpaulk marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
stages: | ||||||
- slug: "jm1" | ||||||
|
@@ -676,4 +688,54 @@ stages: | |||||
primary_extension_slug: "pub-sub" | ||||||
name: "Unsubscribe" | ||||||
difficulty: medium | ||||||
marketing_md: In this stage, you'll add support for the `UNSUBSCRIBE command`, which is used to unsubscribe from a channel. | ||||||
marketing_md: In this stage, you'll add support for the `UNSUBSCRIBE command`, which is used to unsubscribe from a channel. | ||||||
|
||||||
# Geospatial Commands | ||||||
- slug: "zt4" | ||||||
primary_extension_slug: "geospatial" | ||||||
name: "Add a location" | ||||||
|
||||||
difficulty: easy | ||||||
marketing_md: In this stage, you'll add support for adding a single location under a key using the `GEOADD` command. | ||||||
|
||||||
- slug: "ck3" | ||||||
primary_extension_slug: "geospatial" | ||||||
name: "Validate coordinates" | ||||||
difficulty: easy | ||||||
marketing_md: In this stage, you'll add support for validating the latitude and longitude provided in the `GEOADD` command. | ||||||
|
||||||
- slug: "xg4" | ||||||
primary_extension_slug: "geospatial" | ||||||
name: "Retrieve a location" | ||||||
difficulty: easy | ||||||
marketing_md: In this stage, you'll add support for retrieving the coordinates of a location using the `GEOPOS` command. | ||||||
|
||||||
- slug: "ia8" | ||||||
primary_extension_slug: "geospatial" | ||||||
name: "Retrieve multiple locations" | ||||||
difficulty: easy | ||||||
marketing_md: In this stage, you'll add support for retrieving multiple locations using a single `GEOPOS` command. | ||||||
|
||||||
- slug: "ek6" | ||||||
primary_extension_slug: "geospatial" | ||||||
name: "Measure distance" | ||||||
|
name: "Measure distance" | |
name: "Calculate distance" |
(Consistent with other stages)
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,36 @@ | ||||||
In this stage, you'll add support for adding a single location under a key using the `GEOADD` command. | ||||||
|
||||||
### The `GEOADD` command | ||||||
The `GEOADD` command adds a location (with longitude, latitude, and name) to a key. If the key doesn’t exist, it is created. If the key exists, the location is appended to that key. | ||||||
The syntax for `GEOADD` command is | ||||||
|
||||||
|
||||||
``` | ||||||
GEOADD <key> <longitude> <latitude> <name> | ||||||
``` | ||||||
|
||||||
Example usage: | ||||||
|
||||||
``` | ||||||
> GEOADD places 13.361389 38.115556 "Palermo" | ||||||
|
> GEOADD places 13.361389 38.115556 "Palermo" | |
> GEOADD places 13.361389 38.115556 "London" |
(Pick a place that people are more familiar with)
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add the tester's expectation
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,52 @@ | ||||||
In this stage, you'll add support for validating the latitude and longitude provided in the `GEOADD` command. | ||||||
|
||||||
### The `GEOADD` command (Validate coordinates) | ||||||
Latitudes and longitudes used in the `GEOADD` command should be in a certain range as per [EPSG:3857](https://epsg.io/3857). Valid longitudes are from -180 to 180 degrees. Valid latitudes are from -85.05112878 to 85.05112878 degrees. Both of these limits are inclusive. | ||||||
Example use case: | ||||||
|
||||||
|
||||||
``` | ||||||
# Invalid latitude | ||||||
> GEOADD places 180 90 test1 | ||||||
(error) ERR invalid longitude,latitude pair 180.000000,90.000000 | ||||||
|
||||||
# Invalid longitude | ||||||
> GEOADD places 181 0.3 test2 | ||||||
(error) ERR invalid longitude,latitude pair 181.000000,0.300000 | ||||||
``` | ||||||
|
||||||
### Tests | ||||||
The tester will execute your program like this: | ||||||
``` | ||||||
./your_program.sh | ||||||
``` | ||||||
It will then send multiple `GEOADD` commands specifying one or more location to add. For valid coordinates, the tester will expect the response to be the usual response of the `GEOADD` command. For invalid coordinates values, it will expect an error. | ||||||
|
It will then send multiple `GEOADD` commands specifying one or more location to add. For valid coordinates, the tester will expect the response to be the usual response of the `GEOADD` command. For invalid coordinates values, it will expect an error. | |
It will then send multiple `GEOADD` commands. If the coordinates supplied are valid, the tester will expect the response to be `:1\r\n`, the usual response of the `GEOADD` command. For invalid coordinates values, it will expect an error response. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
In this stage, you'll add support for retrieving the coordinates of a location using the `GEOPOS` command. | ||
|
||
### The `GEOPOS` command | ||
|
||
The `GEOPOS` command returns the longitude and latitude of the specified locations. Its syntax is | ||
|
||
``` | ||
GEOPOS <key> <location1> <location2> … | ||
``` | ||
|
||
Example usage: | ||
``` | ||
> GEOADD places 15.087269 37.502669 "Catania" | ||
> GEOADD places 12.496365 41.902783 "Rome" | ||
> GEOPOS places Catania Rome non_existent | ||
1) 1) "15.087267458438873" | ||
2) "37.50266842333162" | ||
2) 1) "12.496366202831268" | ||
2) "41.90278213378984" | ||
3) (nil) | ||
``` | ||
|
||
It returns an array with one entry for each location requested. | ||
|
||
- If the key does not exist, an empty array is returned `(*0\r\n)` | ||
- If a location exists under the key, its entry is an array of two items: | ||
- Longitude (Encoded as a Bulk string) | ||
- Latitude (Encoded as a Bulk string) | ||
- If a location doesn’t exist, the entry is a null bulk string `($-1\r\n)`. | ||
|
||
### Tests | ||
The tester will execute your program like this: | ||
``` | ||
./your_program.sh | ||
``` | ||
|
||
It will add multiple locations using the `GEOADD` command. | ||
|
||
``` | ||
$ redis-cli | ||
> GEOADD location_key 19.0872 33.5026 "Foo" | ||
> GEOADD location_key 49.125 72.991 "Bar" | ||
> GEOADD location_key 10.0872 34.5026 "Baz" | ||
> GEOADD location_key 41.125 73.991 "Caz" | ||
``` | ||
|
||
The tester will then send multiple `GEOPOS` commands, each specifying a single location that may or may not have been added. For example, the tester might send your program a command like this: | ||
|
||
``` | ||
> GEOPOS places Foo | ||
cursor[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
# Expecting [["19.0872", "33.5026"]] | ||
``` | ||
|
||
The value is a RESP array, which is encoded as | ||
``` | ||
*1\r\n | ||
*2\r\n | ||
$7\r\n | ||
19.0872\r\n | ||
$7\r\n | ||
33.5026\r\n | ||
``` | ||
|
||
### Notes | ||
|
||
- The tester will be lenient in checking the coordinates provided. The latitude and longitude returned by the server should match the values provided in the `GEOADD` command with a precision of up to 4 decimal places when rounded off. | ||
|
||
* For example, if a location was added using `GEOADD key 20.123456 30.123001`, any of the following will be accepted: | ||
|
||
* `20.1235 30.1230` | ||
* `20.123456 30.123000` | ||
* `20.123490 30.123045` | ||
* `20.123459 30.123001` | ||
* `20.1235001 30.122999` | ||
|
||
- If the location key does not exist, you should return an empty array. | ||
|
||
- In this stage, you will only implement retrieving a single location using the `GEOPOS` command. We'll get to retrieving multiple locations in a single `GEOPOS` command in the next stage. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
In this stage, you'll add support for retrieving multiple locations using a single `GEOPOS` command. | ||
|
||
### Tests | ||
The tester will execute your program like this: | ||
|
||
``` | ||
./your_program.sh | ||
``` | ||
|
||
It will add multiple locations using the `GEOADD` command. | ||
|
||
``` | ||
$ redis-cli | ||
> GEOADD location_key 19.08729 33.5026 "Foo" | ||
> GEOADD location_key 49.125 72.991 "Bar" | ||
> GEOADD location_key 10.0872 34.5026 "Baz" | ||
> GEOADD location_key 41.125 73.991 "Caz" | ||
``` | ||
|
||
The tester will then send multiple `GEOPOS` commands, each specifying multiple locations that may or may not have been added. For example, the tester might send your program a command like this: | ||
|
||
``` | ||
> GEOPOS location_key Foo Caz non_existent | ||
|
||
# Expecting RESP Array | ||
1) 1) "19.08729" | ||
2) "33.5026" | ||
2) 1) "41.125" | ||
2) "73.991" | ||
3) (nil) | ||
``` | ||
|
||
The value is a RESP array, which is encoded as | ||
|
||
``` | ||
*3\r\n | ||
*2\r\n | ||
$8\r\n | ||
19.08729\r\n | ||
$7\r\n | ||
33.5026\r\n | ||
*2\r\n | ||
$6\r\n | ||
41.125\r\n | ||
$6\r\n | ||
73.991\r\n | ||
$-1\r\n | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
In this stage, you'll add support for calculating the distance between two locations. | ||
|
||
### The `GEODIST` command | ||
The `GEODIST` command returns the distance between two members. The default unit of the distance which is returned, is meters. | ||
The syntax for `GEODIST` command is: | ||
``` | ||
GEODIST <key> <location1> <location2> | ||
``` | ||
Example usage: | ||
|
||
``` | ||
> GEODIST places Catania Rome | ||
"537215.1152" | ||
``` | ||
|
||
|
||
It returns the distance as a string, encoded as a RESP Bulk String. The precision of the response is up to 4 digits after the decimal. | ||
|
||
Redis uses the [Haversine's Formula](https://en.wikipedia.org/wiki/Haversine_formula#Example) to calculate the distance between two points. You can see how this is done in the Redis source code [here](https://github.com/redis/redis/blob/4322cebc1764d433b3fce3b3a108252648bf59e7/src/geohash_helper.c#L228C1-L228C72). | ||
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
### Tests | ||
The tester will execute your program like this: | ||
``` | ||
./your_program.sh | ||
``` | ||
|
||
It will add multiple locations using the `GEOADD` command. | ||
``` | ||
$ redis-cli | ||
> GEOADD places 15.087269 37.502669 "Catania" | ||
> GEOADD places 12.496365 41.902783 "Rome" | ||
``` | ||
|
||
The tester will then send multiple `GEODIST` commands specifying two locations. For example, the tester might send your program a command like this: | ||
|
||
``` | ||
> GEODIST places Catania Rome | ||
# Expecting "166.2742" | ||
``` | ||
|
||
The value is a RESP bulk string encoded as: | ||
|
||
``` | ||
$8\r\n | ||
166.2742\r\n | ||
``` | ||
|
||
### Notes | ||
- The tester will be lenient when validating the distance returned by the `GEODIST` command. The distance should match the actual distance between the provided locations with a precision of **up to 2 decimal places after rounding**. | ||
cursor[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
* This means that minor floating-point differences are acceptable as long as the values, when rounded to two decimal places, are the same. | ||
|
||
* For example, if the expected distance is `12345.67`, any of the following returned values will be accepted: | ||
|
||
* `12345.67001` | ||
* `12345.674` | ||
* `12345.6659` | ||
* `12345.6666` | ||
* `12345.669` | ||
|
||
* However, values like `12345.64`, `12345.70`, or `12345.61` would be considered incorrect. | ||
|
||
|
||
- If one or both of the location specified in the `GEODIST` command does not exist, it should return a null bulk string `($-1\r\n)`. | ||
- In this stage, you will only implement returning the distance in meters. We will get to using different units in the next stage. |
Uh oh!
There was an error while loading. Please reload this page.