\documentclass{article} \usepackage[L7x,T1]{fontenc} \usepackage[utf8]{inputenc} \usepackage[lithuanian]{babel} \usepackage{hyperref} \usepackage{minted} \usepackage{tikz} \usetikzlibrary{positioning} \title{Žemėlapių naršyklės ir elektroninės paslaugos\\ \vspace{4mm} Galutinis semestro egzaminas} \author{Motiejus Jakštys} \date{\today} \begin{document} \maketitle \section{Įžanga} Kaip pasufleruota užduotyje, pagrindinė problema yra bandymas atvaizduoti per daug duomenų vienu metu. Problemos sprendimas dvilypis: vartotojo sąsajoje ir "serverinėje" implementacijoje. Kaip pasufleruota užduotyje, sprendimas dvilypis: vartotojo sąsaja ir serverinis komponentas. \section{Sprendimas} Kadangi problema labai opi smulkiuose masteliuose, pirmiausia nuspręskime, kaip žemėlapį vaizduoti smulkiame mastelyje. Tai atsispindės ir GUI/UX, ir serveriniame sprendime. \subsection{Funkcionalumo keitimas, GUI/UX keitimas} \label{sec:ux} Jei vienoje vietoje (pvz., per 5\% ekrano ploto) yra daugiau, nei du objektai, juos agreguoti ir vietoj pačių objektų rodyti skaičių, kiek tame plote yra objektų. Tada priartinus tuos objektus jie natūraliai atsiskirs. Tai implementuojant reikia apgalvoti šiokias tokias išimtis: pvz., jei ekrane rodoma iš viso mažiau, nei X objektų (tarkime, 42), tuomet agregacijos daryti nereikia, ir rodyti viską taip, kaip buvo "senuoju būdu". Taip užtikriname, kad objektus, kad ir kaip arti vienas kito esančius, visada galėsime pamatyti pakankamai priartinę. Algoritmą, kaip tai padaryti, aprašome skyriuje~\ref{sec:backend}. \subsection{Žemėlapio vizualizacijos modifikavimo/optimizavimo priemonės} \label{sec:api} Šioje sekcijoje aprašome API dalį: į ką pakeisti milžinišką GeoJSON objektą, kad galėtume jį atvaizduoti? Pirmiausia, vartotojas į serverį turi siųsti savo matomo žemėlapio koordinates ({\em extent}). Tada pagal tai serveris nusprendžia, kuriuos duomenis grąžinti tiesiogiai, kuriuos -- agreguotus. Taip kai kurie taškai lieka originalūs, o kai kurie dingsta, ir vietoje jų atsiranda "agreguoti". Agreguoti taškai -- GeoJSON objektai, tačiau su papildomu atributu, kad tai yra "virtualūs" taškai, ir nurodantys, kiek objektų savyje "slepia". Pvz. \begin{minted}{json} { "type": "Feature", "geometry": { "type": "Point", "coordinates": [24.3 55.68] }, "properties": { "aggregated": true, "aggregate_count": 10 } } \end{minted} Paspaudus ant agreguoto komponento būtų patogu, jei atsirastų kitas langas su visais "slepiamais" komponentais, arba žemėlapis taip prisiartintų, kad pasirodytų visi to agreguoto vidiniai slepiami objektai. Grąžinus tik matomą dalį duomenų, serveris visada atsiųs pakankamai mažą kiekį GeoJSON objektų, kurie tikrai neapkraus naršyklės; taip vartotojo sąsaja bus sėkmingai naudotina ir smulkiuose, ir stambiuose masteliuose. \subsection{Esamų servisų modifikavimo ir/ar naujų kūrimo priemonės, įvardinant konkrečius servisus tipus/sprendimus ir juos trumpai pagrindžiant} Dėstytojo nurodymu, ArcGIS Online pakeičiame PostGIS duombaze ir serveriniu ({\em back-end}) komponentu; žr. architektūros diagramą~\ref{fig:arch}. \begin{figure}[H] \centering \begin{tikzpicture}[thick] \node at (0,4)[rectangle,draw=black,fill=yellow!20] (browser) {Naršyklė}; \node at (0,2)[rectangle,draw=black,fill=blue!20] (backend) {Serverinis komponentas}; \node at (0,0)[rectangle,draw=black,fill=blue!20] (gis) {PostGIS}; \draw [->] (browser) to (backend); \draw [->] (backend) to (gis); \end{tikzpicture} \caption{Architektūros diagrama} \label{fig:arch} \end{figure} Pakeitę ArcGIS į PostGIS, atsikratome dirbtinio 2000 objektų ribojimo ir aplikacijoje galime pasiimti tiek duomenų, kiek reikia. Šioje užduotyje taip pat tariame, kad visi, kas įrašinėja objektus, juos rašo į duombazę naudojant GIS įrangą, ir įrašymu mums rūpintis nereikia. Liko neišspręsta viena problema: kaip, turint tūkstančius objektų ir vartotojo "langą" (extent) grąžinti tinkamus PostGIS objektus? Logiką galima dėti į dvi vietas: arba duomenų bazę, arba pačią programą. \subsubsection{Duomenų bazė} \label{sec:db} Programuoti skirstymo duomenų bazėje yra paprasčiau, nei serveriniame komponente. Pavyzdinis, gana naivus, algoritmas, kurį galima parašyti naudojant plpgsql: \begin{itemize} \item parinkti objektus, esančius rėme ({\em extent}). \item padalinti rėmą į reikiamą skaičių dalių (aprašyta~\ref{sec:ux}). Rėmą populiaru dalinti į šešiakampius arba kvadratus. \item kiekvienai daliai grąžinti tikrus arba virtualius objektus (aprašyta~\ref{sec:api}). \item sukonstruoti GeoJSON objektą ir grąžinti vartotojui. \end{itemize} Nors išspręsti problemą duomenų bazėje yra paprasčiau kodo prasme, tačiau duomenų bazės apkrovimas bus didesnis ir kils su naršančiųjų kiekiu. Todėl ateityje, jei duomenų arba vartotojų bus dar daugiau, gali būti sunkiau optimizuoti algoritmus; naudojant tikrą programavimo kalbą (tarkime, C++ arba Go) daug paprasčiau optimizuoti ir užtikrinti norimą servisą augant vartotojų skaičiui. \subsubsection{Serverinis komponentas} \label{sec:backend} Algoritmas gali būti panašus į aprašytą~\ref{sec:db}. Tačiau kaip gauti duomenis? Kadangi objektų kiekis -- tik dešimtys tūkstančių, visus duomenis lengvai galima laikyti atmintyje ir serveriniame komponente analizę leisti su kiekviena užklausa iš naujo. Duomenis atsisiųsti iš duomenų bazės galima reguliariai, tarkime, kas kelias sekundes ar minutę: taip duomenų bazės apkrovimas bus minimalus, ir nekils didėjant skaitytojų kiekiui (didės rašančiųjų kiekiui, bet tokių paprastai būna daug mažiau). Kaip minėta anksčiau, serveriniame komponente lengviau užtikrinti, kad servisas veiks gerai ir su dideliais apkrovimais, ir nereikės didinti duomenų bazių galingumo, kas paprastai yra brangiau ir/arba sudėtingiau, nei aplikacijos. Jei apkrovimai smarkiai didėja, reikia analizuoti ir tobulinti algoritmą. Kelios idėjos optimizacijai: \begin{itemize} \item apskaičiuoti generalizacijas iš anksto kiekvienam įmanomam masteliui ir atėjus užklausai, tiesiog pasiimti jas iš atminties. \item išankstinės optimizacijos, jei skaičiuojamos ne kiekvienos užklausos metu, gali būti leidžiamos ir į duomenų bazę: taip DB apkrovimas nesikeičia su naršančių vartotojų kiekiu. \end{itemize} \end{document}