README.md in geocoder-1.1.8 vs README.md in geocoder-1.1.9

- old
+ new

@@ -5,13 +5,13 @@ Compatibility ------------- -* Supports multiple Ruby versions: Ruby 1.8.7, 1.9.2, 1.9.3, and JRuby. +* Supports multiple Ruby versions: Ruby 1.8.7, 1.9.2, 1.9.3, 2.0.0, and JRuby. * Supports multiple databases: MySQL, PostgreSQL, SQLite, and MongoDB (1.7.0 and higher). -* Supports Rails 3.x. If you need to use it with Rails 2 please see the `rails2` branch (no longer maintained, limited feature set). +* Supports Rails 3 and 4. If you need to use it with Rails 2 please see the `rails2` branch (no longer maintained, limited feature set). * Works very well outside of Rails, you just need to install either the `json` (for MRI) or `json_pure` (for JRuby) gem. Installation ------------ @@ -96,13 +96,15 @@ If you have just added geocoding to an existing application with a lot of objects you can use this Rake task to geocode them all: rake geocode:all CLASS=YourModel -Geocoder will print warnings if you exceed the rate limit for your geocoding service. +Geocoder will print warnings if you exceed the rate limit for your geocoding service. Some services — Google notably — enforce a per-second limit in addition to a per-day limit. To avoid exceeding the per-second limit, you can add a `sleep` option to the rake task, like so: + rake geocode:all CLASS=YourModel sleep=0.25 + Request Geocoding by IP Address ------------------------------- Geocoder adds a `location` method to the standard `Rack::Request` object so you can easily look up the location of any HTTP request by IP address. For example, in a Rails controller or a Sinatra app: @@ -119,10 +121,12 @@ To find objects by location, use the following scopes: Venue.near('Omaha, NE, US', 20) # venues within 20 miles of Omaha Venue.near([40.71, 100.23], 20) # venues within 20 miles of a point + Venue.near([40.71, 100.23], 20, :units => :km) + # venues within 20 kilometres of a point Venue.geocoded # venues with coordinates Venue.not_geocoded # venues without coordinates With geocoded objects you can do things like this: @@ -219,15 +223,13 @@ distance = 20 center_point = [40.71, 100.23] box = Geocoder::Calculations.bounding_box(center_point, distance) Venue.within_bounding_box(box) -This can also dramatically improve query performance, especially when used in conjunction with indexes on the latitude/longitude columns. Note, however, that returned results do not include `distance` and `bearing` attributes. If you want to improve performance AND have access to distance and bearing info, use both scopes: +This can also dramatically improve query performance, especially when used in conjunction with indexes on the latitude/longitude columns. Note, however, that returned results do not include `distance` and `bearing` attributes. Note that `#near` performs both bounding box and radius queries for speed. - Venue.near(center_point, distance).within_bounding_box(box) - Advanced Geocoding ------------------ So far we have looked at shortcuts for assigning geocoding results to object attributes. However, if you need to do something fancy you can skip the auto-assignment by providing a block (takes the object to be geocoded and an array of `Geocoder::Result` objects) in which you handle the parsed geocoding result any way you like, for example: @@ -298,11 +300,11 @@ The following is a comparison of the supported geocoding APIs. The "Limitations" listed for each are a very brief and incomplete summary of some special limitations beyond basic data source attribution. Please read the official Terms of Service for a service before using it. #### Google (`:google`, `:google_premier`) * **API key**: required for Premier (do NOT use a key for the free version) -* **Key signup**: http://code.google.com/apis/maps/signup.html +* **Key signup**: https://developers.google.com/maps/documentation/business/ * **Quota**: 2,500 requests/day, 100,000 with Google Maps API Premier * **Region**: world * **SSL support**: yes * **Languages**: ar, eu, bg, bn, ca, cs, da, de, el, en, en-AU, en-GB, es, eu, fa, fi, fil, fr, gl, gu, hi, hr, hu, id, it, iw, ja, kn, ko, lt, lv, ml, mr, nl, no, pl, pt, pt-BR, pt-PT, ro, ru, sk, sl, sr, sv, tl, ta, te, th, tr, uk, vi, zh-CN, zh-TW (see http://spreadsheets.google.com/pub?key=p9pdwsai2hDMsLkXsoM05KQ&gid=1) * **Extra options**: `:bounds` - pass SW and NE coordinates as an array of two arrays to bias results towards a viewport @@ -344,11 +346,11 @@ * **Region**: world * **SSL support**: no * **Languages**: ? * **Documentation**: http://wiki.openstreetmap.org/wiki/Nominatim * **Terms of Service**: http://wiki.openstreetmap.org/wiki/Nominatim_usage_policy -* **Limitations**: Please limit request rate to 1 per second and include your contact information in User-Agent headers. Data licensed under CC-BY-SA (you must provide attribution). +* **Limitations**: Please limit request rate to 1 per second and include your contact information in User-Agent headers (eg: `Geocoder.configure(:http_headers => { "User-Agent" => "your contact info" })`). Data licensed under CC-BY-SA (you must provide attribution). #### Yandex (`:yandex`) * **API key**: none * **Quota**: 25000 requests / day @@ -368,23 +370,37 @@ * **Languages**: English * **Documentation**: ? * **Terms of Service**: http://geocoder.ca/?terms=1 * **Limitations**: "Under no circumstances can our data be re-distributed or re-sold by anyone to other parties without our written permission." +#### Geocoder.us (`:geocoder_us`) + +* **API key**: HTTP Basic Auth +* **Sign up**: http://geocoder.us/user/signup +* **Quota**: You can purchase 20,000 credits at a time for $50 +* **Region**: US +* **SSL support**: no +* **Languages**: English +* **Documentation**: http://geocoder.us/help/ +* **Terms of Service**: http://geocoder.us/terms.shtml +* **Limitations**: ? + #### Mapquest (`:mapquest`) -* **API key**: required for the licensed API, do not use for open tier +* **API key**: required +* **Key signup**: http://developer.mapquest.com/web/products/open * **Quota**: ? * **HTTP Headers**: in order to use the licensed API you can configure the http_headers to include a referer as so: `Geocoder.configure(:http_headers => { "Referer" => "http://foo.com" })` You can also allow a blank referer from the API management console via mapquest but it is potentially a security risk that someone else could use your API key from another domain. * **Region**: world * **SSL support**: no * **Languages**: English * **Documentation**: http://www.mapquestapi.com/geocoding/ * **Terms of Service**: http://info.mapquest.com/terms-of-use/ * **Limitations**: ? +* **Notes**: You can specify the licensed API by setting: `Geocoder.configure(:mapquest => {:licensed => true})` (defaults to free "open" version) #### Ovi/Nokia (`:ovi`) * **API key**: not required, but performance restricted without it * **Quota**: ? @@ -393,18 +409,44 @@ * **Languages**: English * **Documentation**: http://api.maps.ovi.com/devguide/overview.html * **Terms of Service**: http://www.developer.nokia.com/Develop/Maps/TC.html * **Limitations**: ? +#### ESRI (`:esri`) + +* **API key**: none +* **Quota**: Required for some scenarios (see Terms of Service) +* **Region**: world +* **SSL support**: yes +* **Languages**: English +* **Documentation**: http://resources.arcgis.com/en/help/arcgis-online-geocoding-rest-api/ +* **Terms of Service**: http://www.esri.com/software/arcgis/arcgisonline/services/geoservices +* **Limitations**: ? +* **Notes**: You can specify which projection you want to use by setting, for example: `Geocoder.configure(:esri => {:outSR => 102100})`. + +#### Data Science Toolkit (`:dstk`) + +Data Science Toolkit provides an API whose reponse format is like Google's but which can be set up as a privately hosted service. + +* **API key**: none +* **Quota**: None quota if you are self-hosting the service. +* **Region**: world +* **SSL support**: ? +* **Languages**: en +* **Documentation**: http://www.datasciencetoolkit.org/developerdocs +* **Terms of Service**: http://www.datasciencetoolkit.org/developerdocs#googlestylegeocoder +* **Limitations**: No reverse geocoding. +* **Notes**: If you are hosting your own DSTK server you will need to configure the host name, eg: `Geocoder.configure(:lookup => :dstk, :host => "localhost:4567")`. + #### FreeGeoIP (`:freegeoip`) * **API key**: none -* **Quota**: 1000 requests per hour. After reaching the hourly quota, all of your requests will result in HTTP 403 (Forbidden) until it clears up on the next roll over. +* **Quota**: 10000 requests per hour. After reaching the hourly quota, all of your requests will result in HTTP 403 (Forbidden) until it clears up on the next roll over. * **Region**: world * **SSL support**: no * **Languages**: English -* **Documentation**: http://github.com/fiorix/freegeoip/blob/master/README.rst +* **Documentation**: http://github.com/fiorix/freegeoip/blob/master/README.md * **Terms of Service**: ? * **Limitations**: ? #### MaxMind Web Services (`:maxmind`) @@ -416,36 +458,34 @@ * **Documentation**: http://www.maxmind.com/app/web_services * **Terms of Service**: ? * **Limitations**: ? * **Notes**: You must specify which MaxMind service you are using in your configuration. For example: `Geocoder.configure(:maxmind => {:service => :omni})`. -#### ESRI (`:esri`) +#### Baidu (`:baidu`) -* **API key**: none -* **Quota**: Required for some scenarios (see Terms of Service) -* **Region**: world -* **SSL support**: yes -* **Languages**: English -* **Documentation**: http://resources.arcgis.com/en/help/arcgis-online-geocoding-rest-api/ -* **Terms of Service**: http://www.esri.com/software/arcgis/arcgisonline/services/geoservices -* **Limitations**: ? -* **Notes**: You can specify which projection you want to use by setting, for example: `Geocoder.configure(:esri => {:outSR => 102100})`. +* **API key**: required +* **Quota**: No quota limits for geocoding +* **Region**: China +* **SSL support**: no +* **Languages**: Chinese (Simplified) +* **Documentation**: http://developer.baidu.com/map/webservice-geocoding.htm +* **Terms of Service**: http://developer.baidu.com/map/law.htm +* **Limitations**: Only good for non-commercial use. For commercial usage please check http://developer.baidu.com/map/question.htm#qa0013 +* **Notes**: To use Baidu set `Geocoder.configure(:lookup => :baidu, :api_key => "your_api_key")`. - Caching ------- It's a good idea, when relying on any external service, to cache retrieved data. When implemented correctly it improves your app's response time and stability. It's easy to cache geocoding results with Geocoder, just configure a cache store: Geocoder.configure(:cache => Redis.new) This example uses Redis, but the cache store can be any object that supports these methods: -* `store#[](key)` - retrieves a value -* `store#[]=(key, value)` - stores a value -* `store#keys` - lists all keys -* `store#del(url)` - deletes a value +* `store#[](key)` or `#get` or `#read` - retrieves a value +* `store#[]=(key, value)` or `#set` or `#write` - stores a value +* `store#del(url)` - deletes a value Even a plain Ruby hash will work, though it's not a great choice (cleared out when app is restarted, not shared between app instances, etc). You can also set a custom prefix to be used for cache keys: @@ -518,11 +558,11 @@ class Venue after_validation :reverse_geocode, :if => :has_coordinates after_validation :geocode, :if => :has_location, :unless => :has_coordinates - end + end Use Outside of Rails -------------------- You can use Geocoder outside of Rails by calling the `Geocoder.search` method: @@ -588,10 +628,17 @@ Country: United States Google map: http://maps.google.com/maps?q=29.952211,-90.080563 There are also a number of options for setting the geocoding API, key, and language, viewing the raw JSON reponse, and more. Please run `geocode -h` for details. +Numeric Data Types and Precision +-------------------------------- + +Geocoder works with any numeric data type (e.g. float, double, decimal) on which trig (and other mathematical) functions can be performed. + +A summary of the relationship between geographic precision and the number of decimal places in latitude and longitude degree values is available on [Wikipedia](http://en.wikipedia.org/wiki/Decimal_degrees#Accuracy). As an example: at the equator, latitude/longitude values with 4 decimal places give about 11 metres precision, whereas 5 decimal places gives roughly 1 metre precision. + Notes on MongoDB ---------------- ### The Near Method @@ -614,11 +661,11 @@ Notes on Non-Rails Frameworks ----------------------------- If you are using Geocoder with ActiveRecord and a framework other than Rails (like Sinatra or Padrino) you will need to add this in your model before calling Geocoder methods: - extend Geocoder::Model::ActiveRecord + extend Geocoder::Model::ActiveRecord Optimisation of Distance Queries -------------------------------- In MySQL and Postgres the finding of objects near a given point is speeded up by using a bounding box to limit the number of points over which a full distance calculation needs to be done. @@ -713,14 +760,37 @@ Known Issue ----------- -You cannot use the `near` scope with another scope that provides an `includes` option because the `SELECT` clause generated by `near` will overwrite it (or vice versa). Instead, try using `joins` and pass a `:select` option to the `near` scope to get the columns you want. For example: +You cannot use the `near` scope with another scope that provides an `includes` option because the `SELECT` clause generated by `near` will overwrite it (or vice versa). - # instead of City.near(...).includes(:venues) +Instead of using `includes` to reduce the number of database queries, try using `joins` with either the `:select` option or a call to `preload`. For example: + + # Pass a :select option to the near scope to get the columns you want. + # Instead of City.near(...).includes(:venues), try: City.near("Omaha, NE", 20, :select => "cities.*, venues.*").joins(:venues) + # This preload call will normally trigger two queries regardless of the + # number of results; one query on hotels, and one query on administrators. + # Instead of Hotel.near(...).includes(:administrator), try: + Hotel.near("London, UK", 50).joins(:administrator).preload(:administrator) + If anyone has a more elegant solution to this problem I am very interested in seeing it. + + +Contributing +------------ + +Contributions are welcome via pull requests on Github. Please respect the following guidelines: + +* Each pull request should implement ONE feature or bugfix. If you want to add or fix more than one thing, submit more than one pull request. +* Do not commit changes to files that are irrelevant to your feature or bugfix (eg: `.gitignore`). +* Do not add dependencies on other gems. +* Do not add unnecessary `require` statements which could cause LoadErrors on certain systems. +* Remember: Geocoder needs to run outside of Rails. Don't assume things like ActiveSupport are available. +* Do not add to base configuration options; instead document required lookup-specific options in the README. +* Be willing to accept criticism and work on improving your code; Geocoder is used by thousands of developers and care must be taken not to introduce bugs. +* Be aware that the pull request review process is not immediate, and is generally proportional to the size of the pull request. Copyright (c) 2009-12 Alex Reisner, released under the MIT license