Como eu tentei consertar uma pesquisa no mapa por drivers

Esta é uma história sobre como tentei resolver um problema estranho que me impedia. Olhando para o futuro, direi que estou satisfeito com a solução resultante e levei o aplicativo ao seu fim lógico. No entanto, para executá-lo completamente, você precisa de mais recursos, então decidi fazer uma pausa e perguntar às pessoas se mais alguém precisava. Para esse fim (e também apenas para falar), escrevo aqui.

Duas palavras sobre mim: moro em Dublin, Irlanda, trabalho como programador. Não fica exatamente no local, por isso, no meu tempo livre em casa, vi vários projetos, principalmente sobre a mesa. Escrevo sobre Habré pela primeira vez, apesar de ler por muitos anos.

O problema


Há muito tempo, quando tive que viajar muito para lugares desconhecidos para trabalhar, comecei a perceber que a pesquisa padrão em qualquer cartão não é absolutamente aplicável hoje aos motoristas. Veja: você está dirigindo em uma área desconhecida e tem uma flecha de gasolina em zero. Suas ações? Se naquele momento não estou sozinho no carro, digo ao passageiro: "Bem, procure um posto de gasolina por perto enquanto eu dirijo". Porque se você fizer você mesmo, precisará executar as seguintes ações:

  1. Para parar
  2. No aplicativo de mapa, digite "gasolina" na pesquisa (ou clique em um dos botões rápidos que alguns cartões oferecem agora)
  3. O aplicativo faz uma pesquisa e mostra um mapa enorme com uma dúzia de postos de gasolina
  4. Você tenta descobrir qual é o mais próximo a você e clica nele para criar uma rota

Na minha opinião, um pesadelo. Em primeiro lugar, você precisa parar ou pelo menos esperar por um semáforo. Porque os cartões são complexos e os ícones são pequenos. Em segundo lugar, o cartão nifig não informa qual é o posto de gasolina mais próximo. A esse respeito, o Google é o pior de tudo: mesmo nos resultados na forma de uma lista, ele teimosamente empurra não o lugar mais próximo e os mais cotados / com fotos / pagos / não faço ideia.



Bem, o terceiro fator: estamos nos movendo. O resultado que os cartões emitidos foi relevante em algum momento, mas já estamos longe disso. Você notou que mesmo a rota estabelecida pelo Google não é atualizada automaticamente se mudarmos? Somente se a navegação já tiver sido iniciada, ela será reconstruída.

Em geral, o problema é claro. Lógica que funciona para pedestres e suas necessidades, para motoristas, não é nada. Eu não me importo com a classificação do local e que tipo de cozinha - eu preciso, sem me distrair da estrada, em tempo real, obter uma rota para o posto de gasolina, carga, estacionamento, caixa eletrônico, etc. mais próximo

Idéia


Agora vamos tentar determinar o cenário de pesquisa ideal. O critério é o seguinte:

  • a interação é curta e clara para não distrair o motorista
  • saída à distância transparente
  • atualização em tempo real

A primeira coisa que implora é substituir a pesquisa única padrão por uma varredura. Ou seja, a cadeia de ações é algo como isto:

  1. Lançou uma varredura
  2. Passeio, olhando para resultados atualizados em tempo real
  3. Quando gostei de algo, cliquei e pavimentei a rota

Você determina os critérios de pesquisa com antecedência - na verdade, esse é o tipo de local e o raio da verificação. Além disso, enquanto o carro está em movimento, o aplicativo funciona como um radar. Muito rapidamente ficou claro que, em primeiro lugar, o raio não é redondo, mas na forma de uma isolinha. Em segundo lugar, deve ser construído não pela distância, mas pelo tempo, porque os minutos são muito mais fáceis de perceber do que os quilômetros.

