Wyszukiwanie obiektów w "pobliżu" w php i googlemaps

Witam serdecznie,

Wątpię, aby samym zapytaniem dało się coś zrobić. Zasadniczo widzę dwie sensowne opcje.

Dam Ci wędkę, ale sam pójdziesz na ryby  :slight_smile:

 

Jeśli chcesz wyciągnąć z bazy obiekty w jakimś promieniu do WHERE musisz dodać coś takiego:

(6371 * acos(cos(RADIANS(" . $params['lat'] . ")) * cos(RADIANS(szer)) * cos(RADIANS(dl) - RADIANS(" . $params['lng'] . ")) + sin(RADIANS(" . $params['lat'] . ")) * sin(RADIANS(szer)))) < " . $value

gdzie:

$params['lat'] // szerokość obiektu w pobliżu którego szukasz
$params['lng'] // długość obiektu w pobliżu którego szukasz
$value // promień, w którym szukasz

 

 

Dzikuje bardzo za odpowiedz - jednak nie do końca to działa :frowning:

zapytanie:

SELECT * FROM `cms_obiekt` WHERE (6371 * acos(cos(RADIANS()) * cos(RADIANS(szer)) * cos(RADIANS(dl) - RADIANS(11.157031375000042)) + sin(RADIANS(34.346579711195)) * sin(RADIANS(szer)))) < 5000

zwraca błąd:

1582 - Incorrect parameter count in the call to native function ‘RADIANS’

 

 

:frowning:

Nie podałeś parametru dla funkcji RADIANS.

SELECT * FROM `cms_obiekt` WHERE (6371 * acos(cos(RADIANS(34.346579711195)) * cos(RADIANS(szer)) * cos(RADIANS(dl) - RADIANS(11.157031375000042)) + sin(RADIANS(34.346579711195)) * sin(RADIANS(szer)))) < 5000

Super!! Działa, dziękuję bardzo za pomoc :slight_smile:

 

Ten promień jest wyrażony w kilometrach?:slight_smile:

Prawdopodobnie w kilometrach, ale dla pewności możesz sprawdzić na jakichś znanych koordynatach.

dziękuję :slight_smile:

chyba jednak nie do końca to działa…

zrobiłem takie zapytanie:

SELECT * FROM cms_obiekt where enable ='1' and (6371 * acos(cos(RADIANS(34.346579711195)) * cos(RADIANS(szer)) * cos(RADIANS(dl) - RADIANS(11.157031375000042)) + sin(RADIANS(34.346579711195)) * sin(RADIANS(szer)))) < 200 ORDER by nazwa ASC;

wszystko ładnie się wykonuje z tym że wyświetlają się także obiekty - które nie mają w okolicy nic dodatkowego… Jak to można zmienić?:slight_smile:

co to znaczy “nie mają nic dodatkowego”?

wzór, który podali Ci koledzy wyżej służy do wyznaczania odległości pomiędzy dwoma punktami centralnymi, czyli możesz sobie teraz dzięki temu sprawdzić np. w jakiej odległości jest to Twoje jezioro od warsztatu i dopiero wypisać warsztaty które spełniają to co sobie założysz.

tutaj nie ma żadnej magii, że Ci znajdzie jeziora w pobliżu - idąc dalej tym przykładem. musisz mieć współrzędne dwóch pkt na mapie i sobie wtedy tym możesz sprawdzić odległość pomiędzy nimi - that’s all

 

a tak jak Ty chcesz zrobić z tego co rozumiem to możesz np dać jeszcze SUBQUERY na te pozostałe obiekty względem tego aktualnie szukanego

Nie polecam powyższego rozwiązania, o ile dobrze rozumiem intencję. Głównie dlatego, że to nie będzie podzapytanie, a podzapytanie skorelowane (w WHERE zapytania wewnętrznego, będą wartości z zapytania zewnętrznego). Przykładowy pseudokod:

SELECT * FROM t as outter WHERE do_ilu_kilometrów > (SELECT * FROM t as inner WHERE distance(outter.X, outter.Y, inner.X, inner.Y))

gdzie distance, to liczenie odległości między punktami, zapisane w skrócie (tak wiem, że taki warunek nie zadziała, porównywanie liczby ze zbiorem wierszy, w praktyce można go zastąpić tym, czy zapytanie wewnętrzne zwróciło jakieś wiersze czy nie, ale chodzi o czytelność tego, że występuje korelacja na zapytaniu wewnętrznym).

 

a czy ja powiedziałem że subqueries to jest dobre rozwiązanie? czasami jest po prostu jedyne.

jest to odpowiedź na problem który został poruszony :slight_smile:

 

