How to use one Mysql query instead of query inside array loop? - php

The query below is currently within a loop(in PHP) that takes latitude, longitude, and id inputs from 3 different arrays. For each position/key in the array the nearest geographical place is selected from the table using the query below.
As the size of the array is typically around 500, so 500 sets of inputs, for which a nearest geographical position needs to be found it is taking some time.
My question: Is there any way to use one query using the input arrays from php at once, and selecting a set of all the nearest geographical positions for each array key?
$sql="SELECT
id, d, tolon, tolat, du,
( 3959 * acos( cos( radians($lat1) )
* cos( radians( travel.tolat ) )
* cos( radians( travel.tolon) - radians($lon1) )
+ sin( radians($lat1) )
* sin( radians( travel.tolat ) ) ) ) AS distance
FROM travel
WHERE userid = $id AND tolon > $lonlow AND tolon < $lonhigh AND tolat > $latlow AND tolat < $lathigh
having distance < $maxdistance ORDER BY distance
";

I don't think you'll do much better than a bunch of unions, although adding a limit 1 is a good idea if you only need the closest. A bunch of unions will be a very long sql string, and there's limits you may hit(max packet size is the setting, i believe). You would have to maybe chunk 100 or so unions at a time.
You stand to gain a lot if the table had indexes designed for this type of query. mysql has suport for spatial indexes that you should seriously consider looking into because regular indexes dont perform very well for this use case.

Related

near by location using lat long - google api - php

