W katalogu sklepów potrzebowaliśmy jednej rzeczy: „pokaż mi, co jest najbliżej i ile tam jadę”. Brzmi banalnie, dopóki nie policzy się, ile zapytań do zewnętrznego routera generuje przeciągnięcie suwaka odległości.

Dlaczego nie API routingu

Pierwsza propozycja jest zawsze ta sama: odpytać zewnętrzne API przy każdej zmianie. To działa na demo z pięcioma punktami i przestaje działać przy stu użytkownikach naraz. Dostawca blokuje ruch, strona zwalnia, a lokalizacja czytelnika wychodzi na zewnątrz przy każdym ruchu.

Ostatni punkt jest tu najważniejszy. Lokalizacja to dane osobowe, a wysyłanie jej do zewnętrznego dostawcy tylko po to, żeby pokazać „12 minut”, jest kosztem, którego nikt nie policzył.

Co liczymy zamiast tego

Haversine daje linię prostą. Dwie własne krzywe zamieniają ją na kilometry drogą i na minuty jazdy:

  • krzywa nadmiaru drogi nad linią prostą — krótka trasa wije się po mieście, długa idzie ekspresówką;
  • średnia prędkość rosnąca z długością trasy, plus stały narzut na wyjazd i parkowanie.

Obie krzywe są wykalibrowane na 460 realnych trasach samochodowych, od 400 metrów do 500 kilometrów, liczonych prawdziwym routerem — z prawdziwych adresów i z losowych punktów w Polsce.

Ile to się myli

Mediana błędu czasu: 13,6 procent. Na trasach spoza zbioru uczącego: 13,5 procent. Połowa szacunków mieści się w sześciu minutach od wyniku prawdziwego routera.

Najsłabiej wychodzi poniżej pięciu kilometrów, gdzie rzeka albo ulica jednokierunkowa potrafi podwoić trasę. Tam pomyłka to jednak minuta, nie godzina.

Co z tego ma czytelnik

Liczenie dzieje się w przeglądarce, więc lokalizacja nigdzie nie wychodzi. Sortowanie „najbliżej mnie” i suwak odległości działają bez jednego zapytania do serwera. Skrypt kalibracyjny leży w repozytorium, więc wynik da się przeliczyć od nowa i sprawdzić.

Geokoder adresu i router trasy są potrzebne tylko tam, gdzie naprawdę trzeba — i mają własne bariery: jedno zapytanie na raz, odstęp między zapytaniami, pamięć na powtórki (także na zapamiętany brak wyniku) i limit na czytelnika po adresie IP.