Redis GeoSpatial data sets are actually just SortedSets in Redis, there is no secret about it. Basically it provides an easy way to store geo spatial data like longitude/latitude coordinates into Redis.Lets look at some of the commands that Redis provides for Geo Spatial data.
Redis Geo Datatype – Operations
- GEOADD: Adds or updates one or more members to a Geo Set O(log (N)) where N is the number of elements in the sorted set.
- GEODIST: Return the distance between two members in the geo spatial index represented by the sorted set O(log(N)).
- GEOHASH: Gets valid Geohash strings representing the position of one or more elements from the Geo Sets O(log(N)), where N is the number of elements in the sorted set.
- GEOPOS: Return the longitude,latitude of all the specified members of the geo spatial sorted set at key O(log(N)), where N is the number of elements in the sorted set.
- GEORADIUS: Return the members of a sorted set populated with geo spatial information using GEOADD, which are within the borders of the area specified with the center location and the maximum distance from the center (the radius) O(N+log(M))
- GEORADIUSBYMEMBER: Same as GEORADIUS with the only difference that instead of taking, as the center of the area to query, it takes a longitude and latitude value O(N+log(M))
I wanted to use some open data to showcase the usage of Redis GeoSpatial data in Redis. I chose to use Basketball courts in Ottawa since my son plays a bit of basketball.
Here is a map of basketball courts in Ottawa.
C# code using Redis Geo Set Datatype
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
class Program { static void Main(string[] args) { var redis = RedisStore.RedisCache; var list = new List<GeoEntry>(); //BasetBallExtractor is just a class that calls Ottawa OpenData foreach (var item in BasketBallExtractor.Extract()) { var longtitue = Convert.ToDouble(item.Item1); var latitude = Convert.ToDouble(item.Item2); var name = item.Item3; list.Add(new GeoEntry(longtitue, latitude, name)); } var key = "locations"; //clear out the data redis.KeyDelete(key, CommandFlags.FireAndForget); //add all the geoentry redis.GeoAdd(key, list.ToArray()); //find the distance between parks var val = redis.GeoDistance(key, "Gesner Court Park", "Walter Baker Park", GeoUnit.Kilometers); Console.WriteLine($"Distance from Gesner Court to Walter Baker Park is {val} km"); //ouput - Distance from Gesner Court to Walter Baker Park is 0.4377 km val = redis.GeoDistance(key, "Brewer Park", "Walter Baker Park", GeoUnit.Kilometers); Console.WriteLine($"Distance from Brewer Park to Walter Baker Park is {val} km"); //output - Distance from Brewer Park to Walter Baker Park is 19.6528 km //get the position of Walter Baker Park var pos = redis.GeoPosition(key, "Walter Baker Park"); Console.WriteLine($"Walter Baker Park is located at: Lat {pos.Value.Latitude}, Long {pos.Value.Longitude} "); //Walter Baker Park is located at: Lat 45.2947688017077, Long - 75.902011692524 //assume we are at walter baker and the place is closed //we want to find out what is close by within 5 km for us to play basketball and find us the top 10 closes place var results = redis.GeoRadius(key, "Walter Baker Park", 5, GeoUnit.Kilometers, 10, Order.Ascending, GeoRadiusOptions.WithDistance); foreach (var geoRadiusResult in results) { Console.WriteLine($"- {geoRadiusResult.Member}, Distance: {geoRadiusResult.Distance}"); } /* * - Walter Baker Park, Distance: 0 * - Gesner Court Park, Distance: 0.4377 * - Stonegate Park, Distance: 0.9454 * - Fringewood Park and Community Centre, Distance: 1.8288 * - Clarence Maheral Park, Distance: 1.9128 * - Cattail Creek Park, Distance: 2.0176 * - Amberway Park, Distance: 2.4079 * - Ed Hollyer Park, Distance: 2.5855 * - Bryanston Gate Park, Distance: 2.7199 * - Jim Malone Park, Distance: 2.9452 */ //lets say we are a Ottawa Parliment Hill and want to play basketball where can we go var parliamentHillLatitude = 45.424807; var parliamentHillLongtitude = -75.699234; //find me all the locations nearby results = redis.GeoRadius(key, parliamentHillLongtitude, parliamentHillLatitude, 3, GeoUnit.Kilometers, -1, Order.Ascending, GeoRadiusOptions.WithCoordinates); foreach (var geoRadiusResult in results) { Console.WriteLine($"- {geoRadiusResult.Member}, Position {geoRadiusResult.Position}"); } /* * - Cathcart Park, Position -75.6929334998131 45.4346575277704 * - St. Luke's Park, Position -75.6867161393166 45.4152390289687 * - Bordeleau Park, Position -75.6928798556328 45.4373215197089 * - New Edinburgh Park, Position -75.6871077418327 45.4377904431234 * - Dalhousie Community Centre, Position -75.7093647122383 45.4104889615161 * - Sandy Hill Park and Community Centre, Position -75.6765183806419 45.4219332275505 * - Chaudière Park, Position -75.7137742638588 45.409835003457 * - Plouffe Park, Position -75.7150831818581 45.4074777127788 * - Dutchie's Hole Park, Position -75.6693086028099 45.4209015960387 * - Riverain Park, Position -75.6697806715965 45.4313877374749 * - Springhurst Park, Position -75.6728920340538 45.4127347244633 * - Sylvia Holden Park, Position -75.6818452477455 45.4029101452497 * - Lindenlea Park, Position -75.6763252615929 45.4449763776101 * - Ev Tremblay Park, Position -75.7115051150322 45.3998811534643 * - Laroche Park, Position -75.7291594147682 45.408689309493 */ //we can get back the hash of the geo location //The command returns 11 characters Geohash strings, so no precision is loss compared to the Redis internal 52 bit representation var hash = redis.GeoHash(key, "Walter Baker Park"); //we can now use http://geohash.org/<geohash-string> Console.WriteLine($"Walter Baker Park geo hash is {hash}"); //output Walter Baker Park geo hash is f2418v9v4u0 //this will also work http://geohash.org/f2418v9v4u0 Console.ReadKey(); } } |
So this covers the basic usage of Redish GeoSpatial Datatype, in the next blog post I will cover using Sentinel which provides high availability for Redis.
For the code please visit
https://github.com/taswar/RedisForNetDevelopers/tree/master/13.RedisGeo/RediusGeo
For previous Redis topics
- Intro to Redis for .NET Developers
- Redis for .NET Developer – Connecting with C#
- Redis for .NET Developer – String Datatype
- Redis for .NET Developer – String Datatype part 2
- Redis for .NET Developer – Hash Datatype
- Redis for .NET Developer – List Datatype
- Redis for .NET Developer – Redis Sets Datatype
- Redis for .NET Developer – Redis Sorted Sets Datatype
- Redis for .NET Developer – Redis Hyperloglog
- Redis for .NET Developer – Redis Pub Sub
- Redis for .NET Developers – Redis Pipeline Batching
- Redis for .NET Developers – Redis Transactions
- Redis for .NET Developers – Lua Scripting
- Redis for .NET Developers – Redis running in Docker
- Redis for .NET Developers – Redis running in Azure
- Redis for .NET Developers – Redis running in AWS ElastiCache
Leave A Comment