Nesse exemplo, vamos ler os dados simulando que estão chegando em um sistema de arquivos, no caso, o sistema será o disco local mesmo, para fins didáticos. Os dados lidos de um CSV tem os campos descritos na tabela a seguir:
O primeiro passo é se conectar ao cluster do Spark e configurar o Input de dados. Esse exemplo foi preparado para executar localmente, por isso não há necessidade de criar um cluster de Apache Spark para executar o código, tudo processa de forma auto-contida. Todos os fragmentos de código mostrados a seguir estão em linguagem Scala.
É importante notar que na definição do readStream o schema do CSV foi informado para o Spark, nesse ponto é necessário mostrar como devem ser lidos os dados, segue o schema:
Com a entrada de dados lendo as informações com readStream informamos ao Spark que o diretório deve ser tratado como um stream de dados, dessa forma o Spark sabe que haverá um influxo de novos arquivos nesse diretório e que eles devem ser processados continuamente.
O próximo passo será o processamento com os dados que estão chegando, nesse exemplo, vou fazer um agrupamento dos registros pelos campos: carrier e marital_status, simplesmente fazendo a contagem do número de ocorrências.
Como o Structured Stream trabalha com a mesma API de processamento dos Dataframes podemos simplificar a regra de negócio escrevendo o código em SQL, ao invés de uma das outras linguagens suportadas.
Para fazer isso, o Dataframe deve ser registrado como uma view temporária e a partir de então já podemos executar comandos SQL sobre essa view. Isso foi feito usando o comando: createOrReplaceTempView("user_records").
Algumas observações quanto a definição da saída writeStream, o OutputMode.Complete indica que toda a saída deve ser despejada na saída configurada, que no caso do exemplo apenas imprimir o resultado por meio da instrução: format("console"). A frequência de execução foi definida pelo gatilho em: Trigger.ProcessingTime("2 seconds").
O programa só começa efetivamente o processamento quando a instrução start() é invocada. A saída a seguir mostra o resultado do processamento com a execução de 3 batches:
A cada batch executado, os dados são consolidados e agregados, os dados da coluna num_users é atualizado a cada iteração.
Para simular a saída anterior, execute o programa e em tempo de execução mova gradativamente arquivos para dentro do diretório mapeado pelo stream.
Mova gradualmente os arquivos do diretório raw_data para o stream_in para simular a chegada de novos arquivos no stream de dados e veja o processamento acontecer:
Toda estrutura de arquivos mostrada anteriormente e o projeto de exemplo pode ser encontrado nesse repositório. É possível usar esse projeto para executar tudo localmente em seu computador sem necessidade de grandes ambientes de infraestrutura configurados.
Esse artigo mostrou a fundo o funcionamento da API de processamento de streams do Apache Spark, suas principais características, uma breve comparação de um código de processamento em lote e processamento contínuo.
Mostrei também um programa prático de processamento de streams, comentando passo a passo e como executá-lo em seu próprio ambiente de desenvolvimento.
No próximo artigo dessa série mostro como usamos o processador de Stream do Spark para processar dados em tempo real resolvendo um problema em produção na Wavy!

Um pressuposto implícito feito pela maioria das equipes ágeis é que o 'valor' é algo diretamente proporcional à 'velocidade' da equipe. Ainda que isto possa ser verdadeiro em alguns casos, no entanto, na maioria das vezes a velocidade da equipe dá pouca indicação sobre o verdadeiro valor entregue.
Ryan Shriver sugere que o valor é uma medida dos benefícios entregues, como percebido pelos interessados do projeto (stakeholders). Por outro lado, velocidade é um agregado de pontos por história que uma equipe pode entregar durante uma iteração. Dizer-se que todos esses pontos por história entregam valor é questionável. De acordo com Ryan, as equipes de desenvolvimento devem procurar responder às seguintes questões,
Responda a esta questão: O que é mais importante para as pessoas que financiam seu projeto/produto/serviço? Seriam os benefícios que elas esperam da solução, tais como aumento de lucro, mais participação no mercado ou eficiências operacionais (vamos chamar isto de valor de negócio)?
De forma semelhante, Mike Cottmeyer sugere que valor e velocidade não estão explicitamente correlacionadas entre si. Quando uma equipe inclui novas características com rapidez ao software, atinge assim uma grande velocidade. Entretanto, se a equipe de vendas não é capaz de vender o produto ou se a equipe de negócio não for capaz de usá-lo, então a equipe atualmente vai estar adicionando pouco valor. Ele observa que a definição de valor para um produto complexo pode depender do valor adicionado por todas as equipes da cadeia. Segundo Mike,
Digamos que você tenha quatro equipes que tenham de trabalhar juntas para lançar um novo pacote de produtos no mercado. As equipes A, B e C têm uma velocidade fantástica, mas a equipe D não está sendo capaz de integrar os módulos em sua etapa. A equipe D acaba por atrasar o lançamento... e o produto acaba chegando mais tarde ao mercado. Nesse meio-tempo... a concorrência acaba por lançar a última versão do produto deles, ganhando espaço no mercado e fazendo com que o desempenho do seu produto no mercado acabe não sendo tão bom.
O quanto que a velocidade das equipes A, B e C ajudou no valor final de seu produto? Novamente... uma grande velocidade... mas um valor não tão grande assim.