bez zmiany struktury bazy też bym zalecał przetworzenie to po stronie języka, jednak autor nie mówił nic o języku innym niż sql. tak więc idąc w stronę autora chyba podałem jedyne rozwiązanie :smiley:

poczytam sobie o tym “skorelowaniu”, pierwszy raz spotkałem się z tym terminem

 

edit. z zasadzie nie było co czytać. zwykłe subquery zależne od głównego, czyli tak, takie jak podałem.

Nie tyle zwykłe, jeśli rozumiemy co to robi. Jeśli nie jest ono skorelowane, to wewnętrzny select zostanie wykonany dokładnie raz, jeśli jest skorelowane wewnętrzny select zostanie wykonany tyle raz ile wierszy zwróciło zapytanie nadrzędne, co jest równoznaczne z wykonaniem bezsensownych operacji dyskowych (a te są dużo wolniejsze od operacji na RAM).

no jasne, tylko po prostu czasami trzeba.

wiadomo w tym przypadku by było tak, że dla każdego znalezionego miejsca zawsze wykonywało się sub query dla danych z aktualnego “znaleziska” co jest zabójstwem dla wydajności

Baza to MySQL.

Już tłumaczę problem - bo chyba nie do końca jasno go rozpisałem , albo nie jest mi do końca jasne to co napisaliście :frowning:

 

mam stronkę z selecte:

"pokaż obiekty w pobliżu których znajdują się atrakcje:

a) 1km

b) 5 km

c) 10km

d) 50km

e) 100km".

 

 

Muszę wyświetlić listę obiketów - nie CAŁĄ - tylko taką, w której obiekty ( typobiektu = 3) będą miały w pobliżu jakieś atrakcje (wartości z selecta) - czyli np. typobiektu = 2, typobiektu = 1…

 

to zapytanie które otrzymałem jest fajne - ale zwraca WSZYSTKIE obiekty (typobiektu = 3) + to co je otacza (typobiektu = 1 i typobiektu = 2).

Bazy jako takiej nie mogę przeprojektować, muszę niestety operować na tym co mam…

 

Obrazowo mam obiekty: A, B (nie ma atrakcji w okolicy), C, D, E, F (nie ma atrakcji w okolicy) - wybieram z selecta 50km.

System wyświetla mi Obiekty A,C,D,E (typobiektu = 3) + wszystkie atrakcje które znajdują się w pobliżu tych obiektów (czyli rekordy typobiektu = 1 i typobiektu = 2)

 

Mam nadzieję że udało mi się to lepiej zobrazować :slight_smile:

Definitywnie to drugie.

 

 

Dopóki nie wprowadzisz usprawnienia w postaci powiązania obiektów w sensownej odległości, najlepiej będzie zrobić dwa SELECT-y.

Pierwszy z nich wybierze obiekty które chcesz z czymś powiązać, a drugi listę obiektów, które można hipotetycznie powiązać (są dobrego typu). Następnie dla każdego obiektu z pierwszej listy sprawdzasz, czy któryś obiekt z drugiej listy może zostać powiązany (jest w dobrej odległości). Jeśli tak, tworzysz skojarzenie (dodajesz go do jakiejś wewnętrznej listy powiązań pierwszego obiektu, aby móc go potem wyświetlić).

Problem w tym że nie mogę modyfikować tej bazy… :frowning:

Chcę tylko zbudować ten filtr do niej…

Dochodzą tam codziennie jakieś rekordy i nie mam możliwości integrowania w to…

 

czyli sugerujecie zrobić:

a) wyświetlamy całą listę (typobiektu = 3)

b) w momencie gdy 2 zapytanie MySQL znajdzie jakiś obiekt w “pobliżu” tego pierwszego obiektu - to wyświetlamy oba?

jeśli nie możesz przeprojektować to zrób tak że jak ktoś sobie kliknie w pobliży np 5km to ty szukasz najpierw wszystkich obiektów danego typu a potem znajdujesz sobie potencjalne obiekty w okolicy i nie po stronie mysql tylko języka w którym jest napisana strona, zakładam że php, dopasowujesz sobie wyniki. takie rozwiązanie będzie wydajniejsze. możesz to jeszcze cache’ować ale pisałeś że codziennie dochodzą nowe wpisy więc nie ma to sensu raczej

dokładnie cache też idpada… rekordów dużo nie ma (ok 400) - więc z wydajnością nie będzie źle pewnie…

Dlatego chyba mysql będzie najszybszym rozwiązaniem?

 

Dziękuję za cierpliwość :slight_smile:

Oczywiście, że nie działa, bo (powołując się na post #11):

 

Innymi słowy musisz podstawić wzór na odległość dwóch punktów, bo taka funkcja nie istnieje, zapisałem skrótowo, aby było czytelniej.