Работа с клъстери при търсене на точки на карта с помощта на mysql

Намерих различни въпроси с решения, подобни на този проблем, но нищо съвсем за парите досега. Много благодарен за всяка помощ.

Имам база данни mysql (v.5.6.10) с една таблица, наречена POSTS, която съхранява милиони и милиони редове от интересни точки по ширина/дължина на карта. Всяка точка се класифицира като един от няколко различни типа. Всеки ред е структуриран като id, type, coords:

  • id an unsigned bigint + първичен ключ. Това се увеличава автоматично за всеки нов ред, който се вмъква.
  • type an unsigned tinyint използван за кодиране на типа на интересната точка.
  • coords mysql геопространствен POINT тип данни, представляващ ширината/дължината на интересната точка.

Има индекс SPATIAL за „коорди“.

Трябва да намеря ефективен начин да направя заявка в таблицата и да върна до X от най-скоро вмъкнатите точки в радиус („R“) на конкретна позиция по ширина/дължина („ Позиция"). Базата данни е много динамична, така че, моля, приемете, че данните са радикално различни всеки път, когато таблицата се запитва.

Ако X е безкрайно, проблемът е тривиален. Просто трябва да изпълня заявка като:

SELECT id, type, AsText(coords) FROM POSTS WHERE MBRContains(GeomFromText(BoundingBox, Position))

Където „BoundingBox“ е тип данни на mysql POLYGON, който идеално затваря кръг с радиус R от позицията. Използването на ограничителна кутия, разбира се, не е идеалното решение, но това не е важно за конкретния проблем, който се опитвам да разреша. Мога да подредя резултатите с помощта на „ORDER BY ID DESC“, за да извлека и обработя първо най-скоро вмъкнатите точки.

Ако X е по-малко от безкрайно, тогава просто трябва да променя горното на:

SELECT id, type, AsText(coords) FROM POSTS WHERE MBRContains(GeomFromText(BoundingBox, Position)) ORDER BY id DESC LIMIT X

Проблемът, който се опитвам да разреша, е как да получа добър представителен набор от резултати от даден регион на картата, когато точките в този регион са силно групирани (например в рамките на градове в региона за търсене на карта). Например:

въведете описание на изображението тук

В примера по-горе аз стоя на X и търся 5-те най-скоро вмъкнати точки от тип черно в рамката с черна рамка. Ако всички тези точки бяха вмъкнати в клъстера в долния десен ъгъл (да приемем, че клъстерът е Лондон), тогава моят набор от резултати няма да включва черната точка, която е близо до горния десен ъгъл на областта за търсене. Това е проблем за моето приложение, тъй като не искам потребителите да остават с впечатлението, че няма интересни точки извън зони, където точките са групирани.

Обмислих няколко потенциални решения, но не мога да намеря такова, което да работи ефективно, когато броят на редовете е огромен (десетки милиони). Подходите, които съм опитвал досега, включват:

  1. Разделяне на областта за търсене на S брой квадрати (т.е. превръщането му в решетка) и търсене на до x/S точки във всеки квадрат - т.е. изпълнение на отделна mysql заявка за всеки квадрат в мрежата. Това работи добре за малък брой редове, но става неефективно, когато броят на редовете е огромен, тъй като трябва да разделите региона на голям брой квадрати, за да работи подходът ефективно. Само с малък брой квадрати не можете да гарантирате, че всеки квадрат няма да съдържа гъсто населен клъстер. Големият брой квадрати означава голям брой търсения в mysql, което кара нещата да се забиват.

  2. Добавяне на колона към всеки ред в таблицата, която съхранява разстоянието до най-близкия съсед за всяка точка. Най-близкото съседно разстояние за дадена точка се изчислява, когато точката се вмъкне в таблицата. С тази структура след това мога да подредя резултатите от търсенето по колоната за разстояние на най-близкия съсед, така че всички точки, които са в клъстери, да се връщат последни. Това решение работи само когато търся ВСИЧКИ точки в района на търсене. Например, разгледайте ситуацията в диаграмата, показана по-горе. Ако искам да намеря 5-те най-скоро вмъкнати точки от тип зелено, най-близкото съседно разстояние, което се записва за всяка точка, няма да е правилно. Преизчисляването на тези разстояния за всяка заявка ще бъде твърде скъпо, дори при използване на ефективни алгоритми като KD дървета.

Всъщност не мога да видя никакъв подход, който изисква предварителна обработка на данни в редовете на таблицата (или, казано по друг начин, „докосване“ на всяка точка в съответния набор от данни за регион на търсене), за да бъде жизнеспособен, когато броят на редовете стане голям. Обмислях алгоритми като k-средства / DBSCAN и т.н. и не мога да намеря нищо, което да работи с достатъчна ефективност, като се има предвид случая на използване, обяснен по-горе.

Някакви бисери? Моята интуиция ми казва, че това МОЖЕ да бъде решено, но досега съм объркан.


person Al Mann    schedule 10.06.2013    source източник
comment
Ако трябва да покажете само 5 места, защо чувствате необходимостта да намеквате за съществуването на горното вдясно? Какво ще кажете за използването на по-очевиден цвят и икона на клъстер за първите 5 случая и първо ги групирайте, а след това останалите. Направих този подход в Google Maps.   -  person Robin Castlin    schedule 10.06.2013


Отговори (1)


Постобработката в този случай изглежда по-ефективна. Извличане на последните X точки от даден тип. Открийте дали има някакво групиране, например: твърде много точки, твърде близо една до друга, спрямо разстоянието на вашата гледна точка. Пуснете най-старите от тях (или тези, които са много близки - може вашите данни да препращат към една и съща POI). Колко - решавате вие. Извлечете следващите X точки и вижте дали има някои от тях, които не са в клъстера, или можете да изчислите стойност за всяка от тях въз основа на отдалеченост и скорошност и да изхвърлите точки според тази стойност.

person pl71    schedule 10.06.2013
comment
Благодаря - това ми даде някои идеи. По принцип се опитвам да спра точките извън клъстерите (така наречените „шумни“ точки) да бъдат елиминирани от резултатите от търсенето. Ще се опитам да извлека първоначална партида от X точки от региона за търсене (както е предложено) и след това да извърша ново търсене в същия регион, но като отделя области, заети от клъстери (ако има такива), идентифицирани в първата партида (напр. чрез изключване на изпъкналата обвивка на всеки клъстер или нещо подобно). Повторете, докато търсенето не разкрие повече клъстери. Стискам палци. - person Al Mann; 15.06.2013