Как получить больше точности для вычисленного расстояния в MySQL, не используя геометрические типы? - PullRequest
0 голосов
/ 17 января 2019

Я должен вычислить расстояние между объектом (городом) и каждой из нескольких записей из таблицы MySQL, которую я имею (некоторые рестораны). Этот город и рестораны находятся в одной стране.

Расчетное расстояние используется, чтобы показать все рестораны, которые находятся близко к этому городу; пороговое расстояние произвольно. Кроме того, это ранжированный список: самые близкие рестораны показываются первыми, а самые отдаленные - в конце списка. Моя проблема связана с этим ранжированием.

Что я сейчас сделал

Итак, я провел несколько исследований, и мне удалось вычислить это расстояние.

    $special_select_distance = "DEGREES(ACOS(COS(RADIANS(" . $oneVilles->__get('latitude')[app::getLang()] . ")) * COS(RADIANS(lat)) * COS(RADIANS(lon) - RADIANS(" . $oneVilles->__get('longitude')[app::getLang()] . ")) + SIN(RADIANS(" . $oneVilles->__get('latitude')[app::getLang()] . ")) * SIN(RADIANS(lat))))";

    $restaurants = $restaurantsDAO->getAll(null, ['distance DESC'] , null, 'HAVING distance < 1.9' , null , '*, ' . $special_select_distance . " AS distance");

... где:

  1. ['distance DESC'] обозначает ранжирование по расстоянию

  2. 'HAVING distance < 1.9' обозначает произвольный порог

  3. '*, ' . $special_select_distance . " AS distance" является селектором

  4. $oneVilles->__get('latitude')[app::getLang()] и $oneVilles->__get('longitude')[app::getLang()] - координаты города, широта и долгота

  5. lat и lon - координаты ресторана (автоматически учитываются в таблице, по которой мы выполняем итерацию, , то есть: restaurants таблица, поскольку мы используем рестораны DAO)

Вопрос

Фактический и неожиданный результат

Для каждого из ресторанов, которые достаточно близки между собой, расчетное расстояние до города остается неизменным.

Пример: предположим, что рестораны A и B довольно близки. Тогда расстояние между А и городом такое же, как у В и города, это мой фактический и неожиданный результат.

Это не то, что я хочу. Действительно, на самом деле один из этих ресторанов ближе к городу, чем другой. Я думаю, что в MySQL недостаточно точности.

Ожидаемый результат

Ожидаемый результат: составить рейтинг ресторанов по расстоянию до города. Другими словами, чтобы получить более точное вычисленное расстояние.

Пример: предположим, что рестораны A и B довольно близки. Тогда расстояние между А и городом короче, чем В и городом, это мой ожидаемый результат.

Примеры вычисленных расстояний

  1. Между рестораном и городом (ресторан находится далеко от города): 1.933156948976873

  2. Между рестораном A и городом (A находится недалеко от города): 1.6054631070094885

  3. Между рестораном B и городом (B находится рядом с A): 1.6054631070094885

Расстояния в точках 2. и 3. одинаковы и это не нормально. Я хотел бы иметь больше цифр, чтобы иметь возможность более эффективно ранжировать свои рестораны.

Ограничения

  • Я бы не хотел менять конфигурацию MySQL Server.

    • В частности: я абсолютно не могу использовать геометрические типы MySQL (это ограничение фирмы)
  • Ожидаемое решение должно просто изменить SQL-запрос, который я написал и предоставил вам, чтобы быть более точным, если это возможно.

  • При необходимости допускаются другие методы расчета расстояния.

1 Ответ

0 голосов
/ 18 января 2019

Для больших расстояний используйте формулу Haversine для точности. На коротких дистанциях Пифагор в два раза быстрее.

16 значащих цифр (тип данных DOUBLE) смешно. Вам не нужно различать двух разных блох на вашей собаке.

С Пифагором обязательно делите долготу на косинус широты - один градус долготы возле Хельсинки в два раза меньше, чем один градус на экваторе.

Некоторые подробности здесь: http://mysql.rjweb.org/doc.php/latlng

Если 1.6054631070094885 является разницей по широте, то подумайте об этом следующим образом: если вы и я на одной долготе, но наши широты равны 1.605463 и 1.605464, то, ну, я не знаю вас достаточно хорошо, чтобы быть , что близко.

Невозможно сравнивать два значения с плавающей запятой без коэффициента выдумки:

If abs(a-b) < 0.00001, then treat them as equal.

Подробнее

Я рекомендую FLOAT для широты, расстояния и расстояния, так как вы говорите о ресторанах. Если вы говорите не о, скажем, 100 милях или километрах, то это выражение достаточно точное:

SQRT(  ($lat - lat) *
       ($lat - lat) +
      (($lng - lng) * COS(RADIANS(lat))) *
      (($lng - lng) * COS(RADIANS(lat))) )  * $factor

Где ...

  • lat и lng - это имена FLOAT столбцов в таблице, в градусах.
  • $lat и $lng - это значения местоположения, с которого вы начинаете, также в градусах. (PHP использует $; другие языки используют другие соглашения.)
  • $factor - 69,172 для миль или 111,325 для километров.
  • Я бы не отображал результат более чем с 1 десятичным знаком. (Не показывайте «12,345678 миль»; достаточно «12,3 миль».)

A Сравнение Пифагора и GCD:

             Pyt        GCD
To Rennes:  93.9407    93.6542
To Vannes:  95.6244    95.6241
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...