Днес ми е последния работен ден в Уисдам. Една работа, която започнах преди точно 12 години. Тогава рязко смених професията и започнах да се занимавам с това което ми харесва – Линукс. И до ден днешен не съжалявам, че го направих. Но беше време за някаква промяна. Някои лични и професионлани проблеми ме принудиха да се огледам за нова работа. От другия месец ще започвам в по-голяма фирма и ще се занимавам с “по-модерни” неща като Cloud, но като цяло основата си остава Линукс. Ще видим как ще ми се отрази промяната, но все се надявам, че ще е за добро. Ето например това ме подтикна да пиша тук след повече от две години пауза 🙂
Category Archives: Работа
Оптимизиране на MySQL заявки при геолокализирано приложение
Навярно повечето от вас знаят, че се занимавам със сайта fuelo.net и на мен се стоварват всички технически проблеми. В този пост искам да споделя два от основните проблемите пред подобен род приложения – силно зависими от местоположението на потребителите, и как съм ги разрешил.
1. Намиране на най-близките N обекта (в нашия случай бензиностанции).
Във fuelo използваме MySQL за основен database и една от първите ми оптимизации беше да upgrade-нем до версия 5.7, където има доста подобрения и готови функции, свързани с геолокацията. Първоначално всички заявки свързани с определяне на бензиностанции наблизо бяха нещо от рода на :
$sql = "SELECT *, (6371 * acos( cos( radians(".$lat.") ) * cos( radians(`lat`) ) * cos( radians(`lon`) - radians(".$lon.") ) + sin( radians(".$lat.") ) * sin( radians(`lat`) ) ) ) AS `distance` FROM `gasstations` HAVING `distance` < ".$distance." ORDER BY `distance` ASC";
забележка: всички примери ще бъдат на PHP, а заявките са опростени (без WHERE и LIMIT клаузи) с цел прегледност.
Както виждате тук дори не се използва stored procedure, а цялата haversine формула се изчислява при всяка заявка. Това при малък ненатоварен сайт с неголяма база данни (напр. до 1000 обекта) на практика работи и се използва доста често. Повечето tutorials в интернет препоръчват именно тази формула. Първата ми идея за MySQL 5.7 беше именно да заменим тази формула с вградената (от версия 5.7.6) функция ST_Distance_Sphere. Така горната заявка се свива до:
$sql = "SELECT *, ST_Distance_Sphere(POINT(`lon`, `lat`), POINT(".$lon.", ".$lat."), 6371) AS `distance` FROM `gasstations` HAVING `distance` < ".$distance." ORDER BY `distance` ASC";
Така изчислението на теория (и на практика) става много по-бързо. Забележете, добавения трети параметър на функцията ST_Distance_Sphere, който преобразува изчислението в km, а не в метри както е по подразбиране. Това ни се наложи, за да запазим съвместимостта със функциите, които извикваха тази заявка, а те очакват резултата в километри.
На пръв поглед всичко изглежда супер, но на практика не е. Тази функция наистина изчислява възможно най-бързо разстоянието между две точки, но не използва индекси и затова все пак трябва да обходи всички редове в таблицата, за да подреди резултатите по разстояние. При все по-голяма база (при нас като наближихме 50000 бензиностанции), тази заявка също започна да става бавна. Започнах да мисля как да огранича резултатите, за които се изчислява разстоянието. Както се вижда от заявките (почти) винаги има ограничение в разстоянието (HAVING `distance` < X) и се зачудих как мога да превърна това X в координати и така да огранича резултатите още преди да започне изчислението и сортирането. Така намерих тази статия (Finding Points Within a Distance of a Latitude/Longitude Using Bounding Coordinates by Jan Philip Matuschek), в която на теория много добре е описан точно моя проблем. Има и source код на Java, както и линкове за други програмни езици, включително и PHP. Това беше точно каквото ми трябваше. Като използвам тази библиотека кода придобива следния вид:
$edison = Geolocation::fromDegrees($lat, $lon);
$coordinates = $edison->boundingCoordinates($distance, 'km');
$lat_min = $coordinates[0]->getLatitudeInDegrees();
$lon_min = $coordinates[0]->getLongitudeInDegrees();
$lat_max = $coordinates[1]->getLatitudeInDegrees();
$lon_max = $coordinates[1]->getLongitudeInDegrees();
$sql = "SELECT *, ST_Distance_Sphere(POINT(`lon`, `lat`), POINT(".$lon.", ".$lat."), 6371) AS `distance` FROM `gasstations` WHERE `lat` > '".$lat_min."' AND `lat` < '".$lat_max."' AND `lon` > '".$lon_min."' AND `lon` < '".$lon_max."' HAVING `distance` < ".$distance." ORDER BY `distance` ASC";
Така вече заявката беше доста по-бърза, обхождаше доста по-малко редове, което подобри работата на MySQL и сървъра като цяло. Аз обаче не се спрях до тук. Хрумна ми как да се възползвам от spatial индекса на MySQL. Първо направих ново поле в таблицата gasstations с име coords и тип POINT. Попълних новото поле от другите две полета, които вече имах, lat и lon , чрез заявката UPDATE `gasstations` SET coords = Point(lon, lat);
и след това направих полето spatial index. След тази промяна бях готов за последната ми (за сега) SQL заявка за намиране на най-близките бензиностанции:
$edison = Geolocation::fromDegrees($lat, $lon);
$coordinates = $edison->boundingCoordinates($distance, 'km');
$lat_min = $coordinates[0]->getLatitudeInDegrees();
$lon_min = $coordinates[0]->getLongitudeInDegrees();
$lat_max = $coordinates[1]->getLatitudeInDegrees();
$lon_max = $coordinates[1]->getLongitudeInDegrees();
$sql = "SELECT *, ST_Distance_Sphere(`coords`, POINT(".$lon.", ".$lat."), 6371) AS `distance` FROM `gasstations` WHERE ST_Within(`coords`, ST_MakeEnvelope(Point(".$lon_min.", ".$lat_min."), Point(".$lon_max.", ".$lat_max."))) HAVING `distance` < ".$distance." ORDER BY `distance` ASC;
Същността тук е функцията ST_Within(), която се възползва от spatial index-а на coords и филтрира резултатите още по-бързо. Функцията ST_MakeEnvelope създава “квадрат”, по две крайни точки, в който се ограничава търсенето.
За сега това ми е решението за намиране на най-близките бензиностанции. Не мога да дам сравнителни стойности, защото междувременно условията много се променяха, но на практика нещата вървят много по-добре. Бавните заявки намаляха и натоварването на сървъра спадна.
2. Изобразяване на голям брой обекти на карта
Във fuelo използваме Google Maps за визуално представяне на бензиностанциите на карта. В началото беше лесно – малко обекти – просто показвай всички на картата. След време, както всички, започнахме да използваме js marker clusterer. Така обаче прехвърляме тежките изчисления върху клиента и когато той реши да unzoom-не за да види всички бензиностанции в Европа, може направо да му забие browser-а и/или компютъра. Започнах да търся сървърно решение за clustering на обекти. Решението, което използваме в момента, се нарича geohash. MySQL поддържа geohash функции и с тяхна помощ заявката за server-side clustering става нещо подобно:
$sql = "SELECT `id`, `brand_id`, AVG(lat) as avglat, AVG(lon) as avglon, substring(`geohash`, 1, ".$precise.") as cluster_hash, count(*) as cluster_count
FROM `gasstations`
WHERE ST_Within(`coords`, ST_MakeEnvelope(Point('.$lon_min.', '.$lat_min.'), Point('.$lon_max.', '.$lat_max.')))
GROUP BY `cluster_hash`";
За целта Ви трябват няколко неща:
- поле geohash (при мен VARCHAR(9) ) в таблицата gasstations, което предварително е попълнено със ST_GeoHash() функцията (и не забравяйте да го update-вате винаги, когато промените координатите на обекта ! )
- $lon_min, $lat_min, $lon_max и $lat_max , които лесно може да вземете за видимата част на картата от google maps API-то
- $precise – колко прецизно да е клъстерирането. Основно зависи от zoom level-а на картата и може да си го нагласите според вашите нужди
При изпълнение на заявката получавате всичко необходимо за визуализиране на картата и не е необходимо на използвате client-side clustering:
- cluster_count е броя обекти в клъстера – ако е 1, значи е само една бензиностанция и може да покажете пинче в зависимост от нейната brand_id. Ако е повече от 1 значи има повече от една бензиностанция в района и показвате клъстерна иконка с цифричка cluster_count, която показва броя.
- avglat и avglon са средноаритметично от координатите на бензиностанциите и така може да позиционирате клъстерната иконка на “по-правилно” място. Иначе, от самата специфика на geohash алгоритъма, Земята се разделя на правоъгълници и клъстерите Ви ще се наредят като в решетка. Разбира се ако cluster_count e 1, avglat и avglon са координатите на самата бензиностанция.
Това са решенията и заключенията до които стигнах за тези два проблема и ще се радвам, ако съм полезен на някой.
Ново начало
Преди около две седмици с мен се свързаха едни хора, които проявяваха интерес към моя сайт fuelo.net. След няколко срещи, през тези две седмици, се стигна до днес, когато създадохме “Фуело ООД”. Така вече съм съдружник във фирма, за първи път, и то със хора, които на практика не познавам. Общо сме 5 човека, като е хубаво, че всеки е силен в различна област и вярваме, че заедно може да постигнем нещо голямо. За мен най-хубаво, е че Фуело ще може да реализира някои мои идеи, които беше немислимо да се справя сам. Днес беше само началото, от утре започваме да реализираме мечтите си.
В Девин съм
Този уикенд още от петък съм в Девин. Повода е нещо като teambuilding на фирмата. Дори сме в един доста гъзарски хотелски комплекс – Исмена. Има басейн, сауна, фитнес … а ние сме в едни доста готини къщички.
Аз нещо не се блазня от всички тези глезотийки и днес си взех сноуборда и отидох в Стойките да карам, въпреки че навън беше над 10°C. За всеобщо учудване имаше сняг и съм доста доволен от каране като цяло. Снега беше мокър, но това го правеше „бавен“ и се пробвах на някои писти, които друг път не бих посмял да се пусна. И ги минавах много добре 🙂 Освен това нямаше много хора и въобще не съм чакал на лифтове. Направих много спускания и накрая доста се поизморих, въпреки, че бях само за следобяд. Накрая само паднах по-лош и сега ме боли коляното, но се надявам да ми мине бързо.
Работа, работа
Измина една доста натоварена за мен седмица. За който не знае отново имам пълнодневна работа, обаче още от първата седмица ме хванаха яко. То така се случи де, просто имаше много проблеми. То не бяха падане на сървъри, оправяне на сървъри, местене на сайтове през нощта, работа през уикенда … заедно със всички останали ежедневни грижи. Да не говорим че нещата, с които се бях захванал докато нямах работа, сега стигнаха до етапа, когато наистина трябва да се свършат и с това също съм се занимавал. У нас е заприличало на малко сървърно 🙂 Дори си купих още един комутатор, а една вечер няколко часа съм кримпвал кабели.
Не се оплаквам. Просто споделям и си записвам тук за историята 🙂
В Telepoint
След уикенда в София, реших да го съчетая с малко работа в понеделник. От много време отлагахме да направим една профилактика на сървърите на място. Така, чак сега за първи път ми се случи да се “запозная” на живо с сървърите ни в Телепойнт. Идеята беше да рестартираме сървъри на по 500-600 дни uptime и да видим кои няма да тръгнат … т.е. fun 🙂 Е, имах и други задачи, като да сменя малко дискове, сменя малко кабели, преконфигурирам KVM-и и т.н. Като цяло си мислех, че е работа за 3-4 часа, но естествено съвсем не стана така. Очакваните проблеми се появиха, доста сървъри не тръгнаха … въобще както казах – беше весело. В крайна сметка останах до след 18 часа, т.е. си изкарах цял работен ден там. Като цяло от Телепойнт са направили готин datacenter, само където оборудването им беше малко ръчно сглобено – ползвах един стар CRT монитор с удължен кабел (връзката между двата кабела, за да не се разделят лесно, по традиция беше затегната със свинска опашка), който оставях директно на земята, и една клавиатура (свързана по същия начин). Всъщност на мен ми беше забавно, защото не отнесох цялата работа, т.е. аз бях основно support, а колегите оправяха проблемите. Аз само каквото не можеше отдалечено.
Другото, което ми беше интересно, е че докато оправях разни сървъри по разни rack-ове, видях част от старите сървъри на host.bg (нашите и техните сървъри са малко омешени). Видях beeblebrox и megamosh, сървъри на които преди доста време съм си хоствал разни неща. Ех, спомени.
Джаз концерти и Handmade ден
Измина една дъждовна и студена седмица. Аз я запълних с културни мероприятия. Основно беше Пловдив джаз фест 2010 в драматичния. В четвъртък, първия ден от фестивала, започна много силно. Дори за мен си остана най-добрия ден. Върха на програмата бяха Теодосий Спасов със Kai Eckhardt и Trilok Gurtu. Особено индиеца ни разби всички, свирейки на всякакви ударни инструменти (включително една метална кофа с вода), перкусии и импровизирайки с уста. Германеца-мулат също ме впечатли какви звуци успя да извади от бас китарата си. Въобще беше много яко, въпреки че все пак джаза не ми е най-любимата музика. Просто за пореден път се убедих ,че си струва да се ходи на концерти на живо, независимо какви. Първият проект за вечерта също се представи много добре. За финал на вечерта отидохме в Петното, обаче се оказа, че там няма да свирят същите хора от драматичния и не слязохме долу. Само хапнахме в ресторанта и след това изпихме по едно-две в бара. Получи се приятно.
Втората вечер на фестивала, ме изненада, че имаше много свободни места. За разлика от първия ден, когато залата беше препълнена. И честно казано имаше защо. Може би беше най-джаз вечерта и може би затова не ми хареса. Дори голямото име Chico Freeman не можа да ме задържи до края и си тръгнахме преди края на концерта. След това Дарко ми разказа, че и зад сцената Chico се е държал много глупаво. Ние отидохме в XIX век, където едни приятели на Елица гледаха мача и беше доста голяма културна промяна за нас – от джаз концерт на кръчма 🙂 Все пак беше забавно – лафове след лафове. На тръгване до вкъщи осъзнах, че наистина е станало доста студено, направо зимно време. Не искаааам !
Третата вечер отново ми хареса 🙂 Първо бяха Percussion impact project, коато се състои от Христо Йоцов, Стоян Янкулов и Милен Кукошаров. Двама барабанисти на една сцена е леко странно, но двама много добри барабанисти правят нещата много по-различни. Наистина ни показаха урок по барабани. Клавира само допринасяше за малко по-мелодично звучене в целия проект. За финал на фестивала бяха Акага, но със специално изпълнение на кавъри на Chicago в друг аранжимент. Много добре се справиха. Допринесоха за малко вокалност в целия фестивал 🙂
Стига толкова за джаз. Малко за Handmade деня в събота. Номер 10 по ред ! Юбилеен, слънчев (за щастие слънцето се показа в събота), много пълен (с хора, музика и неща), весел (с огромна торта и танци). Въобще получи се много добре ! Събитието започва да става все по-голямо и по-голямо. Очаквайте скоро снимки 🙂
Неделният ден 10.10.10 използвах за наспиване. Проспах 10:10 и се събудих чак след обяд, след което видях че навън отново е грейнало слънце и веднага се запътихме към Бойково. Първо на скалата, докато се скри слънцето и после в кръчмата 🙂 Така вкусно завърши и тази седмица изпълнена с неща.
Само на работата ми нещата нещо не вървят и се стигна до там че да си търся друга работа или друг доход. Ако имате нещо като за мен или някаква идея, за която мислите че мога да помогна да се осъществи – свиркайте. Все ще намерите как да се свържете с мен.
Teambuilding край Крушуна
След като разбрах че от фирмата ни организират тиймбилдинг край Крушуна въобще не му мислих много. Така този уикенд бях на това хубаво място отново. Вчера като пристигнах дори установих, че го организира същата фирма (Алпийски клуб Еделвайс), при която ни беше предишния тиймбилдинг миналата година в Карлуково. Отново видях Яна и Христо от организаторите, с които се бях видял и лятото на Кара Дере. И този път ни бяха подготвили интересни и разнообразни екстремни и логически задачи. Имаше скално катерене, спускане, лодки в пещерно езеро, ориентиране по карта и компас, разгадаване на кодове и други. Всичко се въртеше около Деветашката пещера и продължи 6-7 часа. Съвсем не малко – привършихме към 8 часа вечерта и вече се стъмваше.
За вечерта имахме наета къща в село Кърпачево, което е на 4-5 километра от Крушуна. Самата къща беше много хубава. На края на селото, няма къщи в непосредствена близост и на един склон, така че гледката към планини и полета е зашеметяваща. За съжаление нямахме време да й се нарадваме. Прибрахме се след изморителния тиймбилдинг почти на стъмване, след като цял ден не бяхме яли, направихме си вечеря на барбекюто в двора. Имаше много хубав навес навън с голяма маса и камина оборудвана със всичко. Цялата къща си имаше всичко необходимо. Повечето заспаха рано, само със Стойчо довършихме бутилката уиски пред камината и откарахме до 2-3 часа.
На сутринта нещо и събуждането на другите беше трудна задача, затова ние от колата на Стойчо решихме сами да отидем до Крушунските водопади и да ги разгледаме (общо взето само аз бях ходил преди това). Установих че са ги комерсиализирали дори още повече от колкото когато бях преди 3 години. Вече си има постоянни бира-скара, маси, сергии с джунджурии … а върха на всичко е че вече има входна такса да разгледате водопадите от 1 лев ! Има някакъв човек, който къса билетчета и разказва на бързо какво може да се види. Въпреки всичко това водопадите са си все така красиви и ги препоръчвам да ги видите, ако не сте го направили до сега. Особено сега през пролетта бяха доста пълноводни. Истинска красота.
След като се върнахме в Кърпачево имахме време само да подредим и изчистим къщата и трябваше да тръгваме към неделното ни занимание – спускане с лодки по река. Затова казах, че въобще нямахме време да се насладим на къщата и спокойствието около нея. Спускането беше по-скоро туристическо гребане на надуваеми лодки. Повечето време беше спокойно, но имаше един момент в който за малко се обърнем. Иначе се намокрихме стабилно. Не само че пръскаше и влизаше вода от реката, но и валеше почти през цялото време. Иначе беше страшно красиво. Минахме и видяхме места, до които няма път и трудно може да се видят. Тръгнахме по река Осъм близо до село Умаревци и излязохме до един изоставен газодобивен център малко преди село Александрово. Общо взето 2-3 часа гребане не е малко за неподготвени хора. Ако поне беше пекнало малко слънце след като слязохме от лодките щеше да е по-добре да поизсъхнем, но уви. Преоблякохме се целите, само където аз нямах резервни обувки, което беше голяма грешка, и в колата на връщане си стоях по чорапи 🙂
Въпреки всички премеждия, всички останахме много доволни. Точно ето такива преживявания остават спомен за цял живот.
допълнение: ето снимки от крушунските водопади.
6 януари 2010
Днес най-сетне от Адроит ми смениха изгорелия хард диск. Сега отново инсталирам – реших да сложа на ново операционната система, така че инсталирам ArchLinux на чисто от доста време (разбирайте години) насам. Пиша това, докато чакам да се копират данните от бекъп диска ми. Скоро се надявам да се върна в нормално състояние, без да мисля, че нямам място да запиша нищо никъде. В момента дори снимките от новия ми фотоапарата си стоят само на SD картата … и по разни компютри на приятели 🙂
Тиймбилдинг край Карлуково
В петък от новата ми работа ме поканиха на тиймбилдинга през уикенда. На мен вече ми беше пропаднало ходенето до Райското пръскало, така че бях свободен. След като разбрах, че става дума за по-екстремно преживяване и спане на палатки, просто нямаше как да откажа. Единствения леко кофти момент беше, че в събота сутринта трябваше да съм в 6 часа в офиса.
Пристигнах на уреченото място и време. Принципно нямаше нужда от моята кола си мислех че ще се наспя, но като се събрахме се оказа, че Сребрин е спал само час и половина (след нощ с някакви каучсърфърки по барове) и така аз карах. Бяха ни казали, че срещата ни е в Луковит. Трябваше да стихнем до 9:30, но имахме проблем със спирачките на едната кола и стигнахме към 10. Там ни посрещна един човек, който каза, че трябва да продължим още 7-8 километра до мястото. А “мястото” се оказа, националния пещерен дом до Карлуково, който аз много добре знаех от едно ходене преди почти пет години.
Тиймбилдинга започна леко скучно от типа хайде сега всички да се запознаем и да се раздвижим леко. След това измислихме име на отбора като половината трябваше да намислят прилагателно, а другата половина съществително и се получи доста глупавото “бяла жена”, но кой за каквото си мисли. Дори си направихме знаме на отбора на един плат със спрейове и маркери.
Всички препятствия (естествено) бяха организирани под формата на приключенска игра от типа намери съкровището. Тук вече стана интересно. Едно от нещата които ми хареса като цяло беше, че за основа беше използвана местна легенда за съкровище, скрито от монасите от скалния манастир край Карлуково. Дори накрая организаторите ни питаха дали е трябвало да бъде нещо в стил Властелина на пръстените, но ние казахме твърде не – местните легенди са си много по-добре и опознаваш още по-добре района.
Взехме първия лист с упътвания и тръгнахме към пещера Проходна, където някакви французи снимаха филм на праисторическа тематика и всъщност бяха затворили пещерата (което е доста тъпо!). Имахме доста разправии с охраната, докато влезем. Наистина вътре имаше струпана доста бутафория, но ние нищо нямаше да счупим … а и си търсихме следващото писмо. Както и да е – в крайна сметка успяхме. След това последваха построяване на жива пирамида от хора на три етажа (аз бях един от най-долните – ужасно беше), леко скално катерене в редица, хванати с едно въже, ориентиране с компас (по зададен азимут), спускане (по-точно прелитане) по въже между два склона на каньон ала Тарзан (отдолу си беше голяма пропаст), промъкване в пещери през едни тесни отвори, където трябва да лазиш само с челник (ако бях сам никога не бих си помислил да продължа напред), междувременно имаше доста трудни логически задачи (всъщност това май се хареса на всички – задачките съвсем не бяха елементарни, трябваше доста да напънем 11 програмистки мозъка), вертикално спускане с въже от над 40 метра (това го сметнахме, че е все едно да се пуснеш от 13-я етаж на някой блок) към едно езеро (в крайна сметка стъпваш точно на брега, но от високо не изглежда така), ходене из гора по карта, още ходения и почти лазения в пещери, гребане няколко километра с надуваеми лодки по Искър (с всичките му там бързеи, мостове и т.н.), търсене на бутилка в реката … и всичко това за да стигнем до крайното ковчеже, което да отключим с десет (!) ключа и вътре имаше най-прекрасната топла бира на света, която бях пил ! Общо всичко това за около 6 часа и накрая всички бяхме много доволни. Много добър тиймбилдинг. Браво на организаторите Христо и Яна от Алпийски клуб Еделвайс, които са много готини хора.
Вечерта бяхме на палатки, като аз си носех моята и моя спален чувал и си ми беше много добре. Дори бях сам, а дъжда който ни заваля, макар че беше за кратко, беше доста силен, въобще не го усетих вътре. Някои от другите палатки протекоха доста. Аз както имах доста енергия, изведнъж капнах и си легнах сравнително рано.
На сутринта останалата част от тиймбилдинга беше пейнтбол. До сега не бях ходил и ми беше интересно да пробвам. Въпреки, че не си падам много по подобни игри, ми беше готино. Най-хубавото, може би беше, че се организираше в една горичка близо до палатките – истинска среда, без никакви бутафории. Изиграхме няколко игри, но в крайна сметка май слънцето ни измори повече – с тези дрехи и маски се сварихме и капнахме.
След пейнтбола си тръгнахме към Пловдив. По пътя само спряхме да хапнем в един крайпътен ресторант и успяхме да се приберем малко преди да завърши изборния ден и гласувах. Ей така както си бях с голяма раница на гърба, влезнах в изборната секция и си пуснах бюлетините.