Как эффективно находить группы местоположений GPS, находящихся на определенном расстоянии?

Я разрабатываю приложение PHP, которое работает с набором местоположений, предоставленных через широту, долготу-координаты в таблице MySQL. Поскольку эти местоположения импортируются из внешних источников, я хочу предоставить пользователю представление «объединения», где они могут видеть группы местоположений, которые находятся в пределах X метров друг от друга, и объединять их в одно.

Проблема реализации поиска по близости обсуждалась много, например:

Большинство из них используют стандартную формулу гаверсинуса для расчета расстояний:

SELECT 
  -- stuff here
  , ( 6371000 * acos( cos( radians($LAT) ) * cos( radians( stuff.lat ) ) * cos( radians( stuff.lng ) - radians($LNG) ) + sin( radians($LAT) ) * sin(radians(stuff.lat)) ) ) AS distance 
FROM 
  stuff
HAVING 
  distance < $distance

Однако это работает только в том случае, если у меня есть одна точка для поиска, но я хочу найти ВСЕ группы местоположений, которые находятся в пределах X метров друг от друга.

Моим простым решением было бы получить все местоположения в PHP-код, затем перебрать их и использовать приведенный выше запрос, чтобы найти все близлежащие местоположения для каждого местоположения. После этого я очищаю повторяющиеся группы. Но это решение имеет стоимость n², потому что я создаю n запросов, которым нужно вычислить расстояние до всех других местоположений. Вторая часть может быть улучшена с помощью ограничительной рамки, однако мне все еще нужно выполнить n запросов (чтобы получить все близлежащие местоположения для каждого местоположения).

Есть ли более производительный метод? Может быть, даже внутри одного запроса MySQL (чтобы просто вывести идентификаторы местоположений для каждой группы)?

Таблица с местоположениями - это просто «id», «name», «lat» и «lng».


person ArcticXWolf    schedule 22.01.2020    source источник
comment
Разделите всю площадь на квадраты со стороной, равной (или немного большей) искомому диапазону (X метров). Выполняйте эти дорогостоящие вычисления только для тех пар точек, квадраты которых являются смежными по стороне или углу. И - если достаточно приблизительного результата, то просто делим на квадраты с side ~ X * 0.7 и берем пары в соседних квадратах.   -  person Akina    schedule 22.01.2020
comment
Хорошо, но как мне получить пары точек, у которых есть соседние квадраты? Я должен вычислить квадратную геометрию для каждой точки, не так ли?   -  person ArcticXWolf    schedule 22.01.2020
comment
Какая геометрия? Просто разделите широту/долготу на расстояние и округлите до целого числа.   -  person Akina    schedule 22.01.2020
comment
О да. Но я только что столкнулся с дополнительной проблемой: что, если у вас есть местоположения A -> B ‹- C, и AB ниже X метров, BC ниже X метров, а AC нет. Какие группы мне нужны? Две группы AB,BC или одна со всеми? Возможно, мне нужно переосмыслить саму проблему.   -  person ArcticXWolf    schedule 22.01.2020
comment
Что делать, если у вас есть местоположения A -> B ‹- C и AB ниже X метров, BC ниже X метров, а AC нет. Какие группы мне нужны? Две группы AB,BC или одна со всеми? Это похоже на кластеризацию, которая является более сложной задачей, чем поиск соседних точек только для каждой отдельной точки. Возможно, мне нужно переосмыслить саму проблему. Может быть... тем более, что вероятность этого довольно высока, как мне кажется.   -  person Akina    schedule 22.01.2020
comment
В яблочко. Я думаю, что я просто предоставлю представление о близлежащих местах в представлении каждого местоположения, поэтому я могу перебирать набор только один раз. У меня не будет представления слияния, которое показывает все группы, но я считаю, что этого будет достаточно. Спасибо за вашу помощь!   -  person ArcticXWolf    schedule 22.01.2020
comment
@ArcticXWolf. Прочитайте это: en.wikipedia.org/wiki/Fractal_dimension_on_networks Это может дать вам ключ к сложности того, что вы спрашиваете.   -  person Rick James    schedule 25.01.2020