Então pensei em uma maneira de produzir os resultados. Mais precisamente, preciso de um cartão? O motorista olha para o aplicativo com um olho e interage com um dedo - ele não precisa de um mapa, mas de um texto grande e de botões grandes. Portanto, decidi imediatamente que a tela principal seria uma lista, e posso adicionar um mapa primeiro e depois ver se devo deixá-lo.

Planejar


Conhecendo minha própria peculiaridade de esticar projetos, decidi me dedicar 2 meses para tudo - no final, encontrei no 3. Em princípio, a aplicação é bastante simples:

  1. Cliente de um par de telas (pesquisa, lista e mapa)
  2. Periodicamente envia ao servidor suas coordenadas, raio de busca e tipo de locais
  3. O servidor constrói um isoline no tempo (a propósito, ele tem seu nome em inglês - isochrone), faz uma pesquisa em locais e retorna uma lista

Soa como um pulmão mais leve. Eu já tinha alguma experiência anterior em cartografia (alguns anos atrás, eu criei um portal imobiliário onde a pesquisa estava no mapa), então a pilha no back-end ficou imediatamente clara:

  • importar dados do OpenStreetMaps para o Elasticsearch
  • OpenTripPlanner para construção de contornos

No cliente, pensei, decidiu usar a nova estrutura do Google - Flutter. É multiplataforma, bastante flexível e permite criar aplicativos completos com um mínimo de código. Obviamente, é cru e não está claro o que está em produção, mas parece perfeito para a criação de protótipos. Deve-se esclarecer que, naquele momento, eu tinha experiência em desenvolvimento nativo para android (eu era um líder de equipe) e decidi, por assim dizer, enfrentar o inimigo. O inimigo não era tão assustador.

Implementação


O primeiro aplicativo de protótipo ficou pronto muito rapidamente - o Flutter possui um limite de entrada baixo e uma filosofia de redux compreensível. Curiosamente, a descrição declarativa das interfaces também foi agradável, bem como a reinicialização a quente (React Native, seu bitmap). Em geral, a impressão era de que o Google era responsável pela maioria das doenças congênitas de tentativas anteriores. No entanto, eu entendo pessoas que podem não querer entrar nisso - alguém não gosta de dardo, um número limitado de widgets e a "depuração visual" oferecida aqui é algo muito cru.

No back-end, fiz o seguinte:

  1. Entregou o Nominatim, carregou a extração de dados do OpenStreetMaps (obtida aqui ) em seu banco de dados, usando seu utilitário osm2pgsql padrão. Por que me virei para o pequeno, mas muito agradável, geocoder de código aberto Photon . Anteriormente, eu já o usei em alguns projetos - ele gera um índice Elasticsearch, importa dados do banco de dados Nominatim e pesquisa esse índice. Gosto com velocidade e mapeamento puro (por exemplo, tentei Pelias e gostei menos). Seu principal problema é a versão antiga do elástico, mas no meu caso eu não precisava da funcionalidade do geocoder, apenas dos dados; portanto, após a importação, transferi o índice para a instalação da versão mais recente do elástico com alma pura. A propósito, por que escolhi o Elasticsearch? É muito rápido e tem a função de encontrar coordenadas por polígono.
  2. O aterro - também conhecido como isócrona - gerou inicialmente o OpenTripPlanner para mim. Este é um bom planejador de rotas de código aberto. Funciona da seguinte maneira: pega o mesmo extrato do OpenStreetMaps e o compila em um grande gráfico de estradas, que, como um objeto separado, é salvo no disco. Quando o servidor inicia, este gráfico é carregado na RAM e todas as rotas são pesquisadas nele. Prós: escolha rapidamente, funcionalidade rica (por exemplo, gera contornos da caixa) e boa velocidade. Contras: essa velocidade depende da quantidade de RAM e a documentação é extremamente nojenta. Apenas documentação monstruosa. Flashbacks vietnamitas.
  3. Joguei uma pequena API no python, que pega o tipo de local e o raio da pesquisa em segundos, solicita um polígono do OpenTripPlanner e, em seguida, procuro no Elasticsearch. Ele solicita uma rota para cada local encontrado (novamente no OpenTripPlanner), leva seu tempo e duração. Depois disso, todos os dados coletados são lindamente empacotados e retornados.

