X

Redis for .NET Developers – Redis GeoSpatial

Redis

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.

Ottawa Basketball Courts

C# code using Redis Geo Set Datatype

  class Program
    {
        static void Main(string[] args)
        {
             var redis = RedisStore.RedisCache;

            var list = new List();

            //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/
            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

  1. Intro to Redis for .NET Developers
  2. Redis for .NET Developer – Connecting with C#
  3. Redis for .NET Developer – String Datatype
  4. Redis for .NET Developer – String Datatype part 2
  5. Redis for .NET Developer – Hash Datatype
  6. Redis for .NET Developer – List Datatype
  7. Redis for .NET Developer – Redis Sets Datatype
  8. Redis for .NET Developer – Redis Sorted Sets Datatype
  9. Redis for .NET Developer – Redis Hyperloglog
  10. Redis for .NET Developer – Redis Pub Sub
  11. Redis for .NET Developers – Redis Pipeline Batching
  12. Redis for .NET Developers – Redis Transactions
  13. Redis for .NET Developers – Lua Scripting
  14. Redis for .NET Developers – Redis running in Docker
  15. Redis for .NET Developers – Redis running in Azure
  16. Redis for .NET Developers – Redis running in AWS ElastiCache
Categories: C# Redis
Taswar Bhatti:
Related Post