Skip to content

Instantly share code, notes, and snippets.

@justincastilla
Last active November 4, 2021 15:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save justincastilla/df6c71fa0bbc665b3c1c11d4e380371e to your computer and use it in GitHub Desktop.
Save justincastilla/df6c71fa0bbc665b3c1c11d4e380371e to your computer and use it in GitHub Desktop.
RU101[LIVE] Week 4

RU101[LIVE] Week 4

Geospatial Indexing

Geospatial objects include coordinate pairs (latitude and longitude) and a name. The coordinates are transformed into a GEOHASH, which is a string combination of letters and numbers.

For Redis, we transform this hash into a 52-bit integer. We then store the name and 52-bit integer into a sorted Set, with the integer hash being the score and the name as the member.

We can still use all of the Sorted Set commands on a Geospatial Index, with a few exceptions covered later.

GEOADD

GEOADD lets us add one or more coordinate pairs with an associated member.

I maintain a Geospatial Index of all of my favorite cities I've visited for each state. Here I'll add Seattle to my Washington State Geospatial Index:

GEOADD location:washington:visited -122.3486205 47.6528443 Seattle

Note that I am adding the Longitude followed by the Latitude

GEOADD is variadic, so I can add multiple geospatial objects at once to the key location:washington:visited:

GEOADD location:washington:visited -123.1230992 47.4634248 Lilliwaup -124.5512108 47.9431287 Quillayute -123.0600437 47.5267583 "Hamma Hamma" -123.1694709 47.3297766 Skokomish -122.5510554 47.4281479 Olalla -122.9047634 47.6874041 Dosewallips -124.7240169 48.216681 "Shi-Shi Beach" -124.5849068 48.2902034 "Soooes Peak" -124.327493 48.2639607 Sekiu -121.1628973 45.8171467 Klikitat -120.5930853 46.973228 Kittitas -120.1344294 46.6835036 Selah -124.065365 46.2996001 "Cape Disappointment" -123.8617118 46.2489413 "Dismal Nitch" -122.6445519 48.40625 "Deception Pass" -122.8136242 48.5954102 "Obstruction Island" -122.4912808 48.663969 Chuckanut -123.7031496 48.0751097 "Snug Harbor" -123.8197942 47.9513964 "Sol Duc Falls" -124.3342942 47.5400944 Queets -118.3475557 46.0651317 "Walla Walla" -123.4644633 46.2806144 Skamokawah -121.8796366 46.1546342 Skamania -122.0085578 47.4994385 "Poo Poo Point"

GEOHASH

Lets verify the Geospatial data by running the GEOHASH command on one of the members. Lets make sure Walla Walla is still where I remember it:

GEOHASH location:washington:visited "Walla Walla"
1) "c25y4cvuy40"

Now we have the hash (c25y4cvuy40), rather than the 52-bit integer (1558811990489856*). Lets enter that hash into a site that converts geohash values into coordinates on a map:

https://www.movable-type.co.uk/scripts/geohash.html

  • to find the 52-bit integer value of the Geospatial member, find the score of the member in the Sorted Set

GEODIST

To find the distance between two of the members within our Geospatial index, lets use the GEODIST command. How far is Dosewallips from Deception Pass in miles?

GEODIST location:washington:visited "Deception Pass" Dosewallips mi
"51.1156"

GEOPOS

We can also check on the coordinates of a member we've already added by using the GEOPOS command. Where exactly is Obstruction Island, again?

GEOPOS location:washington:visited "Obstruction Island"
1) 1) "-122.81362205743789673"
   2) "48.5954091884852204"

GEORADIUS

We can use the GEORADIUS command to query what Geospatial Objects are near a specific set of coordinates within a given radius.

Lets say we want to know how many of my favorite cities are within 50 miles of Seattle (-122.3486205 47.6528443):

GEORADIUS location:washington:visited -122.3486205 47.6528443 50 mi
1) "Skokomish"
2) "Lilliwaup"
3) "Hamma Hamma"
4) "Olalla"
5) "Dosewallips"

Now lets run this command again with the optional WITHCOORD to get the coordinates of all of the locations:

GEORADIUS location:washington:visited -122.3486205 47.6528443 50 mi WITHCOORD
1) 1) "Skokomish"
  2) 1) "-123.16947072744369507"
     2) "47.32977728864641165"
2) 1) "Lilliwaup"
  2) 1) "-123.12310069799423218"
     2) "47.46342553121488095"
3) 1) "Hamma Hamma"
  2) 1) "-123.06004196405410767"
     2) "47.52675807410211917"
4) 1) "Olalla"
  2) 1) "-122.55105525255203247"
     2) "47.42814728211919828"
5) 1) "Dosewallips"
  2) 1) "-122.90476351976394653"
     2) "47.68740363173870378"
6) 1) "Seattle"
  2) 1) "-122.34861820936203003"
     2) "47.65284524345227624"
7) 1) "Poo Poo Point"
  2) 1) "-122.0085570216178894"
     2) "47.49943884944676142"

GEOSEARCH (6.2)

GEORADIUS is considered deprecated as of version 6.2 with the new command GEOSEARCH. Lets switch to GEOSEARCH instead.

Using version 6.2:

GEOSEARCH location:washington:visited FROMLONLAT -122.3486205 47.6528443 BYRADIUS 50 mi WITHCOORD
1) 1) "Skokomish"
   2) 1) "-123.16947072744369507"
      2) "47.32977728864641165"
2) 1) "Lilliwaup"
   2) 1) "-123.12310069799423218"
      2) "47.46342553121488095"
3) 1) "Hamma Hamma"
   2) 1) "-123.06004196405410767"
      2) "47.52675807410211917"
4) 1) "Olalla"
   2) 1) "-122.55105525255203247"
      2) "47.42814728211919828"
5) 1) "Dosewallips"
   2) 1) "-122.90476351976394653"
      2) "47.68740363173870378"
6) 1) "Seattle"
   2) 1) "-122.34861820936203003"
      2) "47.65284524345227624"
7) 1) "Poo Poo Point"
   2) 1) "-122.0085570216178894"
      2) "47.49943884944676142"

Whats the big difference? With this specific command, not much, but instead of using a radius (circle), we can now use a rectangular box around a given coordinate pair. Let's try to capture all of the attractions around Puget Sound, an area that encompasses roughly 25 miles wide and 150 miles tall. We'll use a starting coordinate pair from the center of the Puget Sound between Seattle and Kitsap County: (-122.454272,47.612980)

GEOSEARCH location:washington:visited FROMLONLAT -122.454272 47.612980 BYBOX 25 150 mi WITHDIST
1) 1) "Olalla"
   2) "13.5495"
2) 1) "Seattle"
   2) "5.6395"
3) 1) "Deception Pass"
   2) "55.5267"
4) 1) "Chuckanut"
   2) "72.6570"

Now we can refine our area of search to better shape regions, as opposed to an all-encompassing circle. If we were using GEORADIUS in the Bay Area, California, for example, we might get results from San Francisco, Marin County, and Oakland, when all we wanted were results specifically in San Francisco. GEOSEARCH allows us to "draw" our search boundaries.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment