zenly - reverse geocoding

20
An architecture to handle reverse geocoding [email protected]

Upload: cocoaheads-france

Post on 06-Jan-2017

4.404 views

Category:

Software


0 download

TRANSCRIPT

Page 1: Zenly - Reverse geocoding

An architecture to handle reverse [email protected]

Page 2: Zenly - Reverse geocoding

Zenly is a location app that lets you know what friends and family are

up to in real-time.

The app is focused on location, and therefore relies a lot on adresses.

Our users do millions of reverse geocoding's everyday and it has to

work :)

Page 3: Zenly - Reverse geocoding

The operation to transform a latitude/longitude into an address.

Handled by CoreLocation : ReverseGeocoder one simple API.

public typealias CLGeocodeCompletionHandler = ([CLPlacemark]?, NSError?) -> Void

// reverse geocode requests public func reverseGeocodeLocation(location: CLLocation, completionHandler: CLGeocodeCompletionHandler)

May return multiple placemarks.

Reverse geocoding

Page 4: Zenly - Reverse geocoding

In practice

Take one, use it, forget it….

Usually data comes from two providers NAVTEQ and TELEATLAS.

Other APIs available : Google (do not mix and match), open data…

Simply search for “Free reverse geocoding”.

CoreLocation hides everything.

Page 5: Zenly - Reverse geocoding

When problems start

Some applications may want to display multiple adresses for multiple people, possibly moving … … and we bump into a limit.

Apple writes: “avoid more than one per minute and do it when UI needs it”. Problem of count and rate.

Empirically it can handle one every few seconds.

If too many: longer answer time and then errors.

“Boss, we need to pay Google”

Page 6: Zenly - Reverse geocoding

Architecture leading to a problem

Being purely model driven leads to problems.

User AddressReverse Geocode

Location Change

UI

User AddressReverse Geocode

Location Change

User AddressReverse Geocode

Location Change

Page 7: Zenly - Reverse geocoding

Thinking bias

Get UI components ready ASAP to avoid spinning wheel.

Optimize in a time based manner.

Optimize in the context of one user only.

Page 8: Zenly - Reverse geocoding

Improvements

Global.

Cache.

Scheduling.

Priority and UI driven.

Track identifier.

Do only what is necessary!

Page 9: Zenly - Reverse geocoding

Global operation

Avoid to use “reverse geocoding on the go”.

One available through a unique object (Singleton).

Handle both time based and position based consideration and optimization.

Make sure an operation can be redistributed through multiple places.

Only one object is responsible.

Page 10: Zenly - Reverse geocoding

Data structure

func reverseGeocode<T:ReverseGeocodable>(geocodableObject:T?, identifier:String?, priority:ReverseGeocodingPriority, completionHandler: CLGeocodeCompletionHandler?) -> ReverseGeocodeResult

struct GeopositioningRunningInfo:CustomStringConvertible { var priority:ReverseGeocodingPriority = ReverseGeocodingPriority.Normal var context:Any? = nil var handlers:[Any] = [] var identifier:String? }

Page 11: Zenly - Reverse geocoding

Cache

Based on coordinates….but how to encode this ?

Geohash: a division of the planet and many nice things (neighbors…). See Wikipedia !.

Must have a resolution: level. May depend on where you are!

Implementation through an NSCache where key is geohash and value the originally received CLPlacemarks.

Scheduled operations should be considered: multiple handlers.

Multiple people in the same place.

Page 12: Zenly - Reverse geocoding

Geohash samples

//Paris: Zenly office var aPos:Pos = Pos(latitude:48.868117, longitude:2.355915) var geoHash:String = (ServiceReverseGeocoder.sharedGeocoder.geoHashString(aPos, level: 8))! XCTAssert(geoHash == "u09wj85t") geoHash = (ServiceReverseGeocoder.sharedGeocoder.geoHashString(aPos, level: 3))! XCTAssert(geoHash == "u09") geoHash = (ServiceReverseGeocoder.sharedGeocoder.geoHashString(aPos, level: 1))! XCTAssert(geoHash == "u")

Downscaled information in no network.

Page 13: Zenly - Reverse geocoding

Scheduling

Avoid flooding the Apple Reverse Geocoder.

Schedule operation on a heartbeat (timer).

Do nothing in the background.

Stop when all is done.

If error: next operation can be progressively delayed.

Don’t trap yourself!

Page 14: Zenly - Reverse geocoding

Scheduling Principle

func reverseGeocode<T:ReverseGeocodable>(geocodableObject:T?, identifier:String?, priority:ReverseGeocodingPriority, completionHandler: CLGeocodeCompletionHandler?) -> ReverseGeocodeResult

{ var result = ReverseGeocodeResult.DefaultLaunch

//Do pre check //Keep where we are in order to start heartbeat if necessary let countBefore:Int = self.reverseGeocodingCount()

//More stuff

//Start heartbeat if needed let countAfter:Int = self.reverseGeocodingCount() if 0 == countBefore && countAfter > 0 { self.heartbeat = Foundation.NSTimer.scheduledTimerWithTimeInterval(self.GeocodingServiceHeartbeatValue,

target: self, selector:#selector(_doExecuteHeartBeat(_:)) , userInfo: nil, repeats: true) self.heartbeat?.tolerance = self.GeocodingServiceHeartbeatTolerance } return result }

Page 15: Zenly - Reverse geocoding

Priority

Arbitrary number: 3 sounds good for normal usage.

Very simple FIFO model : 3 FIFOs as queues.

Heartbeat is unstacking the queues.

Operations can be moved between queues.

Should be settable on a more permanent basis: use cautiously!

Priorities are to be used!!!!

Page 16: Zenly - Reverse geocoding

Priority queues

HighMedium

u09wj85t

u09wj86d

ke7fynh8

6gyqdy5u

6gyqdy5v

drt2xp2mu09wj84f

Normal

Heart beat

Page 17: Zenly - Reverse geocoding

UI driven

Medium High Medium

Page 18: Zenly - Reverse geocoding

Track identifier

Follow someone moving

T1

T2

T3

T4T5

T6

Page 19: Zenly - Reverse geocoding

Implementation details

Follow someone moving.

Identifier can be a user UUID but we can think of other cases (e.g UI).

We do not want to encode position of the past.

An operation with an identifier replaces the previous one.

Should handle both identifier and priority.

One more improvement: still keep a delivery ratio.

Page 20: Zenly - Reverse geocoding

Thank You!https://zen.ly/join