Fiz a atualização dos resultados deslocando as coordenadas do dispositivo em 5 metros. O mapa é estático - eu apenas usei APIs de mapas estáticos do Google (como você pode ver, este é o único lugar em que a corporação, no entanto, entrou no nosso aconchegante mundo aberto). A primeira implementação ficou assim:







Depois de jogar com o aplicativo, decidi ocultar o mapa. Ela fez um bom trabalho para entender em que polígono a pesquisa foi feita e parecia divertida - foi interessante observar como esse polvo muda de forma em tempo real. No entanto, esse entretenimento não ajudou o aplicativo a cumprir suas funções e ocupou um terço da tela.

Também me ocorreu adicionar uma seta, que indicava a direção de cada resultado. Funcionou assim:

  1. Lembre-se de suas coordenadas anteriores
  2. Ao mudar, colocamos a rota da posição anterior para a atual
  3. Tomamos o último segmento da nossa rota e comparamos com o primeiro segmento da rota a cada resultado. Como eles são dispostos ao longo da mesma malha viária, com 99% de probabilidade, o ângulo entre eles é próximo de 0 ou 180.

Esse truque muito simples facilita muito o entendimento de se já estamos indo em direção ao local ou se será necessário dar meia-volta.



Nesse ponto, fiquei bastante satisfeito com o aplicativo resultante e decidi tentar implantá-lo em vários países. Ainda assim, a Irlanda é um estado muito pequeno, respectivamente, e o índice elástico e o gráfico de estradas eram pequenos. Para testar, decidi conectar o Reino Unido vizinho. É cerca de 4 vezes maior e possui uma rede de estradas muito mais densa (especialmente a capital e as grandes cidades). E então surgiu um problema.

O Elasticsearch provavelmente digeriu muito bem o índice aumentado, mas com o OpenTripPlanner houve uma falha completa. Está escrito em Java e, como eu disse acima, gera um gráfico de estradas, para que depois de carregado na RAM. O gráfico para a Irlanda era de 1 gigabyte, para o Reino Unido já era 5. Era possível, obviamente, dividi-lo em países, regiões e até regiões e depois redirecionar para o gráfico desejado, dependendo das coordenadas do usuário. No entanto, isso tornou impossível estabelecer rotas entre regiões e, o mais importante, não resolveu a necessidade de manter todos esses gráficos na memória. Por fim, a simples compilação de cada um desses objetos consumiu MUITOS recursos e durou para sempre. Por diversão, lancei na minha máquina (quadros de 16 GB) a montagem do Conde da França, esperei um dia e cancelei.

Obviamente, uma tecnologia que se provou bem em pequenas tarefas não foi projetada para ser escalada (pelo menos não com meus recursos). Portanto, deve admitir a derrota ou rastrear para outra tecnologia. Fiz uma pausa por alguns dias e comecei a estudar o que outras soluções de código aberto existem no mundo. Descobriu-se que existem basicamente dois deles:


Se o primeiro é escrito em Java e carrega o gráfico da estrada na RAM, o OSRM - Open Source Routing Machine - já está escrito com vantagens e mantém seus arquivos intermediários (não menos monstruosos) em disco. Assim, a necessidade de ter uma quantidade enorme de RAM foi substituída pelo requisito de um disco grande e rápido. Isso é mais real.

Linha de chegada


