|
Оптимизация кода для поиска | ☑ | ||
---|---|---|---|---|
0
Ayvengo
07.09.12
✎
14:57
|
Есть справочник точки, у которых есть широта, долгота, радиус
Есть регистр сведений, в который постоянно попадают данные где есть ссылка на справочник машины и широта, долгота. Т.е. 2 таблицы с колонками: Точка, Широта, Долгота, Радиус и Машина, Широта, Долгота. Мне нужно обработать каждую строку таблицы с машинами, что бы понять, попала ли она в нужную точку. Теоретически я могу сделать так Для Каждого Машина из Машины Цикл ТекТочка = Неопределено; Для Каждого Точка из Точки Цикл Если ТочкаВходитВРадиус(Машина.Широта1, Машина.Долгота1, Точка.Широта2, Точка.Долгота2, Точка.Радиус) Тогда ТекТочка = Точка.Ссылка; Прервать; КонецЕсли; КонецЦикла; Если ТекТочка <> Неопределено Тогда ЗарегистрироватьПрибытиеВТочку(Машина.Ссылка, ТекТочка); КонецЕсли; КонецЦикла; Допустим , код примерно выглядет так. Хотелось бы его оптимизировать, что бы работало все быстрее. Количество строк в таблице точек = 10000, количество строчек в таблице машин - 10000 |
|||
1
Happy Bear
07.09.12
✎
15:00
|
(0) у тебя все 10000 машин на выезде постоянно?
|
|||
2
Ayvengo
07.09.12
✎
15:01
|
(1) у меня у каждой машины по 500 координат
|
|||
3
Heckfy
07.09.12
✎
15:03
|
Не совсем понял... А запрос с соединением не пойдет?
|
|||
4
mzelensky
07.09.12
✎
15:04
|
(3) на сколько я понимаю - запросом ты не вычислишь это:
ТочкаВходитВРадиус(Машина.Широта1, Машина.Долгота1, Точка.Широта2, Точка.Долгота2, Точка.Радиус) |
|||
5
Ayvengo
07.09.12
✎
15:05
|
В запросе я не могу понять, что "ТочкаВходитВРадиус"
|
|||
6
mzelensky
07.09.12
✎
15:06
|
(4) но обойти машины и ИХ конкретные точки - это да, запросом! Так меньше обходов будет
|
|||
7
Галахад
гуру
07.09.12
✎
15:06
|
(0) Может логику поменять?
При записи в регистр проверять ТочкаВходитВРадиус ну и соответственно чо-то писать. |
|||
8
Ayvengo
07.09.12
✎
15:07
|
(6) у меня таблица очищается постоянно, когда точка обрабатывается. Т.е. 10000 строк - они постоянно с каждой секундой растут. GPS шлет данные.
|
|||
9
mzelensky
07.09.12
✎
15:07
|
(5) ты можешь запросом сразу сделать связку Машина-ТОЧКИ...т.е. во втором цикле " Для Каждого Точка из Точки Цикл" ты будешь перебирать не АБСОЛЮТНО ВСЕ ТОЧКИ, а толко точки конкретно этой машины. А дальше как ты написал.
|
|||
10
Ayvengo
07.09.12
✎
15:08
|
(9) я не могу сделать так, такой связки нет. Машина может прибыть не в свою точку :)
|
|||
11
mzelensky
07.09.12
✎
15:09
|
(10) и что при этом будет? Приехала машина не в свою точку...что дальше?
|
|||
12
Ayvengo
07.09.12
✎
15:09
|
(11) нужно оповестить диспетчера, что машина прибыла не в ту точку :)
|
|||
13
Ayvengo
07.09.12
✎
15:10
|
(11) там дальше жесть вообще, на самом деле. Всяческие событие, пересчет маршрута, оповещения и т.д.
|
|||
14
AndyD
07.09.12
✎
15:10
|
можно условно принять точку доставки не кругом, а квадратом, тогда будет намного проще проверку делать
|
|||
15
AndyD
07.09.12
✎
15:10
|
в том числе и в запросе
|
|||
16
GLazNik
07.09.12
✎
15:10
|
(5) Почему?
Можно показать функцию ТочкаВходитВРадиус? |
|||
17
y88
07.09.12
✎
15:11
|
изменить формат хранения точки - добавить долгота_начало, долгота_конец, широта_начало, широта_конец
Получаем запросом точки (проверка на квадрат), далее уточняем на вхождение в круг |
|||
18
mzelensky
07.09.12
✎
15:11
|
(12) в таком случае ты никак не оптимизируешь...в любом случае выбирать все-ко всем.
|
|||
19
Ayvengo
07.09.12
✎
15:12
|
(15) я делал не квадратом, прямоугольником... но в таком случае у меня очень сильно теряется точно. Это по геокоординатам, обрезая знаки, составлял соответствие и далее по нему искал - работает быстро, но не точно. Вот ищу метод лучше.
|
|||
20
mzelensky
07.09.12
✎
15:12
|
(16) там тригонометрические функции используются (косинус угла)...такое в запросе не посчитать!
|
|||
21
Ayvengo
07.09.12
✎
15:13
|
(19) точность теряется. Прямоугольник, т.к. изменение на сотую часть широты и долготы разные. т.е. смещение 59.50 - до 59-51 по широте отличается от 59.50 до 59.51 по долготе. Расстояние разное.
|
|||
22
GLazNik
07.09.12
✎
15:13
|
(20) а таки покажи... я так понимаю что нужно просто определить что точка попадает в круг... куда там косинус и угол...
|
|||
23
Ayvengo
07.09.12
✎
15:14
|
(22) не круг, земля же не круглая :Р
Пи = 3.14159; РадиусЗемли = 6372795; Расстояние = РадиусЗемли*ATAN(Sqrt(Pow(COS(Пи*Широта2/180)*SIN(ABS(Пи*Долгота2/180-Пи*Долгота1/180)),2)+Pow(COS(Пи*Широта1/180)*SIN(Пи*Широта2/180)-SIN(Пи*Широта1/180)*COS(Пи*Широта2/180)*COS(ABS(Пи*Долгота2/180-Пи*Долгота1/180)),2))/(SIN(Пи*Широта1/180)*SIN(Пи*Широта2/180)+COS(Пи*Широта1/180)*COS(Пи*Широта2/180)*COS(ABS(Пи*Долгота2/180-Пи*Долгота1/180)))); Возврат Расстояние <= Радиус; |
|||
24
Aprobator
07.09.12
✎
15:14
|
(0) СКД с выводом результат в коллекцию значений. Правда функцию придется пихать в общий модуль.
|
|||
25
vmv
07.09.12
✎
15:15
|
тут математика и физика нужна, т.е. на формум морской навигации шагом марш
|
|||
26
Ayvengo
07.09.12
✎
15:15
|
(24) связь по функции???
|
|||
27
acsent
07.09.12
✎
15:15
|
для упрощения бери не круглый радиус а квадратный
|
|||
28
mzelensky
07.09.12
✎
15:16
|
(22) :) наивный :) Там учитывается широта, на которой находится точка!
|
|||
29
LAAry
07.09.12
✎
15:16
|
(23) Разложи гармонические функции и корень в ряд, выбери адекватное для себя количество членов ряда и замени функцию на выражение в запросе
|
|||
30
Aprobator
07.09.12
✎
15:17
|
(26) вычисляемое поле и отбор по нему.
|
|||
31
Ayvengo
07.09.12
✎
15:17
|
(22) хотел x*x + y*y >= r*r? :)
|
|||
32
LAAry
07.09.12
✎
15:17
|
+(29) выражение получится огромным...
|
|||
33
mzelensky
07.09.12
✎
15:18
|
(23) я вот так считал:
//расчет вхождения Если Выборка.ШиротаКонтра<>0 и Выборка.ДолготаКонтра<>0 тогда //расстояние в секундах РасчШирота= ? ( (Выборка.ШиротаКонтра - Выборка.ШиротаДока) >=0,(Выборка.ШиротаКонтра - Выборка.ШиротаДока), -(Выборка.ШиротаКонтра - Выборка.ШиротаДока) ) *60; РасчДолгота= ? ( (Выборка.ДолготаКонтра - Выборка.ДолготаДока) >=0,(Выборка.ДолготаКонтра - Выборка.ДолготаДока), -(Выборка.ДолготаКонтра - Выборка.ДолготаДока) ) *60; //расстояние в метрах РасчШирота=РасчШирота*30.86; РасчДолгота=РасчДолгота*30.86* cos( Цел(Выборка.ШиротаДока/100) ); //рассчитываем удаленность точки Удаленность=Sqrt( РасчШирота*РасчШирота + РасчДолгота*РасчДолгота); Если Удаленность<=100 тогда КменЗачет=КменЗачет+1; КДеньЗачет=КДеньЗачет+1; Нстрока.Попадание="ДА"; Иначе КменНеЗачет=КменНеЗачет+1; КДеньНеЗачет=КДеньНеЗачет+1; Нстрока.Попадание="Нет"; КонецЕсли; Иначе КменНовые=КменНовые+1; КДеньНовые=КДеньНовые+1; Нстрока.Попадание="Нет контрольной точки"; КонецЕсли; |
|||
34
Aprobator
07.09.12
✎
15:18
|
(32) с чего бы? Выражение в общей функции. В поле только имя функции с параметрами.
|
|||
35
Aprobator
07.09.12
✎
15:19
|
а млин соррь - мазнул. В (32) все верно сказано.
|
|||
36
LAAry
07.09.12
✎
15:22
|
Еще вариант. В запросе отбирать с 4 ближайшие точки для каждой машины по неточной формуле, а потом для этих 4-х точек считать точно.
|
|||
37
Ayvengo
07.09.12
✎
15:24
|
(33) так а чем это связано с оптимизацией, что-то не понимаю. Не трогаем функцию ТочкаВходитВРадиус :)
Тут больше интересно, может быть какие-то объекты можно использовать, которые работают быстрее чем ТЗ. Допустим ранее я использовал соответствие. Было как-то так, но тут погрешность большая: Запрос = Новый Запрос( "ВЫБРАТЬ | ТР_Точки.Ссылка КАК ТекущаяТочка, | ТР_Точки.Широта, | ТР_Точки.Долгота, | ТР_Точки.Округление |ИЗ | Справочник.тр_Точки КАК ТР_Точки |ГДЕ | НЕ ТР_Точки.ПометкаУдаления"); Выборка = Запрос.Выполнить().Выбрать(); Соответствие = Новый Соответствие; Пока Выборка.Следующий() Цикл Если Не ЗначениеЗаполнено(Выборка.Широта) ИЛИ Не ЗначениеЗаполнено(Выборка.Долгота) или Выборка.Округление = 0 Тогда Продолжить; КонецЕсли; Коэффициент = 1/Число("1"+Формат(0,"ЧЦ="+Выборка.Округление+"; ЧН=; ЧВН=; ЧГ=")); Широта1 = Окр(Выборка.Широта, Выборка.Округление); Широта2 = Широта1 + Коэффициент; Широта3 = Широта1 - Коэффициент; Долгота1 = Окр(Выборка.Долгота, Выборка.Округление); Долгота2 = Долгота1 + Коэффициент; Долгота3 = Долгота1 - Коэффициент; Соответствие.Вставить(Лев(Строка(Широта1), Выборка.Округление + СтрДлина(Цел(Широта1))) + ":"+ Лев(Строка(Долгота1), Выборка.Округление + СтрДлина(Цел(Долгота1))), Выборка.ТекущаяТочка); Соответствие.Вставить(Лев(Строка(Широта1), Выборка.Округление + СтрДлина(Цел(Широта1))) + ":"+ Лев(Строка(Долгота2), Выборка.Округление + СтрДлина(Цел(Долгота2))), Выборка.ТекущаяТочка); Соответствие.Вставить(Лев(Строка(Широта1), Выборка.Округление + СтрДлина(Цел(Широта1))) + ":"+ Лев(Строка(Долгота3), Выборка.Округление + СтрДлина(Цел(Долгота3))), Выборка.ТекущаяТочка); Соответствие.Вставить(Лев(Строка(Широта2), Выборка.Округление + СтрДлина(Цел(Широта2))) + ":"+ Лев(Строка(Долгота1), Выборка.Округление + СтрДлина(Цел(Долгота1))), Выборка.ТекущаяТочка); Соответствие.Вставить(Лев(Строка(Широта2), Выборка.Округление + СтрДлина(Цел(Широта2))) + ":"+ Лев(Строка(Долгота2), Выборка.Округление + СтрДлина(Цел(Долгота2))), Выборка.ТекущаяТочка); Соответствие.Вставить(Лев(Строка(Широта2), Выборка.Округление + СтрДлина(Цел(Широта2))) + ":"+ Лев(Строка(Долгота3), Выборка.Округление + СтрДлина(Цел(Долгота3))), Выборка.ТекущаяТочка); Соответствие.Вставить(Лев(Строка(Широта3), Выборка.Округление + СтрДлина(Цел(Широта3))) + ":"+ Лев(Строка(Долгота1), Выборка.Округление + СтрДлина(Цел(Долгота1))), Выборка.ТекущаяТочка); Соответствие.Вставить(Лев(Строка(Широта3), Выборка.Округление + СтрДлина(Цел(Широта3))) + ":"+ Лев(Строка(Долгота2), Выборка.Округление + СтрДлина(Цел(Долгота2))), Выборка.ТекущаяТочка); Соответствие.Вставить(Лев(Строка(Широта3), Выборка.Округление + СтрДлина(Цел(Широта3))) + ":"+ Лев(Строка(Долгота3), Выборка.Округление + СтрДлина(Цел(Долгота3))), Выборка.ТекущаяТочка); КонецЦикла; Но работает супер быстро :) |
|||
38
LAAry
07.09.12
✎
15:24
|
+(36) не точная формула - х1<=х<=x2 y1<=y<=y2, тогда 4 точки: (x1,y1),(x1,y2),(x2,y1),(x2,y2)
|
|||
39
LAAry
07.09.12
✎
15:26
|
(37) так в вызове "ТочкаВходитВРадиус()" то и тратится все время. Нужно запросом, иначе не ускорить.
|
|||
40
LAAry
07.09.12
✎
15:27
|
Можно немного ускорить, заменив обращение к функции на ее содержание. не красиво, но выхлоп будет небольшой.
|
|||
41
GLazNik
07.09.12
✎
15:31
|
(28) Есть немного
(37) так посмотреть в отладчике, на чем основная нагрузка. но скорее всего все будет на вызове функции ТочкаВходитВРадиус. А преобразовывать в удобные для условий значений в момент записи в регистр не предлагать? |
|||
42
mzelensky
07.09.12
✎
15:31
|
(0) попробуй вот это:
Для Каждого Точка из Точки Цикл Если ТочкаВходитВРадиус(Машина.Широта1, Машина.Долгота1, Точка.Широта2, Точка.Долгота2, Точка.Радиус) Тогда ТекТочка = Точка.Ссылка; Прервать; КонецЕсли; КонецЦикла; написать в одну строку. |
|||
43
Ayvengo
07.09.12
✎
15:33
|
(42) что-то слышал про одну строку - это реально ускоряет? :)
|
|||
44
neckto
07.09.12
✎
15:35
|
Что из себя представляют точки? Может машина находясь в точке А попасть в точку С минуя точку Б, которая находится между А и С. Может стоит перебирать не все точки? Если мы знаем, что машина находилась в точке А, то ее следует ожидать в точке Б, остальные точки выкинуть из перебора?
|
|||
45
mzelensky
07.09.12
✎
15:35
|
(43) попробуй :) просто это будет заметно только на очень длинных циклах - как раз твой случай!
|
|||
46
mzelensky
07.09.12
✎
15:36
|
(44) а что мешает машине объехать точку Б..двигаясь от А к С??? Ну скажем по другой дороге?
|
|||
47
LAAry
07.09.12
✎
15:38
|
попробовал бы все же ряды Маклорена :)
математика наше все! |
|||
48
GLazNik
07.09.12
✎
15:38
|
(42) и (43)... не... вы это типа серьезно? то что идет перебор 100000000 строк, это так... мелочи... главное код в одну строку сделать
однозначно нужно выборку сокращать... |
|||
49
mzelensky
07.09.12
✎
15:39
|
(48) ты реально ОЧЕНЬ наивный чувак :) читай по-больше литературы :)
|
|||
50
neckto
07.09.12
✎
15:44
|
(46) Значит машина появится в точке Г, которая рядом с А.
|
|||
51
pumbaEO
07.09.12
✎
15:45
|
||||
52
GLazNik
07.09.12
✎
15:47
|
(49) да и так читаю... вот колобка заканчиваю, за что дальше браться не подскажешь?
|
|||
53
mzelensky
07.09.12
✎
15:48
|
(52) берись за винипуха - многое подчеркнешь для себя :)
|
|||
54
Ayvengo
07.09.12
✎
15:49
|
(46) блин, ребят .. я не хочу рассказывать про бизнеспроцессы.. об этом в любом случае должен быть уведомлен диспетчер. Т.к. маршрут прокладывается по точкам.
(52) не проверишь, пока не поверишь ;) |
|||
55
Азазелло
07.09.12
✎
16:02
|
(23) а формулу упростить не пробовали? во-первых, мне не понравилось, что используются Ш1, Д1, Ш2, Д2, а не разницы между ними. это раз. во-вторых, для твоего случая формулу вычисления расстояний можно и нужно линеаризовывать.
|
|||
56
Йохохо
07.09.12
✎
16:03
|
самый скучный вариант, обойти все ПочтиПриехали(37) СовсемПриехали(0), будет самым быстрым
(37) можно еще оптимизировать сортировкой |
|||
57
Ayvengo
07.09.12
✎
16:05
|
А вот интересно, такое подойдет условие
иксы - это широта, игреки - это долгота. (x-x1)квадрат + (y-y1)квадрат <= Радиус в квадрате? |
|||
58
mzelensky
07.09.12
✎
16:06
|
(57) читай внимательно (33) :)
|
|||
59
acsent
07.09.12
✎
16:06
|
(57) это же тэйбл скан
|
|||
60
LAAry
07.09.12
✎
16:06
|
Ну сам же писал, что это отбрасывание кривизны планеты.
|
|||
61
Азазелло
07.09.12
✎
16:07
|
(57) нет. для того, чтобы использовать данное условие, тебе нужно ШД перевести в х-у, причем, заранее условиться о точке отсчета.
|
|||
62
acsent
07.09.12
✎
16:07
|
(58) это что за хрень в (33)
|
|||
63
Ayvengo
07.09.12
✎
16:10
|
Тогда вопрос, как первести геокоординаты в координаты х, у
|
|||
64
Азазелло
07.09.12
✎
16:13
|
(63) чисто математически - это будет зависеть от того, что ты подразумеваешь под х и у.
|
|||
65
mzelensky
07.09.12
✎
16:15
|
(67) а ты как думаешь?!
|
|||
66
Ayvengo
07.09.12
✎
16:15
|
(64) проблема в том, что разные системы исчисления. Я не знаю как метры в геокоординаты переделать, а геокоординаты в метры.
|
|||
67
Азазелло
07.09.12
✎
16:17
|
(66) метры из радиуса Земли возьмутся )
|
|||
68
mzelensky
07.09.12
✎
16:17
|
(66) блин, чувак....в очереднйо раз - (33)!!!
там 2 точки с координатам. Широта и долгота это значения в "градусы, минуты, секунды" (как в GPS-приемниках)...а далее идет расчет растояния между двумы точками в МЕТРАХ! |
|||
69
pumbaEO
07.09.12
✎
16:18
|
Читай (51) считай координатам хэш, для быстрого поиска входят ли точки в радиус 600 метров ищешь по первым 6 символам, потом по 7 - а дальше уже можешь и кривизну луны или земли или приливы учитывать для определения точно ли машина возле торговой точки.
|
|||
70
mzelensky
07.09.12
✎
16:19
|
(62) а для тебя, недолекий человек, наводящий вопрос - сколько метров в одной секунде (подсказка - секунде вращения земли)?
|
|||
71
Азазелло
07.09.12
✎
16:19
|
(70) а меня в (33) вот эта штука насторожила:
РасчДолгота=РасчДолгота*30.86* cos( Цел(Выборка.ШиротаДока/100) ); эт чО такое? |
|||
72
Азазелло
07.09.12
✎
16:20
|
+(71) точнее, cos( Цел(Выборка.ШиротаДока/100) )
|
|||
73
Азазелло
07.09.12
✎
16:24
|
(66) еще вот эту ветку посмотри: Калькулятор расстояния (гео. координаты А и Б)
|
|||
74
mzelensky
07.09.12
✎
16:28
|
(71) рассказываю - как раз таки 1 секунда вращения земли НА ЭКВАТОРЕ равна 30.86 метров. Но т.к. земля не круг, а элипс - делается поправка на косинус угола широты точки (это для северного полушария). В результате мы получаем сколько метров в одной секунде на вашей широте. У меня, в Краснодаре, это примерно 21 метр!
И ты не поверишь .сколько времени я убил на то ,чтобы решить эту, как казалось бы, элементарнейщую задачку! |
|||
75
Ayvengo
07.09.12
✎
16:32
|
(74) ну тут вообще эту задачу не решить, если учитывать горы ...
|
|||
76
mzelensky
07.09.12
✎
16:34
|
(75) Какие горы? Тут нужно просто определить - попаает одна точка в другую с определенной погрешность (радиусом) или нет. Если радиус маленький (у меня в 33 это 100 метров), то ни о каких горах собственно речь не идет.
|
|||
77
Ayvengo
07.09.12
✎
16:39
|
(76) вот скажи, зачем мне использовать твой метод вхождения, если у меня есть свой уже проверенный и работающий с большой точность. Я хочу оптимизировать цикл в цикле, что бы не было такого, что мне приходится обходить кажду точку для каждого события блока GPS на машине.
|
|||
78
Азазелло
07.09.12
✎
16:43
|
(77)ну извиняйте, это почти как рыбку съесть и ... ну, вы поняли.
вот здесь: http://xpoint.ru/forums/misc/thread/14553.xhtml кстати, очень похожая проблема. |
|||
79
Азазелло
07.09.12
✎
16:45
|
+(78) *с большой точностью
это кто сказал? математически эта формула абсолютно точна. для поверхности шара. а Земля, как известно, не шар. И даже не эллипсоид. |
|||
80
mzelensky
07.09.12
✎
16:45
|
(77) тебе же уже сказали - при твоих условиях ты там особо ничего не оптимизируешь, т.к. в любом случае нужно обходить ВСЕ для ВСЕХ!
Ты же сам говоришь ,что это ОБЯЗАТЕЛЬНОЕ УСЛОВИЕ...Функцию поиска вхождения ты тоже не хочешь трогать ,т.к. она у тебя правильная и точная - так что ты хочешь оптимизировать?! Больше ничего не остается! |
|||
81
Киборг
07.09.12
✎
16:49
|
в запросе можно использовать приблизительную формулу (какую - не знаю), которая могла бы дать значение радиуса с погрешностью сверху
таким образом в запросе будут получены "точки, подозрительные на регистрацию прибытия" :) их проверяешь точной формулой |
|||
82
Ayvengo
07.09.12
✎
16:50
|
(79) ну я об этом и писал в (75)
(80) можно попробовать оптимизировать используя SQL Запрос :Р Там можно синусы, косинусы использовать ... ужс.. чет не хочу я так оптимизировать ))) |
|||
83
Азазелло
07.09.12
✎
16:51
|
(81) для малых значений радиуса вхождения даже уточнять не нужно. если только ТС хочет отсекать погрешности вплоть до миллиметров.
|
|||
84
GLazNik
07.09.12
✎
16:51
|
(77) запросом ограничь выборку разбив местность по "квадратам" с запасом на радиус... и ты получишь, что точка машины находится в квадрате с 10 точками. В результате твой цикл будет в разы короче.
|
|||
85
Азазелло
07.09.12
✎
16:52
|
(82) не, тебе просто нужно от точной формулы перейти к ее аппроксимации для малых значений дельт между Ш и Д.
|
|||
86
Азазелло
07.09.12
✎
16:53
|
+(85) и тогда уже с чистой совестью в условие для левого джойна запихивать. в принципе то, что в (84) предлагают
|
|||
87
GLazNik
07.09.12
✎
16:56
|
(82) сомневаюсь что скульный оптимизатор хорошо проглотит синусы и косинусы. и скорее всего он будет так же тупо для каждой записи одной таблицы перебирать записи другой таблицы. Но да, будет быстрее чем через 1С
|
|||
88
Азазелло
07.09.12
✎
17:05
|
(87) впендюрить врем. табличку со значениями син и кос для углов в диапазоне от 0 до пи с определенным шагом и делать в запросе с помощью этой таблички сплайн-аппроксимации ))
|
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |