Notes on implementing location based search (part 1 of 2)
Introduction
We’re going to be adding location based searching to OC Food Review soon, so I figured I’ll explain how we do it before it comes out. It took me a good amount of Google searching and reading to get all the details ironed out, so hopefully this will save someone some time. It’s a fairly lengthy topic, so I’ll break it up into parts to make it more manageable. Two parts should do the trick. Today I’ll do a short overview, and talk about geocoding with Yahoo’s Map API. Tomorrow, I’ll talk about distance calculations and doing the actual search. Let’s get this party—err…part started.
Overview
Conceptually, location based searching is pretty straight-forward: find out where you are, find out how far you’re willing to travel, and compare your location against the locations of all your choices. If the distance between where you are and what you’re interested in is less than what you’re willing to travel, add it to your results list. Simple, right? Right. You probably already know one commonly accepted way of expressing your location is with a latitude and longitude coordinate. Normal people [1], however, prefer to represent locations using street addresses, not lat/long points. Luckily, geocoders swoop in to help convert street addresses to lat/long coordinates, saving us from DMS hell. If you do a Google search, you’ll find there are several geocoders available. Some free, some not. We’ll cover a pretty good free one: Yahoo!. After getting everything to lat/long, all you need to do is figure out how to calculate the distance between two lat/long points (covered in part 2), and you’re done!
Geocoding
For geocoding all the restaurant locations at OC Food Review we use the Yahoo! Maps Geocoding API. We like it because we can tell the API to return the data in our favorite server-side language, PHP. Well, that and when we wrote the core code for OC Food Review, Google’s Map API didn’t provide a geocoder. Before you can use Yahoo’s Map API, you’ll need to sign up for an application ID. Go get it now. Relax, it’s free and painless to get. Good, now that you’ve got that taken care of, we can start converting those addresses. All communication with the API is done through REST which may seem complicated, but isn’t really. I promise. To get an address geocoded, just browse to a URL like this:
http://api.local.yahoo.com/MapsService/V1/geocode?appid=[your yahoo app id]&location=[the address you want geocoded]
Yup, it’s that easy. You can see an example of it in action here. The API will return all the data you need as an XML string. But we wanted to make our lives even easier, so we asked the API to give us the output back as PHP by using the following URL:
http://api.local.yahoo.com/MapsService/V1/geocode?appid=[your yahoo app id]&location=[the address you want geocoded]&output=php
The result will be serialized PHP, so you’ll need to use the unserialize function in PHP to get the data in a useable form. After you do that, you’ll have an associative array with a structure similar to the following:
array(1) {
["ResultSet"]=> array(1) {
["Result"]=> array(8) {
["precision"]=> string(7) "address"
["Latitude"]=> string(9) "37.416384"
["Longitude"]=> string(10) "-122.024853"
["Address"]=> string(14) "701 FIRST AVE"
["City"]=> string(6) "SUNNYVALE"
["State"]=> string(2) "CA"
["Zip"]=> string(10) "94089-1019"
["Country"]=> string(2) "US"
}
}
}
Just pull out the data stored in the latitude and longitude indices of the array, and you’re good to go. Well, almost. There are a few hiccups you should watch out for. First, if an error occurs (say, you don’t supply an application ID), you’ll get an error message back in XML, not PHP, even though you specified you want your data returned as PHP. The error will be structured like this:
<Error>
The following errors were detected:
<Message>invalid value: appid</Message>
</Error>
So before you start traversing through the unserialized array, check to make sure it’s not an XML error message. Second, keep in mind that sometimes the exact location you specify can’t be found. In this case, the data will be returned as PHP, but with an extra index called "warning." You’ll want to check for that and handle it appropriately. Lastly, remember, the API returns an array—the "ResultSet" index may be an array of many "Results," so be sure to loop through all of them if you want all the data.
Possible download
If your host has PHP 5 installed with cURL enabled, you’re in luck, I’ve included the simple Geocoding class that we use on OC Food Review. Before you use it, you’ll need to open it up and replace the [your yahoo app id] part with your Yahoo! application ID. After that’s done, use it like this:
$geocoder = new Geocoder();try {
$data = $geocoder->geocode(’701 First Ave, Sunnyvale, CA 94089′);
}
catch (Exception $e) {
// Handle exception however you like.
}
The Geocoder class will take care of determining if the data was returned as XML (because of an error) and will extract and return just the error message. So, $data will contain either the unserialized array, or the error message.
Conclusion
That’s it for this part, if you have any questions send me an e-mail, or leave it in the comments. Check back tomorrow for the second part of the article which will cover calculating distances between two points using the Haversine algorithm (with yummy free PHP code), and putting it all together (you’ll even get a sneak peak at the OC Food Review location based search module!).
Related Reading
- Rasmus’ tutorial on using the Yahoo! Map API.
- About.com’s quick refresher about latitude and longitude.
Footnotes
- Back when I worked at Rand McNally/Thomas Guide, each employee would get a business card that, along with their basic contact information, included the company’s location in lat/long. Cute, but totally pointless.
About this entry
You’re currently reading “Notes on implementing location based search (part 1 of 2),” an entry on The OC Food Review Blog
- Published:
- 06.29.06 / 10am by Rahim
- Category:
- Under the hood
4 Comments
Jump to comment form | comments rss [?] | trackback uri [?]