Esta semana estava lendo o feed do meu twitter quando me deparei com o titulo “Big Data Results“, e resolvi entrar para espiar do que se tratava! Era um post que fazia uma análise com dados de Nova Iorque (táxis) comparando a performance entre o ArcGIS e o PostGIS. Eu achei muito interessante, e resolvi traduzir, adaptar e transcrevo abaixo.

O exemplo utilizado tem um arquivo de 6GB com 16 milhões de pontos de táxi e 263 zonas. O objetivo era determinar o número de táxis em cada zona, juntamente com a soma de todas as tarifas. Abaixo segue a análise aprofundada do que foi realizado:

1. Os dados e o computador

Os dados foram obtidos da Comissão de Táxis e Limousines de Nova York para outubro de 2012. Os aproximadamente 16 milhões de pontos de táxi e 263 polígonos de zona de táxi exigiram cerca de 6 GB de armazenamento. Você pode ver abaixo que é realmente um grande volume de dados:

O computador utilizado tem um processador i7 (4 núcleos), Windows 10, unidade SSD, 12 GB de RAM e um processador de 3.0 GHz.

2. O Problema

A pergunta tinha que ser respondida era: Quantos táxis estavam para cada zona e qual era o valor total da corrida? Então, para tentar responder a essa pergunta foi utilizado o ArcGIS, e Postgres/PostGIS. Vamos então as análises:

3. ArcGIS 10.4

Como deve ser de conhecimento da maioria de vocês, o ArcGIS 10.4 é um aplicativo de 32 bits. Então, para tentar resolver esse problema foi executada uma junção de tabela (AddJoin_Management) entre os pontos de táxi e as zonas de táxi. Para dar ao ArcGIS uma chance de lutar, foram movidos os dados para um geodatabase (assim, as camadas teriam índices espaciais). Depois de executar a junção por algumas horas, o ArcGIS 10.4 relatou um erro de falta de memória.

4. ArcGIS Pro

Em seguida, o teste foi realizado com o ArcGIS Pro, que é um verdadeiro aplicativo de 64 bits. Além disso, o ArcGIS Pro possui várias ferramentas para fazer exatamente o que era necessário. Um deles foi o Summarize Within. A ESRI torna realmente fácil fazer esse tipo de pergunta no ArcGIS Pro. Então a função foi executada, e foi obtida uma tabela resultante em 1h 27m. Neste ponto do experimento, foi bastante satisfeito – pelo menos, houve uma resposta, e é algo que se pode fazer durante um intervalo para o almoço, por exemplo.

5. ArcGIS Server com GeoAnalytics Server

A ESRI estava divulgando seu novo GeoAnalytics Server (o preço é de US$ 40.000 para uma implementação de 4 núcleos), e foi realizado o teste com ele também. Para surpresa, ele executou a consulta em cerca de 2m, o que é realmente espantoso. Este produto é projetado para grandes volumes de dados com certeza.

6. Postgres/PostGIS

Para ver como isso funcionaria no Postgres com o PostGIS a primeira coisa a ser feita foi criar uma instrução SQL:

SELECT count(*) AS totrides,taxizones.zone, sum(taxisandy.fare_amount)
FROM taxizones, taxisandy
WHERE ST_Contains(taxizones."Geom",taxisandy.pu_geom)
GROUP BY zone

Esta consulta foi executada em 10m 27s. Foi um resultado satisfatório, afinal, essa consulta é super simples de escrever. Mas ainda não é o fim pois existem algumas maneiras de otimizar essa consulta.

7. Postgres/PostGIS Otimizado

O índice espacial já havia sido criado, mas havia mais duas coisas que era necessário fazer: esvaziar a tabela e agrupar os dados. Então, o que essas consultas fazem:

VACUUM recupera o armazenamento ocupado por tuplas mortas. Na operação normal do PostgreSQL, as tuplas excluídas ou obsoletas por uma atualização não são fisicamente removidas de suas tabelas; eles permanecem presentes até que um VACUUM seja realizado.

