This question is different from regular mysql lat/long, radius based data fetching
I want to search a mysql database table which contains following columns for example-
ID Items lat long serving_radius(in km)
1 Item1 26.120888 85.364723 2
2 Item2 26.120888 85.364723 5
3 Item3 25.859800 85.786598 4
4 Item4 26.594900 85.504799 8
Now if a user has lat/long (29.941095/77.812424) wants to know which of these items can be served at his location. Then how i will fetch the result using php & mysql.
I guess the SQL you are looking for is this one:
SELECT id, items, lat, long, serving_radius
FROM table
WHERE lat = 29.941095
AND long = 77.812424;
In your PHP code, you should use a DB driver (I recommend you PDO) in order to connect to the DB and execute the query.
There are plenty of tutorials about how to using PDO (creating the connection, selecting, inserting, etc).
I just found this tutorial which could help you: https://parzibyte.me/blog/en/2019/10/14/php-mysql-tutorial-using-pdo/
Edit: Not sure if you mean about how to build a query with those exact lat and long values or closer to them.
If so, you can take a look at https://gis.stackexchange.com/questions/31628/find-points-within-a-distance-using-mysql
Is "serving_radius" already stored in your table ?
What you can do is fetch distance and check if its under serving_radius
SELECT serving_radius,
(6371 * acos(cos(radians(" . $userLatitude . ")) * cos(radians(`latitude`)) * cos(radians(`longitude`) - radians(" . $userLongitude . ")) + sin(radians(" . $userLatitude . ")) * sin(radians(`latitude`)))) as distance
having distance < serving_radius
This question seems to be similar to MySQL - Find points within radius from database
Find the radius from your serving_radius and lat/lon at the database.
use the function MBRContains to find the polygon that contains the user's point.
SELECT
*
FROM
items
WHERE
MBRContains(
GeomFromText('Polygon((0 0,0 100,100 100,100 0,0 0))'),
GeomFromText('Point(77.812424 29.941095)')) = 1;
hope it helps
I think your problem is tougher than the traditional problem due to the radius being variable.
See http://mysql.rjweb.org/doc.php/find_nearest_in_mysql for discussion.
That lists 5 ways to "find the nearest X". The simplest, but slowest, is check every item for its distance. All the rest are faster because of using a "bounding-box" to limit how many items need to be checked. However, the coding gets complex.
A bounding-box, in your case, could be limited to the maximum radius in the table. Your sample data show radii of up to 8, so building a square of side 2*8 around the starting point would let you feed into the various techniques I describe.
The simplest involves INDEX(lat, lng), INDEX(lng, lat) to let the Optimizer pick which is better. The advantage is that it checks only items in a 16-wide band of latitude (or longitude), not the entire globe. The disadvantage is that it does not do much to optimize the other direction.
I suggest you use that technique as a first cut. If you need more performance then read further in my document and, optimally, come back for more help,
The techniques discussed there also allow for limiting the number of returned values.
Related
I'm going to build an app where the users can see points of interest in a predefined radius around their location.
My first idea was to store the latitude and longitude of all POI's in a database and comparing the users location with the POI's location via SQL.
The problem is the performance I think. If there are thousands of POI's and thousands of user requests with their location, it wouldn't be very economically or is this no problem for todays servers?
My next approach was to divide the map in quadrants, and only observing the surrounding quadrants.
tl;dr:
All in all I'm looking for:
a way to do an radius search
at best caching the results for other users
the cache will be updated when a new POI is being registered.
If you have any ideas how to realize something like that, please let me know.
Thank you
Fabian
I think what you are looking for is the Harversine formula, which it allows you to find the distance between two points in a sphere (in this case the Earth). An implementation using SQL would be something like this:
ACOS (
SIN(RADIANS($latitude)) *
SIN(RADIANS(T.latitude))+
COS(RADIANS($latitude)) *
COS(RADIANS(T.latitude))*
COS(RADIANS($longitude-T.longitud)))*6378.137 AS distance
Adding this to the select of your query will return a column called distance calculating (in Km) how far is the point ($latitude,$longitude), normally the user, from (T.latitude,T.longitude), normally the element of the table.
In case you want to filter, and don't show elements further than a certain distance you can make a condition like:
HAVING distance<$radius
I imagine that you are using MySQL, if this is the case you have to use HAVING instead of WHERE to make a condition over a computed column (distance).
A complete example of a query would be like this:
SELECT T.*, ACOS (
SIN(RADIANS($latitude)) *
SIN(RADIANS(T.latitude))+
COS(RADIANS($latitude)) *
COS(RADIANS(T.latitude))*
COS(RADIANS($longitude-T.longitud)))*6378.137 AS distance
FROM your_table as T
HAVING distance < $radius
ORDER BY distance LIMIT $limit
If you want to optimize a bit more the performance add a limit to the query so you will have for example the 10 nearest places.
Take your time to consider Spatial data types aswell since they were specificly made for this kind of work.
Note that I do not recommend you to insert your php variables directly into your query, is really unsecure, I did that only as an example.
Hope this helps you.
I would like to implement a search by distance on a website.
There must be a user in a living city can find all users living within 100 or 200 km for example.
I have a table in my database that stores all the cities and their coordinates.
I thought to create another table that would store the distance between all cities but my data base contains 36,000 cities and it may make a lot of records ...
How could I make this search more simply knowing that my project will be developed with Symfony and Doctrine?
Thank you beforehand
You can use the correct answer here to determine the distance between co-ordinates.
Measuring the distance between two coordinates in PHP
For performance reasons you need to use geospatial index to efficiently query such a database. For example MongoDB has a feature for this.
If performance is not an issue you can simply store locations in relational database table and calculate distances in SQL. See this question for some information about this solution: Geo-Search (Distance) in PHP/MySQL (Performance)
I have a series of rows in MySQL with a 'location' column, which represents the location of an object on a two dimensional xy grid. I want to search the table for rows with a location which is within a given distance of a certain tiles.
For example, if I ran a search within 10 tiles of [34,56], that would return any rows with a 'location' value between [24-44 and 46-66].
My solution to this problem was to create an array (using for loops) with all of the possible tiles that would fall within that search term, and then query MySQL thusly:
"SELECT * FROM table WHERE localcoordinate IN ('$rangearray')"
This solution works fine, but is very resource intensive. I'd like to be able to run many searches at a distance of hundreds or thousands of tiles. Can anyone suggest a better approach that might run faster?
I improved my resource consumption by a factor of 100 by implementing the following strategy changes.
1) I broke the xy coordinate into two fields within the table.
2) I searched natively in MySQL with the "BETWEEN" function.
The final query looked something like this. You can extrapolate the data structure from the query.
SELECT * FROM table WHERE localcoordinateX BETWEEN $x-lo AND $x-hi AND localcoordinateY BETWEEN $y-lo AND $y-hi.
I should have thought of this the first time around but I didn't. Just the act of posting to stack exchange got me thinking clearly again, though!
I work on a site which sells let's say stuff and offers a "vendors search". On this search you enter your city, or postal code, or region and a distance (in km or miles) then the site gives you a list of vendors.
To do that, I have a database with the vendors. In the form to save these vendors, you enter their full address and when you click on the save button, a request to google maps is made in order to get their latitude and longitude.
When someone does a search, I look on a table where I store all the search terms and their lat/lng.
This table looks like
+--------+-------+------+
| term | lat | lng |
+--------+-------+------+
So the first query is something very simple
select lat, lng from my_search_table where term = "the term"
If I find a result, I then search with a nice method for all the vendors in the range the visitor wants and print the result on a map.
If I don't find a result, I search with a levenshtein function because people writing bruxelle or bruxeles instead of bruxelles is something really common and I don't want to make a request to google maps all the time (I also have a "how many time searched" column in my table to get some stats)
So I request my_search_time with no where clause and loop through all results to get the smallest levensthein distance. If the smallest result is greater than 2, I request coordinates from google maps.
Here is my problem. For some countries (we have several sites all around the world), my_search_table has 15-20k+ entries... and php doesn't (really) like looping on such data (which I perfectly understand) and my request falls under the php timeout. I could increase this timeout but the problem will be the same in a few months.
So I tried a levensthein MySQL function (found on stackoverflow btw) but it's also very slow.
So my question is "is there any way to make this search fast even on very large datasets ?"
My suggestion is based on three things:
First, your data set is big. That means - it's: big enough to reject the idea of "select all" + "run levenshtein() in PHP application"
Second, you have control over your database. So you can adjust some architecture-related things
Finally, performance of SELECT queries is the most important thing, while performance for adding new data doesn't matter.
The thing is you can not perform fast levenshtein search because levenshtein itself is very slow. I mean, calculating levenshtein distance is a slow thing. Thus, you'll not be able to resolve the issue with only "smart search". You'll have to prepare some data.
Possible solution will be: create some group index and assign it during adding/updating data. That means - you'll store additional column which will store some hash (numeric, for example). When adding new data, you'll:
Perform search with levenshtein distance (for that you may either use your application or that function which you've (already mentioned) over all records in your table against inserted data
Set group index for new row to value of index which found rows in previous step have.
If nothing found, set some new group index value (it' the first row and there are no similar rows yet) - which will be different from any group index values that already present in table
To search desired rows, you'll need just select rows with same group index value. That means: your select queries will be very fast. But - yes, this will cause extremely huge overhead when adding/changing your data. Thus, it isn't applicable for case, when performance of updating/inserting matters.
You could try MySQL function SOUNDS LIKE
SELECT lat, lng FROM my_search_table WHERE term SOUNDS LIKE "the term"
You can use a kd-tree or a ternary tree to speed up the search. The idea is to use a binary search.
I've done some reading so far and I am at a crossroads.
My situation is this:
Table with a list of lat/lng values ( we can take these to be "cities" ) with a radius
Table with a list of movement values, including a lat/lng
My requirement is that I return the list of movements and include the nearest city (if it's within the radius). I've so far used the haversine formula in PHP to do this for each record I return but it's not particularly efficient.
My two options I've found is either to:
1/ create a stored procedure in MySQL to do the Haversine that side (something like this: Proximity Search )
2/ use a "bounding box" method of positioning the cities instead of a circle. This is not a big problem and would allow the sql to be simplified. However, in some cases the typical logic of determining whether the point lies between the top left and bottom right will not work if the lat and lng are in negatives. In PHP, to work around this, I would do a quick "if" where I'd check if the top-left lat/lng is greater than the bottom-right and use AND/OR depending on the result.
After some extra reading I found this question here on SO.
https://stackoverflow.com/a/5548877/1749630
This answer was exactly what I needed to point me in the right direction. In this way I am now using a sub-select in order to find the city.
If someone posts a better answer than this one I'll mark that instead of this one :)