Найти точки возле LineString в mongodb, отсортированные по расстоянию

У меня есть массив точек, представляющих улицу (черную линию) и точки, представляющие места на карте (красные точки). Я хочу найти все точки возле указанной улицы, отсортированные по расстоянию. Мне также нужно иметь возможность указывать максимальное расстояние (синие и зеленые области). Вот простой пример:

enter image description here

Я думал об использовании оператора $near, но он принимает только Point как вход, а не LineString.

Как mongodb может обрабатывать этот тип запросов?

Ответ 1

Как вы упомянули, Mongo в настоящее время не поддерживает ничего, кроме Point. Вы столкнулись с концепцией боксера? 1 Он был очень популярен несколько лет назад на Google Maps. С учетом строки, которую вы нарисовали, найдите остановки, которые находятся в пределах dist(x). Это было сделано путем создания ряда ограничивающих прямоугольников вокруг каждой точки линии и поиска точек, которые попадают в ведро.

Я наткнулся на ваш вопрос после того, как я понял, что Монго работает только с точками, что разумно предположить.

У меня уже есть несколько вариантов того, как это сделать (они расширяют то, что говорит @mnemosyn в комментарии). С набором данных, над которым я работаю, все это на стороне клиента, поэтому я мог использовать routeboxer, но я хотел бы реализовать его на стороне сервера по соображениям производительности. Вот мои предложения:

  • сломать LineString вниз в свои отдельные координатные множества, а запрос для $near с помощью каждого из них объединить результаты и извлечь уникальный набор. Существуют алгоритмы для упрощения сложной линии, путем сокращения количества точек, но простой легко записать.

  • делать то же, что и выше, но как хранимую процедуру/функцию. Я не играл с хранимыми функциями Mongo, и я не знаю, насколько они хорошо работают с драйверами, но это может быть быстрее, чем первый вариант выше, поскольку вам не придется делать обратные вызовы и в зависимости от того, ваш экземпляр Монго находится (находится), расчеты могут быть быстрее на микросекундах.

  • Внедрите серверный подход routeboxer на стороне сервера (это было сделано на PHP), а затем используйте любой из указанных выше 2, чтобы найти остановки, которые являются $within получающимися ограничивающими прямоугольниками. Если метод routeboxer возвращает прямоугольники, можно объединить все эти прямоугольники в один полигон, покрывающий ваш маршрут, и просто сделать $within. (Что предложил @mnemosyn).

  • РЕДАКТИРОВАТЬ: Я думал об этом, но забыл об этом, но можно было бы реализовать некоторые из вышеперечисленных функций, используя структуру агрегации.

Что-то, над чем я буду работать (надеюсь), я открою исходный результат (ы), основанный на том, с чем я заканчиваю.

РЕДАКТИРОВАТЬ: Я должен упомянуть, что 1 и 2 имеют недостаток, если у вас есть 2 точки в строке, которые говорят на расстоянии 2 км друг от друга, и вам нужны точки, находящиеся в пределах 1.8 км от вашей линии, вы, очевидно, пропустите все точки между этой частью вашей линии. Решение заключается в том, чтобы вводить точки на вашу линию, когда это упрощает (я знаю, бьет цель уменьшения точек при добавлении новых).

Ошибка с 3 тогда заключается в том, что она не всегда будет точна, так как некоторые точки внутри вашего полигона, вероятно, будут иметь расстояние больше вашего предела, хотя разница не будет значительным процентом вашего предела.

[1] google maps utils routeboxer

Ответ 2

Как вы сказали, Монго $рядом работает только с точками, а не линиями, как центр, однако, если вы переверните свое предположение от точек поиска вблизи линии, чтобы найти линию вблизи точки, тогда вы можете использовать свои точки как центр и линию, как цель

это различие между

foreach line find points near it

и

foreach point find line near it

если у вас есть большое количество точек для проверки, вы можете комбинировать это с ответом nevi_me, чтобы уменьшить список точек, которые нуждаются в проверке на гораздо меньшее подмножество