O CLUSTER reordena fisicamente os dados no disco para que os dados que devem estar próximos um do outro no banco de dados estejam realmente próximos uns dos outros no disco. Em outras palavras, os pontos no Brooklyn agora estão fisicamente armazenados no disco perto de outros pontos no Brooklyn.

Então, como fazer isso? Primeiro, limpe e agrupe os dados:

VACUUM ANALYZE taxizones ("Geom"); 
VACUUM ANALYZE taxisandy (pu_geom);
CLUSTER taxisandy USING pugeom_idx; 
CLUSTER taxizones USING "Geom_x";

Agora, executar o cluster nos pontos de táxi de fato levou 18 minutos. Essa é uma “despesa única” que pagamos. Depois disso, podemos executar qualquer consulta que quisermos, repetidamente. A consulta é um pouco mais complicada do que a anterior porque escreve os resultados em uma nova tabela:

SELECT taxizones."Geom", sumfare, a.zone
INTO sumtable
FROM taxizones, 
(SELECT taxizones.zone, sum(taxisandy.fare_amount) AS sumfare
FROM taxizones
JOIN taxisandy
ON ST_Contains("Geom", pu_geom)
GROUP BY zone) AS a
WHERE taxizones.zone = a.zone

A consulta foi concluída em 1m 40s. Claro, com PostGIS você tem que levar em consideração o custo: $0.

Porém, ainda é possível otimizar mais essa consulta, pois algumas das zonas de táxi são um pouco grandes, então, a consulta de restrição pode demorar um pouco mais ao comparar as caixas delimitadoras (BBOX) no índice espacial. Para contornar isso, é possível utilizar a função ST_SubDivide para dividir as zonas de táxi maiores em polígonos menores:

Isso significava que os polígonos da minha zona de taxiamento passaram de 263 para 4.666. Agora, pensando racionalmente, quem faria uma sobreposição com 4.666 polígonos ao invés de 263, que é menor? Bem, foi o que foi feito aqui, e de 1m40s o resultado passou para 1m3s.

Mas como foram divididos os polígonos? Veja baixo:

SELECT ST_Subdivide("Geom", 50) AS geom, zone into taxisub FROM taxizones;
CLUSTER taxisub USING geom_idx;

E sim, o CLUSTER mais uma vez fez uma grande diferença. O SQL desta vez, nos permite fazer algumas coisas inteligentes. Lembre-se, agora temos 4.666 polígonos porque os 263 polígonos foram subdivididos.

Na consulta abaixo, a parte interna (sub consulta) é o SQL para determinar o total de viagens e a soma das tarifas em cada polígono dos 4.666. Assim, a parte externa da consulta está unindo as zonas de táxis originais (aquele com apenas 263 polígonos) e escrevendo para uma tabela com o resultado final.

SELECT taxizones."Geom" AS geom, count(id) AS numrides, sumfare, a.zone
INTO sumtable
FROM taxizones, 
   (SELECT taxisub.zone, sum(taxisandy.fare_amount) AS sumfare
    FROM taxisub
    JOIN taxisandy
    ON ST_Contains(geom, pu_geom)
    GROUP BY zone) AS a
WHERE taxizones.zone = a.zone

8. Resultados:

Abaixo, a lista detalhada dos resultados obtidos nos experimentos descritos acima:



É impressionante a forma como algumas das abordagens mais recentes conseguiram melhorar o desempenho do decorrer dos anos.

9. Conclusão

Então, qual a conclusão que podemos tirar disso tudo? Bem, os produtos GIS estão evoluindo e agora estão posicionados para lidar com conjuntos de dados realmente grandes de maneiras que não podíamos fazer antes. Estou impressionado com cada um desses produtos.

Este post foi traduzido e adaptado livremente do post originalmente escrito por Arthur J. Lembo Jr, do blog GIS Advising.

Fonte: GIS Advising