I have thousands of property in my store. I'm trying to write automated related properties. Each property has latitude and longitude. When customer click anyone property, we need to suggest five top most near by properties as related properties we have.
I'm working in php framework so I expect php related answer.
can anyone point me right direction?
SELECT id, ( 3959 * acos( cos( radians(37) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(-122) ) + sin( radians(37) ) * sin( radians( latitude ) ) ) ) AS distance FROM markers HAVING distance < 25 ORDER BY distance LIMIT 0 , 5;
Here's the SQL statement that will find the closest 20 locations that are within a radius of 25 miles to the 37, -122 coordinate. It calculates the distance based on the latitude/longitude of that row and the target latitude/longitude, and then asks for only rows where the distance value is less than 25, orders the whole query by distance, and limits it to 20 results. To search by kilometers instead of miles, replace 3959 with 6371.
for more details click here
As far as I know(I haven't been using google maps recently), google maps doesn't provide this type of solution.
I believe you're in need of a spacial database; if you're currently using an RDBMS check out the postgis extension for Postgresql:
http://postgis.net/
Here's a good list of references for using postgis and spacial data:
http://twiav-tt.blogspot.ca/2012/07/postgis-using-latitude-and-longitude-to.html
http://workshops.boundlessgeo.com/postgis-intro/spatial_relationships.html#st-distance-and-st-dwithin
http://revenant.ca/www/postgis/workshop/indexing.html
If you're using Mongo, there's also Mongogis:
https://github.com/mongogis
I've never worked with Mongogis so I don't have any good references.

MySQL find rows with lat/lng + radius within a search radius

does anyone know how to do a query which will allow a user to specify their lat / lng and a radius, and then search what could be a very large amount of locations which also have a lat lng + a radius and see if any overlap, and then allow for sorting by distance?
We've been asked to allow for companies to place markers on a map of suburbs that they operate in, with the ability to do a radius, but I can't find any queries on Google that do this.
I'm currently using the following query which does the job,
(SELECT ( 6371.01 * acos( cos( radians( $lat ) ) * cos( radians( location.lat ) )
cos( radians( location.lng ) - radians( $lng ) )
sin( radians( $lat ) ) * sin( radians( location.lat ) ) ) ) AS distance
FROM location
HAVING distance <= $radius
ORDER BY distance ASC) as distance
But obviously this doesn't allow for the locations to have a radius.
The second part of this question, this search query is already part of a very large query.. are there any recommendations on optimizing this at all? Every time I google'd for examples on queries like the above there was always people warning about how expensive this query is. At the moment the only solution I can think of is to have a separate search server.
Very simple answer: use the spacial geometry functions in mySQL (http://dev.mysql.com/doc/refman/5.5/en/spatial-extensions.html)
These have been around for a while, but got a nice upgrade in 5.6 that will make it easier to do your select. http://www.percona.com/blog/2013/10/21/using-the-new-spatial-functions-in-mysql-5-6-for-geo-enabled-applications/ has some details on it.
If you don't have 5.6 then use a "grid" system. Basically, when you store the point (x,y), you also store a grid identifier (X,Y) that covers a larger square. When searching other points nearby you know it's within grid (X-1 to X+1) and (Y-1 to Y+1); this reduces the number of points you need to search. Then check both the actual difference for x and y are within a square in mySQL, then, once you've reduced it massively, then do your cos/sin maths.

How to use GPS data like the double value returned by getLatitude()?

I have been searching quite a bit for an answer, but maybe I'm just not using the correct terminology. I am creating an app that will access a database to return a list of other users that are within a certain distance of the users location. I've never worked with this type of data, and I don't really know what the values mean. I'd like to do all the calculations on the backend with either MySQL or PHP. Currently, I am storing the latitude and longitude as doubles within the database. I can access them and store them, but I have no idea how I might be able to sort them based on distance. Perhaps I should be using a different type or some technique that is common in this area. TIA.
It sounds like you need to use the haversine formula which gets the distance between two sets of long/lat coordindates (adjusting for curvature of the earth).
If you run a query with that as an output, you can easily sort them based on minimum distance from the user.
Here is a link to implementing the haversine in 9 commonly used languages and here is a SO question which implements it inside a SQL query.
Here is the query that you could adapt (gets anything within 25 miles ordered from closest to furthest):
SELECT
id,
( 3959 * acos( cos( radians(37) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(-122) ) + sin( radians(37) ) * sin( radians( lat ) ) ) ) AS distance
FROM
markers
HAVING
distance < 25
ORDER BY
distance
LIMIT
0 , 20;
I would suggest using Vicenty's Inverse Formula (http://en.wikipedia.org/wiki/Vincenty's_formulae) instead of the Haversine Great Circle distance, since Vincenty's been shown to be more accurate (Vincenty assumes the earth is an oblate spheroid instead of a perfect sphere, which is more accurate).
Here's the original Vincenty paper for the formula:
http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf - Section 4
Here's the actual code from the Android platform that is used to calculate distance for distanceTo(Location), which uses Vincenty's Inverse Formula: https://github.com/android/platform_frameworks_base/blob/master/location/java/android/location/Location.java#L272
As to sorting distances based on a database query, for optimum performance you'll want to use a spatial database that allows spatial queries. MySQL has a spatial database plugin:
http://dev.mysql.com/doc/refman/5.0/en/spatial-extensions.html
Check out this post, which should give you the details to go from there, including notes on precision using Vicenty:
Geo-Search (Distance) in PHP/MySQL (Performance)

How to get places with a certain radius

I have a database of activities , each activities could be held on 3 days , each day contains a postal code .
So the database looks like that (+ alot of other fields)
In another database i have a Geo Location info (postal code , lat , long)
Now users can enter there postal code and a radius and activities in that radius will appear.
Question :
1 - What is the best way to accomplish that ?
Solution in mind
Make a view of all possible postal codes from the activities and join it on the Geo table to get their Lat/Lng
then when a user search for a postal code , get the Lat/Lng and do the mathematical equation to get all postal codes near that point .
But i don't think in term of performance this is a good way since i will have to apply the query on 3000+ activities
Codes found for distance
Finding locations nearby with MySQL (Haversine Formula)
SELECT id, ( 3959 * acos( cos( radians(37) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(-122) ) + sin( radians(37) ) * sin( radians( lat ) ) ) ) AS distance
FROM markers
HAVING distance < 25
ORDER BY distance LIMIT 0 , 20;
What do you guys think ?
You would need a GIS to do that (and use spatial index), but mysql is not capable of it - mysql GIS functionality can handle just rectangles. PostreSQL is capable of GIS.
Easiest would really be the math expression. It would be best if you could use some Projected coordinates (lat & lon are sphere coordinates). Convert whole database in this projected coordination system and than just use simple expression (without need to use trigonometric functions):
(activity_x - postal_code_x)^2 + (activity_y -
postal_code_y)^2 < distance^2
note that the Earth is a sphere, which means this will only work exactly for smaller distances (say < 1000 km). But anyway I think you don't need exact circle...
I was wrong in term of performance , the query took less than 0,5 second to calculate the distance on the 3000+ activities .

Find all Locations near to my gps Location

Actually i have millions of records of people in my server database and i want to fetch data of those people who are 5 miles near to me(i mean a circle with 5 miles radius )...
i am sending this data to an iPhone through webservice...
Please tell me how to do this on my PHP server....
Probably this can help you
Let for example you have input latitude and longitude 37 and -122 in degree. And you want to search for users within 25 miles from current given latitude and longitude.
SELECT item1, item2,
( 3959 * acos( cos( radians(37) )
* cos( radians( lat ) )
* cos( radians( lng )
- radians(-122) )
+ sin( radians(37) )
* sin( radians( lat ) )
)
) AS distance
FROM geocodeTable
HAVING distance < 25
ORDER BY distance LIMIT 0 , 20;
If you want search distance in kms. Then replace 3959 with 6371 in above query.
Get nearest places on Google Maps, using MySQL spatial data
With millions of people records in your server database (I hope you're adhering to data protection laws), then you'll need to reduce the workload of calculating all these distances; otherwise you need to do the calculation for every single one of those millions of records.
Use PHP to calculate a "bounding box", which can be used to select a subset of likely candidates from your millions of people records, then only calculate the distance for that subset of people records. See this article from the movable type website for example PHP code describing how to do this, and an excellent description of how the method actually works.

Categories