I have a list of zipcoded in a MySQL Database together with their Latitude & Longitude data (Column names: ZipCode, Lat, Lon).
Now I have to make a search requests (search for the zipcode) to extract information from a website. When I make this search requests the results include all information within a radius of 50km of the zipcode.
Now, I don't want to make an unnessary high amount of search requests, so I would like to minimize the amount of zipcodes. So I'm looking for a way to filter all zipcodes, so that I have only the zipcodes where the distance between them is >50km.
Unfortunately I have no idea how to to it.
Can someone help me to solve this?
You may be interested in checking out the following presentation:
Geo/Spatial Search with MySQL by Alexander Rubin
The author describes how you can use the Haversine Formula in MySQL to limit your searches to a defined range. He also describes how to avoid a full table scan for such queries, using traditional indexes on the latitude and longitude columns.
You can use the google geocoding api , it allows you to get distances between 2 locations (lat/long, it also allows you to get zip from lat/long). From this you should be able to get the distance between each of your zipcodes and put them into a table, then you can do searches on just these.
Well, I see no other way then to iterate all rows on each request and filter them by calculating distance between selected zipcode and others (all of them), based on Lat & Lon.
I am using something similiar...
http://webarto.com/googlemaps
http://webarto.com/izrada-web-stranica/belgrade
PHP function for distance between two LL...
function distance($lat1, $lon1, $lat2, $lon2){
$theta = $lon1 - $lon2;
$dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
$dist = acos($dist);
$dist = rad2deg($dist);
$miles = $dist * 60 * 1.1515;
return round($miles * 1.609344,3);
}
I calculate it this way...
$sql = mysql_query("SELECT * FROM geoip WHERE city = '$city'");
while($row = mysql_fetch_array($sql)){
$ll = explode(",",$row["ll"]);
$x = distance(44.5428009033,18.6693992615,$ll[0],$ll[1]);
$road = intval($x+($x/3));
echo "Distance between ".$row["city"]." and Tuzla is ".$x." kilometers of airline, that's about ".$road." kilometers of road way.";
}
Daniel's link deals with selecting all the zip codes within 50km of a given latitude/longitude. Once you can do that, you can build a filtered list of zipcodes like this...
Select a zip code at random and add it to the filtered list
Delete all zip codes which lie within 50km of the selected zip code
Select a new zip code at random from the remaining zip codes, repeat until no more are left.
You know that you're only picking zip codes that are >50km from the ones already picked, and you know that once the original table is empty it must be because all zip codes lie within 50km of at least one of your selected zip codes.
That doesn't guarantee the smallest possible list of zip codes, and the size of the result will depend on the random choices. However, I think that this simple algorithm is likely to be "good enough", and that saving a few searches wouldn't justify the extra effort involved in finding a truly optimal solution.
The problem has been discussed previously here on SO with various solutions
I had a similar problem and I used this solution to find the answer. Not sure if you are using java or some other language but the logic can be used in any programming language
Geo Location API and finding user within a radius
Related
I'm trying to find all Panera restaurants within a 200 mile radius of a certain point.
Here is the URL I have been using so far :
https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=39.52963,-119.81380&radius=321869&type=restaurant&name=panera&key=your-key-here
However, I have found out that radius has a maximum of 30 miles. Can anyone suggest a quick workaround for me?
Thanks to all in advance.
Open Google Maps and save 8-10 or more points' lat,long value to trigger your request. Then use a loop to find all places within these points. If you want more precise results, increase first trigger points for your requests.
I tried, it works.
Assume we are using php
$triggerPoints = array("lat1,long1", "lat2,long2", "lat3,long3",....);
foreeach(triggerPoints as $t){
$requestUrl = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=$t&radius=[YOUR_RADIUS_VALUE]&type=restaurant&name=panera&key=your-key-here";
$results = file_get_contents($requestUrl);
//Do what you want with response JSON data
}
Important: When you choose trigger points, those points should intersect according to your radius value. So you don't miss any restaurants
Business license with for higher usage limits.
Contact Google sales
Google place nearby search maximum 50,000 meters (31 miles) .
if you try enter more than 50,000 it not work proper.
There is another way for find all restaurants in a city.
google provide Text Search Requests
https://maps.googleapis.com/maps/api/place/textsearch/json?query=restaurants+in+Reno,NV,89501,USA&key={API_KEY}
query = keyword + in + city Name
for get city name using latitude longitude
http://maps.googleapis.com/maps/api/geocode/json?latlng=39.52963,-119.81380&sensor=true
For more information how to get city name using latitude longitude
https://developers.google.com/maps/documentation/geocoding/start?csw=1#ReverseGeocoding
for more information about how to use Text Search Requests
https://developers.google.com/places/web-service/search
I have a database that I populate with specific locations of my choice. For each location, I will provide a longitude and latitude.
I want to get the geoIP (the longitude and latitude for a given IP matched in a database like maxmind.com) of a visitor to my website. Using the geoIP, I want to find the closest location to the visitor from my locations database table.
I've been spending a lot of time trying to figure out how to accomplish this in an efficient manner; I don't want the process to be expensive for every visitor. The process doesn't have to be precise, just precise enough. If it gives a user Sacramento instead of San Francisco, which would have been more correct, that's okay. Just as long as the degree of error is small enough that it wont bother a majority of users. What wouldn't be okay is if the algorithm gave a location completely off and irrelevant from where they are, say like Chicago (when they live in California).
So with that said, what are some solutions?
Here are some of my ideas:
1
Use the pythagorean theorem to find the distances between two points in a plane. The only problem is that the earth is not on a planar coordinate system, but rather a spherical one. So, I'll need a way to convert geolocation data (long. and lat.) into X and Y coordinates. Then I could run a SQL query that finds the record with the shortest distance which is calculated using: sqrt(abs(locationX - geoIpX)^2 + abs(locationY - geoIpY)^2)
I'm not sure if this is a plausible solution. If it is, then please smooth out the rough edges for me so I can implement it.
2
Figure out an algorithm that uses the differences in longitudes and latitudes. For example, first find the locations that has the closest longitude to the geoIP's longitude, then find the location out of that set that has the closest latitude to the geoIP's latitude. The only issue with the algorithm just described is that the margin of error can potentially be huge. For example, say a city in California is 3 degrees longitude away from the geoIP, but a city in Canada's longitude is 2 degrees away, what will happen is that this longitude line would be used to find the closest latitude, which may be only the city in Canada. Despite the fact that the latitude in Canada is many more degrees further than the latitude in the city in California, the user will be presented with data relevant to a Canadian instead of a Californian, which would be too much of an error. However, maybe there are some modifications to this algorithm that may fix this?
afterword
Thanks for reading. All solutions and help are highly appreciated! :)
You can use Haversine formula.
http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL
For optimizing search you can provide max , min coordinates
For max min coords youy can use a server side function to process or you can use stored proceduire to calculate those
Example for max min coords :
$minLng = $lng-($distance/(abs(cos(rad2deg($lat))*69)));
$maxLng = $lng+($distance/(abs(cos(rad2deg($lat))*69)));
$minLat = $lat-($distance/69);
$maxLat = $lat+($distance/69);
Mysql +php :
$select = "3956 * 2 * ASIN(SQRT(POWER(SIN((initial.pin_lat - " . $destination.lat . ") * pi()/180 / 2), 2) +COS(" .
"initial.pin_lat * pi()/180) * COS(" . $destination.lat . " * pi()/180) *POWER(SIN((" .
"initial.pin_lng - " . $destination.long . ") * pi()/180 / 2),2))) as distance_to_destination";
Then use this distance_to_destination in having clause
or use the select in where clause
to narrow down the search
$where = $destination.long." between "
. $minLng . " and " . $maxLng . " and ".$destination.lat." between " . $minLat . " and "
. $maxLat . " having distance < " . $prefered_distance
You want the Haversine formula. Since that calculation involves trigonometry functions, it tends to be kind of costly.
You might consider copying part of your data to a companion technology that supports built-in geolocation searches. MySQL isn't so good at this type of search, but some other tools are.
For example, Sphinx Search has support for geo distance searches:
http://sphinxsearch.com/blog/2013/07/02/geo-distances-with-sphinx/
MySQL does support spatial indexes, but only in MyISAM tables. There are many reasons to avoid using MyISAM tables.
mysql is as good as other databases. you can use the spatial index. I have written a php class solving spatial index with a monster curve. You can download my Hilbert curve package at phpclasses. it also uses mercantor projection and I'm using it very successful. other database have native support but you can do it in some hours yourself.
Suppose a service like Foursquare, I want to save the location of a check-in. Should I save this as latitude-longitude or the address/area name such as 123 Portmill St, NY 12345 or SoHo, NY.
In the first case, I can have users type an address and my service looks up and stores lat-long information. By doing this my service can search check-ins within a polygon-boundary.
While on the second case, I can store location as a bucket and avoid redundant information such as (lat,long) = (100000.1,100000.1), (100000.2,100000.2) which are very close together and can even be considered the same location.
I don't think I've completely understood the nuances of what you're trying to do, but computers usually work better with numbers like latitude and longitude rather than human-readable text information. For example, with the text address, how would you ensure consistency, e.g. dealing with extra spaces, ZIP+4 codes rather than just shorter zip codes etc etc.
I guess it's just my instinct that latitude and longitude might be better than text. Where I live in the UK, there are a lot of examples where towns and cities have two roads of the same name, so I do think that there are likely to be more pitfalls with storing text instead of latitude/longitude.
How about this. I'd store 3 columns in the database, namely (Latitude, Longitude, TextLocation), but it's the pair (Latitude, Longitude) that's regarded as the key of the table. The TextLocation is just the last known result from the reverse geocoder when the geocoder was asked for the text corresponding to the given (Latitude, Longitude).
When a new position arrives, (New_Latitude, New_Longitude), I'd search the database to find all closest rows in the database. To calculate distance of (New_Latitude, New_Longitude) to (Latitude, Longitude), I'd use the following code
float LatDiff = New_Latitude - Latitude;
float LongDiff = New_Longitude - Longitude;
float CosNewLat = Math.cos(New_Latitude);
float ConversionFac = 6371000 * Math.PI / 180; // 6371000 is earth radius in metres
float Dist_metres = ConversionFac * Math.sqrt(LatDiff*LatDiff + LongDiff*LongDiff*CosNewLat*CosNewLat);
Then for each of the closest points to (New_Latitude, New_Longitude), I'd update the TextLocation in the database using reverse geocoding. If the new position doesn't match the current reverse geocoding for any of the existing locations, I'd add it into the database.
Part of my thinking here is that even storing 3 columns which includes a column of text, the database is still going to be tiny compared to modern storage capacities.
I would like to query for all possible streetnames within a radius of 500 meters of a given point.
Multiple posts are reffering to the google store locator example using the Haversine formula or some version of it.
But I also came across some posts that have a much more simplified solution.
They just treat the points as x,y coordinates by adding to the lat and long variables as seen below.
I was wandering if this would be the fastest way to query mysql without getting really complicated and still get a good result. I don't have a lot of data yet, so I want to know if I am on the right track.
Are there any disadvantages or inaccuracy's by using this method?
What I don't get is how this can be a radius like range, it looks more like a one directional
query?
Distance = 0.1; // Range in degrees (0.1 degrees is close to 11km)
LatN = lat + Distance;
LatS = lat - Distance;
LonE = lon + Distance;
LonW = lon - Distance;
...Query DB with something like the following:
SELECT *
FROM table_name
WHERE
(store_lat BETWEEN LatN AND LatS) AND
(store_lon BETWEEN LonE AND LonW)
You might want to ask this question on the GIS site. I've used this answer myself for similar problems. I can see how your proposed solution might be faster, but note your four points are describing a square not a circle so it would not be considered a "radius".
You could use ElasticSearch for that, MySQL will be always slower than ES.
I'm attempting to create an app that will let the user know which 5 or so of our 1,000+ locations he is closest to. I've looked through the Places docs (since Places appears to provide similar functionality), but have not found exactly what I'm looking for, or if I have, I haven't recognized it as such.
I assume I'd have to pass the user's current location, along with a list of all of our installation locations, unless there's a way to have Google persist our installation locations which I could reference with each call.
If anyone can point me in the right direction I'd appreciate it.
Thanks.
If you are only interested in a crow flies type closest then you don't even need maps at all.
You just need the long lats of the position of the user and of the various offices and do a straight forward distance calculation between them.
$sql = "SELECT *,(((acos(sin((".$latitude."*pi()/180)) * sin((`Latitude`*pi()/180))+cos((".$latitude."*pi()/180)) * cos((`Latitude`*pi()/180)) * cos(((".$longitude."- `Longitude`)*pi()/180))))*180/pi())*60*1.1515) as distance FROM `MyTable` WHERE distance <= ".$distance.";//** Miles **//
That's a sql string to get all within a certain distance.
To get the five closest you would simply have an 'order by' and 'top 5'