Skip to content

Instantly share code, notes, and snippets.

@paulosuzart
Created November 29, 2012 23:08
Show Gist options
  • Save paulosuzart/4172548 to your computer and use it in GitHub Desktop.
Save paulosuzart/4172548 to your computer and use it in GitHub Desktop.
;; Autor: Paulo Suzart
;; This code reads a CSV file with a given format and then
;; talks to google to get its route name and generage a SQL output
;; just lein run it. No args to the main.
(ns geocoder.core
(import com.google.code.geocoder.Geocoder)
(import com.google.code.geocoder.GeocoderRequestBuilder)
(import com.google.code.geocoder.model.LatLng)
(import com.google.code.geocoder.model.GeocoderStatus)
(import com.google.code.geocoder.model.GeocoderResultType)
(:use [clojure-csv.core :only [parse-csv]]
[clojure.java.io :only [reader writer]]
[clojure.algo.monads :only [domonad maybe-m]]))
(defn build-req
"Builds google API request"
[address]
(println "REQ" (format "%s - %s, %s, brasil" (:locality address) (:zip address) (:uf address)))
(.getGeocoderRequest
(doto (new GeocoderRequestBuilder)
;(.setLocation (LatLng. lat lng))
(.setAddress (format "%s - %s, %s, brasil" (:locality address) (:zip address) (:uf address)))
(.setLanguage "pt_BR"))))
(defn goo-gcf
"Geocode function. Wraps .geocode"
[gc]
(fn [req] (.geocode gc req)))
(defn glat [result]
(.getLat (.getLocation (.getGeometry result))))
(defn glng [result]
(.getLng (.getLocation (.getGeometry result))))
(defn gen-sql
"Generate the appropriate UPDATE statement"
[result component i]
(println (glat result) (glng result))
(format "UPDATE STREET SET NAME = '%s', LAT = %g, LNG = %g WHERE ID = %s;\r\n"
(.getLongName component)
(glat result)
(glng result)
(:id i)))
(defn is-useful
"Checks if a given GeocodeResponde or AddresComponent are useful"
[t]
(some #{"route" "street_addres"} (.getTypes t)))
(defn gen-result
"Given a GeocodeResponse g and a processing item i, emits
the needed SQL (gen-sql) or information about the failure.
Failures are written as commented SQL statements
"
[[response i]]
(if (= "OK" (.value (.getStatus response)))
(or (domonad maybe-m
[results (.getResults response)
valid-result (first (filter is-useful results))
valid-component (first (filter is-useful (.getAddressComponents valid-result)))]
(gen-sql valid-result valid-component i))
(format "--Unable to find useful information for %s\r\n" (:id i)))
(format "--Unable to geocode %s due to %s\r\n" (:id i) (.value (.getStatus response)))))
(defn geocode
"Geocode function itsel. Builds a request and return back the
result and processin gitem tuple."
[gcf i]
(let [req (build-req i)
response (gcf req)]
(println (format
"Geocoding locality: %s, lat: %g, lng: %g"
(:locality i) (:lat i) (:lng i)))
[response i]))
(defn to-geodata
"Converts a CSV line to a map"
[[uf locality zip id n lat lng]]
{:uf uf
:locality locality
:zip zip
:id id
:name n
:lat (bigdec lat)
:lng (bigdec lng)})
(defn write-output
"Takes the seq of geocoded data and writes to a predefined file. updates.sql"
[o]
(with-open [w (writer "./updates.sql")]
(doseq [i o]
(println "Writing " i)
(.write w i))))
(defn -main
[& args]
(let [gc (new Geocoder)]
(->> (parse-csv (reader "./source.csv"))
(map #(to-geodata %))
(map #(geocode (goo-gcf gc) %))
(map #(gen-result %))
(write-output))))
(defproject geocoder "0.1.0-SNAPSHOT"
:description "gets the right street name"
:url "http://paulosuzart.github.com"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.4.0"]
[com.google.code.geocoder-java/geocoder-java "0.11"]
[clojure-csv/clojure-csv "2.0.0-alpha1"]
[org.clojure/algo.monads "0.1.0"]]
:main geocoder.core)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment