MySQL цикл для геопространственного анализа - PullRequest
0 голосов
/ 16 декабря 2018

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

Что я хочу сделать: В MySQL у меня есть одна таблица, содержащая вызовы данных службы из нашего полицейского управления, и другая таблица, содержащая свободные свойства,Каждая таблица имеет поля широты, долготы.Мы хотим знать для каждого вызова на обслуживание, было ли это в пределах 100 футов от вакантной собственности?Вот запрос, который мы написали, используя примерную координату, чтобы проверить, работает ли анализ расстояний:

SELECT
    address, (
        (20903520) 
    * acos (
        cos ( radians(38.67054) )
        * cos( radians( lat ) )
        * cos( radians( long ) - radians(-90.22942) )
        + sin ( radians(38.67054) )
        * sin( radians( lat ) )
    )
) AS distance
FROM vacants
HAVING distance < 100;

Как мне написать цикл для прохождения каждого вызова для местоположения службы и проверки его для каждого свободного местачтобы выяснить, не было ли для каждого звонка свободного места в радиусе 100 футов?Я попытался написать оператор DECLARE, создать переменную COUNTER и использовать синтаксис BEGIN / END.Никто из них, казалось, не достиг этого, хотя, возможно, я просто не писал их правильно.SQL не мой самый сильный;Я предпочитаю Python, но мы думаем, что сделать это с помощью SQL-запроса будет быстрее, чем зацикливать файлы .csv.Около 2,5 миллиона обращаются за сервисными записямиВ конце мы хотим сказать, что «из 2,5 миллионов вызовов на обслуживание X были в пределах 100 футов от вакантной собственности».Я также хотел бы иметь возможность вывести файл .csv с адресом вакантного свойства, расстоянием от расстояния до вызова для обслуживания, найденного вакантным в радиусе 100 футов, и двумя другими полями из вызова.для служебной таблицы (исходный код вызова и код окончательного вызова).

Примерно так, но с добавлением двух полей.Это происходит из предоставленного мною тестового запроса.

Results of test query

Мы также хотим провести обратный анализ, чтобы увидеть, сколько вызовов для обслуживания было в пределах 100- радиус стопы каждого свойства.

Вот пример данных - вызовы координат сервиса:

38.595767638008056,-90.2316138251402
38.57283495467307,-90.24649031378685
38.67497061776659,-90.28415976525395
38.67650431524285,-90.25623757427952
38.591971519414784,-90.27782710145746
38.61272746420862,-90.23292862245287
38.67312983860098,-90.23591869583113
38.625956494342674,-90.18853950906939
38.69044465638584,-90.24339061920696
38.67745024638241,-90.20657832034047`

Координаты свободного свойства:

38.67054,-90.22942
38.642956,-90.21466
38.671535,-90.27293
38.666367,-90.23749
38.65339,-90.23141
38.645996,-90.20334
38.60214,-90.224815
38.67265,-90.214134
38.665504,-90.274414
38.668354,-90.269966`

Спасибо за любую помощь.

Ответы [ 2 ]

0 голосов
/ 16 декабря 2018

Использование встроенных в MySQL функциональных возможностей gemoetry, несомненно, является лучшим вариантом, как показано в ответе @ johannes.

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

Если вы хотите перейти к текущей настройке, вот запрос, который идентифицирует все сервисные адреса, которые произошли менее чем в 100 футах от вакантного, с расстоянием до ближайшего местоположения.

Он работает путем создания подзапроса, который для каждого вызова службы вычисляет расстояние со всеми местоположениями.Затем подзапрос группируется по сервисному вызову и выбирает те, где минимальное расстояние составляет менее 100 футов.

SELECT 
    address,
    MIN(distance)
FROM (
    SELECT
        cfs.address
        20903520 * acos (
              cos( radians( csf.lat ) )
            * cos( radians( vacants.lat ) )
            * cos( radians( vacants.long ) - radians( cfs.long) )
            + sin( radians( cfs.lat ) ) * sin( radians( vacants.lat ) )
    ) AS distance
    from cfs
    cross join vacants
) AS t
 GROUP BY cfs.address
 HAVING MIN(distance) < 100
0 голосов
/ 16 декабря 2018

Ваши вычисления синуса / косинуса будут медленными, и вы не сможете использовать индекс.Однако MySQL имеет хорошую поддержку индексов геометрии и индексов r-tree для эффективного доступа.

Способ хранения ваших мест - использовать их в типе данных, например POINT, и использовать геометрические функции, такие как st_distance, для расчета.the distance.

Пример, основанный на вашей информации:

CREATE TABLE vacants (address varchar(255), geo POINT NOT NULL SRID 4326,  SPATIAL KEY (geo))
insert into vacants VALUES ('123 some str', ST_PointFromText('POINT(8.6949639 50.1139589)', 4326) );
insert into vacants VALUES ('123 some ave', ST_PointFromText('POINT(8.6779835 50.1156941)', 4326) );
SELECT address, st_distance(geo, ST_PointFromText('POINT(8.532687 50.1036198)', 4326)) as `distance in meters` FROM vacants;
+--------------+---------------------+
| address      | distance in meters  |
+--------------+---------------------+
| 123 some str | 17983.567531177974  |
| 123 some ave | 16124.382142034325  |
+--------------+---------------------+
2 rows in set (0,00 sec)

Значение SRID 4326 описывает пространственное отношение id и описывает геометрическую систему, подобную Земле.Для других планет или искусственных геометрических структур вам нужны другие значения.Геометрия, которую я описываю как WKT или «хорошо известный текст», является стандартизированной формой для описания всех видов геометрических объектов.Данные могут быть предоставлены и в других форматах (например, геойсон или некоторые другие). Выбранные мною местоположения находятся где-то в центральной части Германии.

С этим расстоянием вы сможете довольно легко создать обратный поиск.

Все подробности см. На страницах справочника в https://dev.mysql.com/doc/refman/8.0/en/spatial-types.html и https://dev.mysql.com/doc/refman/8.0/en/spatial-analysis-functions.html

...