Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
0a0d12b
add: redis geospatial stages
UdeshyaDhungana Jul 14, 2025
e7f7f51
- Initial proposition for redis/geospatial challenge
UdeshyaDhungana Jul 16, 2025
314fced
Merge branch 'main' into redis-geospatial
UdeshyaDhungana Jul 17, 2025
ea695bb
- Apply requested changes
UdeshyaDhungana Jul 17, 2025
974c132
Remove merge conflict
UdeshyaDhungana Jul 17, 2025
98b4c6e
fix: update requested changes
UdeshyaDhungana Jul 28, 2025
fabccb8
fix: grammar
UdeshyaDhungana Jul 28, 2025
78d1c0f
fix: typos
UdeshyaDhungana Jul 28, 2025
e5ff7a8
fix: description
UdeshyaDhungana Jul 28, 2025
db308e3
fix: typo
UdeshyaDhungana Jul 28, 2025
f613c8f
fix: update tester description for ck3
UdeshyaDhungana Jul 28, 2025
eac6dc4
Fix: update instructions; fix grammar
UdeshyaDhungana Jul 28, 2025
7a6f6b0
Reorganize and reorder stages
UdeshyaDhungana Aug 1, 2025
bbf188f
- Restructured stages
UdeshyaDhungana Aug 4, 2025
f4af75c
fix: typos and add context
UdeshyaDhungana Aug 4, 2025
29e33a1
apply suggsted changes
UdeshyaDhungana Aug 8, 2025
9a6ec4c
Update geospatial stage description for the GEOADD command and its us…
rohitpaulk Aug 13, 2025
87c039a
Update geospatial stage to clarify latitude and longitude validation …
rohitpaulk Aug 13, 2025
43bd469
Update geospatial-01-zt4.md to remove reference to sorted set in GEOA…
rohitpaulk Aug 13, 2025
af148c6
Update geospatial stage descriptions with prerequisites and implement…
rohitpaulk Aug 13, 2025
bccffba
Refactor location scoring section and update algorithm description in…
rohitpaulk Aug 13, 2025
21b4c0c
Update geospatial stage description with clearer RESP string referenc…
rohitpaulk Aug 13, 2025
182e0d2
Refactor geospatial stage description for clarity and conciseness.
rohitpaulk Aug 13, 2025
ae84812
Fix typos and improve clarity in geospatial stage description for GEO…
rohitpaulk Aug 13, 2025
c1e00ac
Update geospatial stage description for GEOSEARCH command usage and e…
rohitpaulk Aug 13, 2025
fdda190
resolve merge conflicts
UdeshyaDhungana Aug 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 63 additions & 1 deletion course-definition.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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/


stages:
- slug: "jm1"
Expand Down Expand Up @@ -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"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work on the names, this is perfect! Only note is that "Validate Coordinates" doesn't need capitalization - just do "Validate coordinates".

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"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
name: "Measure distance"
name: "Calculate distance"

(Consistent with other stages)

difficulty: medium
marketing_md: In this stage, you'll add support for calculating the distance between two locations using the `GEODIST` comamnd.

- slug: "ra4"
primary_extension_slug: "geospatial"
name: "Unit conversion"
difficulty: easy
marketing_md: In this stage, you'll add support for different units of measure in the `GEODIST` command.

- slug: "rm9"
primary_extension_slug: "geospatial"
name: "Search within radius"
difficulty: hard
marketing_md: In this stage, you'll add support for searching locations near a coordinate within a given radius.

- slug: "hv8"
primary_extension_slug: "geospatial"
name: "Search within box"
difficulty: hard
marketing_md: In this stage, you'll add support for searching locations near a coordinate within a rectangular bounding box.

36 changes: 36 additions & 0 deletions stage_descriptions/geospatial-01-zt4.md
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not use the syntax view here - show the example usage first (i.e. the "show don't tell" technique) and then if needed, explain what the arguments are further. For most simple commands users will be able to infer what the values are if we just use appropriate names


```
GEOADD <key> <longitude> <latitude> <name>
```

Example usage:

```
> GEOADD places 13.361389 38.115556 "Palermo"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
> GEOADD places 13.361389 38.115556 "Palermo"
> GEOADD places 13.361389 38.115556 "London"

(Pick a place that people are more familiar with)

(integer) 1
```

It returns the count of elements added, encoded as a RESP Integer.

### Tests
The tester will execute your program like this:

```
./your_program.sh
```

It will then send a `GEOADD` command specifying a key, random values of latitude and longitude, and also a random name for that coordinate.

```
$ redis-cli GEOADD places 15.09 37.50 Catania
Copy link
Member

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

```

The tester will verify that the response to the command is `:1\r\n`, which is 1 (the number of locations added), encoded as a RESP Integer.

### Notes
- You will only implement adding one location per `GEOADD` command.
52 changes: 52 additions & 0 deletions stage_descriptions/geospatial-02-ck3.md
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:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If either of these values aren't within the appropriate range, GEOADD returns an error. Examples:

(We need to explain what we're showing examples of - just "example use case" doesn't fully explain what's happening)


```
# 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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.


For example, the tester might send your program a command like this:

```
$ redis-cli GEOADD location_key 200 100 foo

# Expecting error
(error) ERR invalid longitude,latitude pair 200,100
```

The value is RESP simple error, which is RESP-encoded as

```
-ERR invalid longitude,latitude pair 200,100\r\n
```

The tester will also send your program a `GEOADD` command specifying a non-numeric value in the latitude/longitude field. In this case, it will expect an error. For example, in case of the following command, it will expect an error.

```
$ redis-cli GEOADD location_key foo bar location_name

# Expecting RESP simple error
(error) ERR value is not a valid float
```

### Notes
- In case of out-of-bounds values of latitude or longitude, the tester is lenient in checking error messages so you don't have to stick to the exact format Redis uses. The exact format it checks for is `ERR invalid` (case-insensitive). Examples of error message strings that will pass the tests:
- `ERR invalid longitude,latitude pair 200,100`
- `ERR Invalid longitude,latitude`
- `ERR invalid`
80 changes: 80 additions & 0 deletions stage_descriptions/geospatial-03-xg4.md
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
# 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.
48 changes: 48 additions & 0 deletions stage_descriptions/geospatial-04-ia8.md
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
```
64 changes: 64 additions & 0 deletions stage_descriptions/geospatial-05-ek6.md
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"
```
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Distance values are inconsistent for the same city pair.

Lines 12-14 show Catania ↔ Rome as 537 215.1152 m while lines 36-38 expect 166.2742 (unit not stated).
Readers (and test-writers) will be confused and may implement wrong logic.

Action:

  1. Decide on the authoritative example (meters vs. kilometers) and keep a single value.
  2. Clarify the unit in the second snippet if you intend to demonstrate a later stage with unit conversion.

Also applies to: 35-38

🤖 Prompt for AI Agents
In stage_descriptions/geospatial-05-ek6.md around lines 11 to 14 and 35 to 38,
the distance values for the city pair Catania and Rome are inconsistent, showing
537215.1152 meters in one place and 166.2742 (unit unclear) in another. Decide
whether to use meters or kilometers as the standard unit for distance throughout
the document, update the values accordingly to be consistent, and explicitly
state the unit of measurement in all examples to avoid confusion.


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).

### 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**.

* 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.
Loading
Loading