Após algumas noites escolhendo a documentação, todo o código do servidor foi transferido para uma nova solução. Realmente funcionou, e funcionou muito bem. Foi possível conectar vários países e até a velocidade da pesquisa aumentou. Os princípios gerais eram os mesmos: a partir do OpenStreetMaps, os arquivos intermediários foram compilados para o perfil “machine” (um perfil é um conjunto de pesos e instruções para as arestas do gráfico - existem perfis “a pé”, “bicicleta” etc.). Em seguida, esses arquivos foram colocados em um diretório e a API do OSRM já os leu do disco. A Api, a propósito, acabou sendo bastante grande - tanto os contornos quanto o planejamento de rotas com várias nuances foram suportados, houve até a geração de peças para o mapa. Decidi me debruçar sobre este último com mais detalhes.

Voltando ao aplicativo e continuando a testá-lo, percebi mais algumas coisas:

  • o menu no topo não é bom, chega longe
  • o mapa geral definitivamente não é necessário, apenas me vincula ao google
  • cartões de resultado são chatos e monótonos

Felizmente, ele jogou fora um mapa do Google (hurrah, agora 100% de código aberto e seus dados), simplificou o menu e desceu. Começou a pensar no que fazer com os cartões. E então os api tiles apareceram muito oportunamente, o que eu mencionei acima. Permite gerar um bloco de vetor para as coordenadas fornecidas e o nível de zoom. O resultado é emitido na forma de um blob binário do tipo application / x-protobuf - um tipo de dados que é bastante inconveniente para manipulação. Não vou entrar em detalhes (tive que suar um pouco), mas, em poucas palavras, minhas ações foram assim:

  1. Pegue a linha da rota construída até o ponto na forma de polilinha
  2. Polilinha -> GeoJSON
  3. Obter a caixa delimitadora desta forma
  4. Solicitar todos os blocos capturados por esta caixa delimitadora
  5. Converta dados de bloco do formato binário em GeoJSON
  6. Cole os ladrilhos, apare pela caixa delimitadora, combine com a linha de rota, colore
  7. O GeoJSON resultante converte em um bitmap

No curso da ação, houve diferentes nuances, por exemplo, recuar a caixa delimitadora ou marcar pontos com anéis coloridos (e manter seu raio constante para todos os níveis de zoom). A imagem resultante era assim:



Toques finais


Quando anexei uma rota visual a cada resultado, a lista começou a brilhar com novas cores. Além disso, percebendo que cada imagem, por padrão, está montada no norte, eu as fiz girar em relação à bússola. Assim, além do efeito visual, esse chip também se tornou funcional - substituindo a seta de direção. Agora que você está dirigindo, pode ver com certeza de que lado esse ou daquele resultado é.

O terceiro mês de desenvolvimento expirou e já era necessário terminar. Quanto mais você adiciona, mais quer, então, em algum momento, você só precisa se recompor e abandonar o projeto. Ajustei e pintei a interface um pouco mais e, para uma sensação de conclusão, desenhei o logotipo do aplicativo:



e página de introdução:



E, finalmente, a versão final do aplicativo:









Sumário


Bem, obrigado por assistir. Espero que esse fluxo de consciência seja interessante para alguém e talvez até útil. Nesta fase, acho que o aplicativo está pronto: é rápido, sem bugs especiais e pode funcionar em qualquer país do mundo. A propósito, você deve ter notado que as capturas de tela eram do iPhone e do Android, porque, graças ao Flutter, o aplicativo funciona exatamente da mesma maneira nas duas plataformas.

No entanto, até agora decidi congelar tudo - mudei de emprego, surgiram novas preocupações. Depois de alguns meses, tirei a poeira e decidi escrever uma retrospectiva. Seu comentário é interessante: você gostaria, o usava, o que pode ser alterado.

PS Obviamente, sobre a prontidão do aplicativo é um absurdo. Está pronto como um protótipo - se você abordar uma produção séria, precisará criar scripts de sincronização de dados com o OpenStreetMaps, verificar a operação no zoológico de dispositivos, localizar interfaces etc. O mesmo back-end no nó e no python cairá sob qualquer carga séria.

Source: https://habr.com/ru/post/pt429240/


All Articles