top of page

Search

81 itens encontrados para ""

  • Listando tabelas AWS Glue

    Utilizar a SDK da AWS é sempre uma boa opção caso precise explorar algum recurso mais a fundo em busca de uma solução. Neste post, iremos explorar um pouco do AWS Glue utilizando SDK. O Glue é uma ferramenta de ETL da AWS, que proporciona um repositório central de metadados, este chamado de Glue Catalog. Resumindo, o Glue Catalog mantém toda a estrutura de bancos e tabelas e seus schemas em um único lugar. A ideia deste post será listar todas as tabelas de um determinado banco de dados existente no Glue Catalog de forma programática utilizando a SDK. Dependências Maven Neste exemplo, estamos utilizando a versão do Java 8 para explorar melhor o uso de Streams na interação. Passo a passo O objeto awsGlue é o responsável pelo acesso ao recurso através das credencias que devem ser configuradas. Neste post não vamos entrar neste detalhe. O objeto getTablesRequest é o responsável por setar os parâmetros de requisição, neste caso, estamos setando o database. O objeto getTablesResult é o responsável por listar as tabelas com base nos parâmetros setados pelo objeto getTablesRequest e também controlar o fluxo do resultado. Perceba que além de retornar as tabelas através do método getTablesResult.getTableList(), este mesmo objeto retorna um token que será explicado melhor no próximo item. O token é representado pelo método getTablesResult.getNextToken(), a ideia do token é controlar o fluxo de resultados, pois todos os resultados são paginados e caso exista token para cada resultado, significa que ainda existem dados a serem retornados. No código, utilizamos uma estrutura de repetição com base na validação da existência do token, ou seja, se ainda existe token, este será setado no objeto getTableRequest através do código getTableRequest.setNextToken(token), para retornar mais resultados. Livros para estudar e ler Se você deseja aprender mais sobre e atingir um alto nível de conhecimento, recomendo fortemente a leitura do(s) seguinte(s) livro(s): AWS Cookbook (Versão Inglês) é um guia prático contendo 70 receitas detalhadas sobre os recursos da AWS e como resolver diferentes desafios. É um livro bem escrito e de fácil entendimento cobrindo os principais serviços da AWS através de exemplos práticos. A AWS ou Amazon Web Services é o serviço de nuvem mais utilizando atualmente em todo o mundo, caso queira entender mais sobre o tema para ficar bem posicionado no mercado, recomendo fortemente o estudo. Recomendações de Setup Se você tem interesse em saber qual é o meu setup que uso para desenvolver meus tutoriais, segue: Notebook Dell Inspiron 15 15.6 Monitor LG Ultrawide 29WL500-29 Espero que tenha curtido!

  • Introdução ao Apache Hive com Spark e Java

    O Hive é um software de Data Warehouse que possibilita a leitura, escrita e o gerenciamento de dados distribuídos e permite a utilização de SQL em consultas estruturadas. Vamos utilizar o contexto do Spark para a configuração inicial, mas é possível fazer de outras formas sem a utilização do Spark. Maven org.apache.spark spark-core_2.12 2.4.5 org.apache.spark spark-hive_2.12 2.4.5 O primeiro passo é criar a configuração do contexto inicial: String dwDir = new File("warehouse-dir").getAbsolutePath(); SparkConf sparkConf = new SparkConf() .set("spark.sql.warehouse.dir", wareHouseDir); SparkSession sparkSession = SparkSession.builder() .config(sparkConf) .enableHiveSupport() .master("local[1]") .getOrCreate(); Entendendo as configurações acima: 1. Neste trecho a variável dwDir recebe o caminho da pasta warehouse-dir que será utilizada nas configurações do Spark. Até então essa pasta não foi criada. String dwDir = new File("warehouse-dir").getAbsolutePath(); 2. No próximo trecho é setado a parâmetro spark.sql.warehouse.dir no contexto do Spark com o caminho do diretório referenciado no primeiro trecho. Dessa forma o Spark usará este diretório como o repositório dos bancos que serão criados. SparkConf sparkConf = new SparkConf() .set("spark.sql.warehouse.dir", wareHouseDir); 3. E por fim, a criação do SparkSession onde estão as configurações criadas anteriormente, o local onde o master será executado (localmente - local[1]) e a ativação do Hive. SparkSession sparkSession = SparkSession.builder() .config(sparkConf) .enableHiveSupport() .master("local[1]") .getOrCreate(); 4. Agora podemos executar algumas operações de DML e DDL 4.1. Criando um banco de dados sparkSession.sql("CREATE DATABASE IF NOT EXISTS hive_tutorial"); 4.2. Criando os Parquets Neste passo iremos criar uma tabela já apontando para o DataSource. Neste caso o DataSource será um Parquet. O Parquet é um arquivo de formato colunar que provê um melhor desempenho nas consultas. Para isso vamos criar um Parquet a partir de um JSON com seguinte o conteúdo: Arquivo data/pessoa.json {"id":1,"nome":"Joao","idade":12} {"id":2,"nome":"Kelly","idade":21} {"id":3,"nome":"Monica","idade":29} {"id":4,"nome":"Laura","idade":32} {"id":5,"nome":"Kiko","idade":23} {"id":6,"nome":"Miguel","idade":55} {"id":7,"nome":"Junior","idade":25} {"id":8,"nome":"Luis","idade":36} Executando a leitura do arquivo para um DataFrame. Dataset df = sparkSession.read().json("data/pessoa.json"); Criando os arquivos Parquet com base no DataFrame dentro do diretório data/parquet do seu projeto df.write().parquet("data/parquet/") Veja que os arquivos foram criados Pronto, agora temos um Data Source criado. 4.3. Criando a Tabela Segue os passos: sparkSession.sql("USE hive_tutorial"); Após selecionar o banco HIVE_TUTORIAL. O comando CREATE TABLE possui alguns argumentos extras, segue: STORED AS PARQUET : É um argumento que o Hive utilizará para saber que tipo de arquivo será usado na conversão, neste caso o Parquet. LOCATION: Diretório do Data Source criado anteriormente. sparkSession.sql("CREATE TABLE IF NOT EXISTS pessoa " + "(id BIGINT, nome STRING, idade BIGINT) " + "STORED AS PARQUET " + "LOCATION 'data/parquet/'"); É possível verificar a tabela criada executando o trecho abaixo: sparkSession.sql("SHOW TABLES").show(); Independente do fim da execução do programa, a tabela será mantida. Diferente de uma view criada com SparkSQL que é somente mantida em memória. 5. Exemplos de consultas Selecione o banco de dados sparkSession.sql("USE hive_tutorial"); Exemplo 1 sparkSession.sql("SELECT id, nome, idade " + "FROM hive_tutorial.pessoa " + "WHERE idade between 10 and 30 " + "ORDER BY nome desc ").show(); Resultado Exemplo 2 sparkSession.sql("SELECT count(nome) " + "FROM hive_tutorial.pessoa " + "WHERE idade > 45 ").show(); Resultado 6. Exemplos de consultas mais complexas Agora vamos criar duas novas tabelas para explorar melhor os recursos do Hive. Crie o arquivo JSON data/produto.json {"id":1,"desc":"video game","preco":1800.0,"tipo":"eletronico"} {"id":2,"desc":"geladeira","preco":1600.0,"tipo":"eletronico"} {"id":3,"desc":"cama","preco":2000.0,"tipo":"quarto"} {"id":4,"desc":"armário","preco":750.0,"tipo":"sala"} {"id":5,"desc":"notebook","preco":4500.0,"tipo":"eletronico"} {"id":6,"desc":"mesa","preco":2500.0,"tipo":"sala"} {"id":7,"desc":"cadeira","preco":110.0,"tipo":"sala"} {"id":8,"desc":"TV","preco":1500.0,"tipo":"eletronico"} {"id":9,"desc":"fogão","preco":900.0,"tipo":"cozinha"} Crie os parquets para Produto Dataset dfP = sparkSession.read().json("data/produto.json"); dfProd.write().parquet("data/parquet/produto/"); Crie o arquivo JSON data/item.json {"id":1,"id_produto":2,"qtde":1} {"id":2,"id_produto":1,"qtde":2} {"id":3,"id_produto":3,"qtde":3} {"id":4,"id_produto":4,"qtde":2} {"id":5,"id_produto":5,"qtde":5} Crie os parquets para Item Dataset dfItem = sparkSession.read().json("data/item.json"); dfItem.write().parquet("data/parquet/item/"); Com base nos parquets criado, agora vamos criar a tabelas Produto e Item sparkSession.sql("USE hive_tutorial"); sparkSession.sql("CREATE TABLE IF NOT EXISTS produto " + "(id BIGINT, desc STRING, " + "preco BIGINT, " + "tipo STRING) " + "STORED AS PARQUET " + "LOCATION 'data/parquet/produto'"); sparkSession.sql("CREATE TABLE IF NOT EXISTS item " + "(id BIGINT, " + "id_produto BIGINT, " + "qtde BIGINT) " + "STORED AS PARQUET " + "LOCATION 'data/parquet/item/'"); Tabelas criadas sparkSession.sql("SHOW TABLES").show(); Consultas utilizando JOIN Exemplo 1 sparkSession.sql("SELECT prod.id, " + "prod.desc, " + "prod.preco, " + "prod.tipo, " + "item.qtde " + "FROM produto prod inner join item item " + "on (prod.id = item.id_produto) " + "order by prod.id ").show(); Resultado Exemplo 2 sparkSession.sql(" SELECT " + "prod.tipo, " + "sum(item.qtde) " + "FROM produto prod inner join item item " + "on (prod.id = item.id_produto) " + "group by prod.tipo").show(); Resultado Exemplo 3 sparkSession.sql(" SELECT " + "prod.tipo, " + "sum(item.qtde), " + "sum(item.qtde * prod.preco) " + "FROM produto prod inner join item item " + "on (prod.id = item.id_produto) " + "group by prod.tipo").show(); Resultado Pra finalizar, dê uma olhada na documentação oficial para mais detalhes: https://spark.apache.org/docs/latest/sql-data-sources-hive-tables.html https://hive.apache.org/ É isso, espero ter ajudado!

  • Lendo arquivo CSV com Apache Spark

    Apache Spark atua muito bem na leitura de diversos arquivos para extração de dados, nesse post vamos criar um exemplo de leitura de um arquivo CSV utilizando Spark, Java e Maven. Para quem não sabe o que é um CSV, é um arquivo texto que separa as colunas entre ponto e vírgula ( ; ). Maven org.apache.spark spark-core_2.12 3.1.0 org.apache.spark spark-sql_2.12 3.1.0 Conteúdo do CSV (Crie um arquivo chamado movies.csv com este conteúdo) title;year;rating The Shawshank Redemption;1994;9.3 The Godfather;1972;9.2 The Dark Knight;2008;9.0 The Lord of the Rings: The Return of the King ;2003;8.9 Pulp Fiction;1994;8.9 Fight Club;1999;8.8 Star Wars: Episode V - The Empire Strikes Back;1980;8.7 Goodfellas;1990;8.7 Star Wars;1977;8.6 Criando SparkSession SparkConf sparkConf = new SparkConf(); sparkConf.setMaster("local[*]"); sparkConf.setAppName("app"); SparkSession sparkSession = SparkSession.builder() .config(sparkConf) .getOrCreate(); Executando a leitura Dataset ds = sparkSession.read() .format("CSV") .option("sep",";") .option("inferSchema", "true") .option("header", "true") .load("movies.csv"); ds.select("title","year","rating").show(); Resultado Entendendo alguns parâmetros .option("sep", ";"): Define a utilização de um separador padrão para a leitura do arquivo, neste caso o separador é o ponto e vírgula (;) .option("inferSchema", "true"): O parâmetro inferSchema possibilita inferir o(s) arquivo(s) afim de entender (adivinhar) os tipos dos dados de cada campo .option("header", "true"): Habilitar o parâmetro header possibilita utilizar o nome de cada campo definido no cabeçalho do arquivo .load("movies.csv"): movies.csv é o nome do arquivo a ser lido Material de estudo Se quer aprender mais sobre o assunto e alcançar um alto nível de conhecimento, recomendo fortemente a leitura do(s) seguinte(s) livro(s): Beginning Apache Spark 3: With Dataframe, Spark SQL, Structured Streaming, and Spark Machine Library (Versão Inglês) com a nova versão do Spark, este livro explora os principais recursos do Spark, como o uso de Dataframes, Spark SQL no qual você pode usar SQL para manipular dados e Structured Streaming para processar dados em tempo real. Este livro contém exemplos práticos e trechos de código para facilitar a leitura. Use a cabeça: Java é um clássico onde qualquer iniciante no assunto deve ler e estudar. Neste livro você aprenderá sobre os principais pilares de Java como, orientação a objetos, criação de classes, interfaces e seu funcionamento, controlar exceções, objetos genéricos e muito mais. Se quer entrar de cabeça neste mundo, é uma excelente opção! High Performance Spark: Best Practices for Scaling and Optimizing Apache Spark (Versão Inglês) é um livro que explora as melhores práticas usando Spark e Scala para lidar com processamentos de larga escala. Ensina sobre técnicas para obter o máximo de desempenho no processamento utilizando RDD, Spark SQL, Spark MLlib e muito mais. Maven: The Definitive Guide (Versão Inglês) é um livro escrito em inglês que vale muito a pena ter no seu acervo caso você queira entender mais sobre o assunto. Maven é hoje o principal gerenciador de dependências em projetos Java encontrado no mercado. Em qualquer projeto seja ele nacional ou internacional, Maven vai estar presente facilitando a instalação, gerenciando bibliotecas e dando suporte aos builds dos projetos. Curtiu? Espero que sim, até mais!

  • Acessando e modificando Terraform State

    Antes de começar a falar sobre o acesso aos estados, é necessário explicar o que são os estados ou State. O que são os States? O que é o Terraform State? O Terraform State é uma forma do Terraform gerenciar a infra, configurações e os recursos criados afim de manter um mapeamento do que já existe e controlar a atualização e criação de novos recursos. Um exemplo básico é quando criamos um Bucket S3, um EC2 ou uma SQS via Terraform. Todos estes recursos são mapeados no estado e passam a ser gerenciados pelo Terraform. Localização do State Local Por padrão o Terraform aloca o estado localmente no arquivo terraform.tfsate. Utilizar o State localmente pode funcionar bem para um estudo específico no qual não exista a necessidade em compartilhar o State entre times. Remote Ao contrário do Local, quando temos times compartilhando dos mesmos recursos, a utilização do State de forma remota se torna imprescindível. O Terraform provê suporte para que o State possa ser compartilhado de forma remota. Não entraremos em detalhes em como configurar, mas é possível manter o State no Amazon S3, Azure Blob Storage, Google Cloud Storage, Alibaba Cloud OSS e entre outras nuvens. O State é representado pelo arquivo terraform.tfsate, um arquivo no formato JSON, segue um exemplo de um Bucket S3 mapeando no State: { "version": 4, "terraform_version": "0.12.3", "serial": 3, "lineage": "853d8b-6ee1-c1e4-e27e-e10", "outputs": {}, "resources": [ { "mode": "managed", "type": "aws_s3_bucket", "name": "s3_bucket_xpto", "provider": "provider.aws", "instances": [ { "schema_version": 0, "attributes": { "acceleration_status": "", "acl": "private", "arn": "arn:aws:s3:::bucket.xpto", "bucket": "bucket.xpto", "bucket_domain_name": "bucket.xpto", "bucket_prefix": null, "bucket_regional_domain_name": "bucket.xpto", "cors_rule": [], "force_destroy": false, "grant": [], "hosted_zone_id": "Z3NHGSIKTF", "id": "bucket.xpto", "lifecycle_rule": [], "logging": [], "object_lock_configuration": [], "policy": null, "region": "us-east-1", "replication_configuration": [], "request_payer": "BucketOwner", "server_side_encryption_configuration": [], "tags": { "Environment": "staging" }, "versioning": [ { "enabled": false, "mfa_delete": false } ], "website": [], "website_domain": null, "website_endpoint": null }, "private": "UJbhV==" } ] } ] } Acessando e alterando o State Apesar do State estar alocado em um arquivo JSON, não é recomendado a alteração direta no arquivo. O Terraform provê a utilização do comando Terraform state executado via CLI para que pequenas modificações sejam efetuadas. Através do CLI, podemos executar comandos afim de manipular o State, segue o uso: terraform state [options] [args] Sub-comandos: list Lista os recursos no estado mv Move um item no estado pull Extrai o estado atual e lista o resultado no stdout push Atualiza um estado remoto de um arquivo de estado local rm Remove instância do estado show Mostra recursos do estado 1. Listando os recursos do State Comando: terraform state list O comando acima possibilita listar os recursos que estão sendo gerenciados pelo State Exemplo: $ terraform state list aws_s3_bucket.s3_bucket aws_sqs_queue.sqs-xpto No exemplo acima, temos um Bucket S3 e um SQS que foram criados via terraform e que estão sendo gerenciados pelo State. 2. Visualizando um recurso e seus atributos Comando: terraform state show [options] ADDRESS O comando acima possibilita mostrar em detalhes um recurso específico e seus atributos Exemplo: $ terraform state show aws_sqs_queue.sqs-xpto # aws_sqs_queue.sqs-xpto: resource "aws_sqs_queue" "sqs-xpto" { arn = "arn:aws:sqs:sqs-xpto" content_based_deduplication = false delay_seconds = 90 fifo_queue = false id = "https://sqs-xpto" kms_data_key_reuse_period_seconds = 300 max_message_size = 262144 message_retention_seconds = 345600 name = "sqs-xpto" receive_wait_time_seconds = 10 tags = { "Environment" = "staging" } visibility_timeout_seconds = 30 } 3. Removendo recursos do State Comando: terraform state rm [options] ADDRESS... O comando acima remove um ou mais items do State. Diferente de um terraform destroy, que remove o recurso do State e os objetos remotos criados na nuvem. Exemplo: $ terraform state rm aws_sqs_queue.sqs-xpto Material de estudo Se quer aprender mais sobre o assunto e alcançar um alto nível de conhecimento, recomendo fortemente a leitura do(s) seguinte(s) livro(s): Terraform: Up & Running: Writing Infrastrucutre as Code (Versão Inglês) é um livo focado em como utilizar Terraform e seus benefícios. O autor buscou fazer comparações com diversas outras ferramentas IAC (Infrastructure as code) como Ansible e Cloudformation (IAC nativa da AWS) e principalmente de como criar e provisionar diferentes recursos para múltiplos serviços de nuvem. Atualmente, Terraform é a ferramenta mais utilizada em projetos de Software para a criação e gerenciamento de recursos no serviços de nuvem como AWS, Azure, Google cloud e vários outros. Se você quer ser um engenheiro completo, recomendo fortemente aprender sobre o tema. Amazon AWS: Descomplicando a computação na nuvem é um livro para aqueles que estão começando na AWS e querem entender o funcionamento e a dinâmicas dos serviços como S3, EC2, ElasticCache, Route 53, SNS, Cloudwatch e muito mais. AWS Cookbook (Versão Inglês) é um guia prático contendo 70 receitas detalhadas sobre os recursos da AWS e como resolver diferentes desafios. É um livro bem escrito e de fácil entendimento cobrindo os principais serviços da AWS através de exemplos práticos. A AWS ou Amazon Web Services é o serviço de nuvem mais utilizando atualmente em todo o mundo, caso queira entender mais sobre o tema para ficar bem posicionado no mercado, recomendo fortemente o estudo. E aí, Curtiu? Até mais!

  • Java: Streams API - findFirst()

    Java 8 Streams introduziu diferentes métodos para manipular coleções. Um destes métodos é o findFirst(), que permite retornar o primeiro elemento de uma Stream através de uma instância Optional. Na prática Output Item: Monica Souza Utilizando filter Output Item: Andre Silva Perceba que retornou o primeiro nome com sobrenome Silva da coleção. A não utilização de Streams Se utilizarmos o modo tradicional, ou seja, sem a utilização de Streams. O código ficaria assim, filtrando pelo sobrenome "Silva" Neste caso dependemos do break para encerrar a execução. Material de estudo Se quer aprender mais sobre o assunto e alcançar um alto nível de conhecimento, recomendo fortemente a leitura do(s) seguinte(s) livro(s): Use a cabeça: Java é um clássico onde qualquer iniciante no assunto deve ler e estudar. Neste livro você aprenderá sobre os principais pilares de Java como, orientação a objetos, criação de classes, interfaces e seu funcionamento, controlar exceções, objetos genéricos e muito mais. Se quer entrar de cabeça neste mundo, é uma excelente opção! Padrões de Projeto é um livro no qual recomendamos após alcançar uma certa maturidade em programação em geral. Escrito por grandes nomes do assunto e traduzido para o português, Padrões de Projeto ou Design patterns como também são conhecidos, são padrões e estratégias que te ajudará a resolver diferentes desafios arquiteturais, aplicando soluções de forma elegante. São estratégias em que desenvolvedores de todo o mundo tem adotado em seus projetos. Imagina se você precisa atuar em um projeto internacional, caso este projetos tem adotado estratégias de Padrões de projeto, você não terá nenhuma grande dificuldade em entender a dinâmica e a arquitetura do código ou caso contrário, você mesmo poderá aplicar os conhecimentos adquiridos através deste livro. O mais interessante que Padrões de Projeto independem de linguagem de programação, é possível aplicar em qualquer outra linguagem, ou seja, é um conteúdo 100% reutilizável. Java Efetivo escrito por Joshua Bloch e traduzido para o português, é um livro excelente para aqueles que possuem um pouco mais de experiência com Java mas que precisam aprofundar em detalhes mais específicos da linguagem como, quando e como usar específicos Padrões de Projeto ou Design Patterns, utilização de Lambdas e Streams, concorrências e serializações. Para aqueles que possuem mais de experiência, é um excelente material de consulta.

  • Primeiros passos com Delta Lake

    O que é o Delta Lake? O Delta Lake é um projeto open-source que visa gerenciar a camada de armazenamento (Storage Layer) que segundo o seu conceito: "traz confiabilidade para Datalakes". Na prática é uma abstração do Apache Spark reutilizando os mesmos mecanismos mas oferencendo recursos extras interessantes. Dentre eles, suporte para transações ACID. Todos sabem que manter a integridade dos dados em uma pipeline de dados é uma tarefa crítica diante do alta concorrência de leitura e escrita de dados. Neste caso, o ACID possibilita gerenciar ambientes como estes. Dentre outras vantagens, o Delta Lake provê histórico de auditoria, versionamento de dados, suporta operações DML do tipo delete e update e vários outras vantagens. Para este tutorial, vamos simular uma pipeline de dados simples de forma local, com o foco no que o Delta Lake pode nos oferecer de vantagens. Na etapa de ingestão, vamos carregar um Spark DataFrame a partir de um JSON, criaremos uma view temporária para nos auxiliar, criaremos uma tabela Delta via SQL e por fim, utilizaremos o Delta Lake para executar algumas operações de DML utilizando a view que será criada. Vamos utilizar Java e Maven para gerenciar as dependências, além de Spark e Hive no qual este, vai nos auxiliar em manter a tabelas em um catálogo de dados. Maven org.apache.spark spark-core_2.12 3.0.1 org.apache.spark spark-sql_2.12 3.0.1 org.apache.spark spark-hive_2.12 3.0.1 io.delta delta-core_2.12 0.8.0 O código será desenvolvido em pequenos trechos para um melhor entendimento. Configurando Spark com Delta e Hive String val_ext="io.delta.sql.DeltaSparkSessionExtension"; String val_ctl="org.apache.spark.sql.delta.catalog.DeltaCatalog"; SparkConf sparkConf = new SparkConf(); sparkConf.setAppName("app"); sparkConf.setMaster("local[1]"); sparkConf.set("spark.sql.extensions",var_ext); sparkConf.set("spark.sql.catalog.spark_catalog",val_ctl); SparkSession sparkSession = SparkSession.builder() .config(sparkConf) .enableHiveSupport() .getOrCreate(); Entendendo o trecho acima Definimos duas variáveis val_ext e val_ctl atribuindo os valores para as chaves (spark.sql.extensions e spark.sql.catalog.spark_catalog) . Estas, necessárias para a configuração do Delta junto com o Spark Demos o nome do contexto do Spark de app Como não estamos rodando o Spark em um cluster, o master está configurado para rodar local local[1] O Spark tem suporte para o Hive, nesse caso o habilitamos no trecho enableHiveSupport( ) Ingestão dos Dados Vamos trabalhar com Spark Dataframe como fonte dos dados. Carregaremos um Dataframe a partir de um JSON. Arquivo order.json {"id":1, "date_order": "2021-01-23", "customer": "Jerry", "product": "BigMac", "unit": 1, "price": 8.00} {"id":2, "date_order": "2021-01-22", "customer": "Olivia", "product": "Cheese Burguer", "unit": 3, "price": 21.60} {"id":3, "date_order": "2021-01-21", "customer": "Monica", "product": "Quarter", "unit": 2, "price": 12.40} {"id":4, "date_order": "2021-01-23", "customer": "Monica", "product": "McDouble", "unit": 2, "price": 13.00} {"id":5, "date_order": "2021-01-23", "customer": "Suzie", "product": "Double Cheese", "unit": 2, "price": 12.00} {"id":6, "date_order": "2021-01-25", "customer": "Liv", "product": "Hamburger", "unit": 1, "price": 2.00} {"id":7, "date_order": "2021-01-25", "customer": "Paul", "product": "McChicken", "unit": 1, "price": 2.40} Criando Dataframe Dataset df = sparkSession.read().json("datasource/"); df.createOrReplaceGlobalTempView("order_view"); Entendendo o trecho acima No trecho anterior, estamos criando um Dataframe a partir do arquivo JSON que está dentro do diretório datasource/ , crie este diretório para que a estrutura do seu código fique mais compreensiva e em seguida, crie o arquivo order.json com base no conteúdo mostrado anteriormente. Por último, criamos um view temporária que vai nos auxiliar mais a frente nos próximos passos. Criando a Tabela Delta (Delta Table) Vamos criar a Delta Table a partir de um script SQL. A princípio a criação é simples, mas perceba que usamos tipagens diferentes de uma tabela utilizada em um banco relacional. Como por exemplo, utilizamos STRING ao invés de VARCHAR e assim por diante. Estamos particionando a tabela pelo campo date_order. Este campo foi escolhido como partição pois acreditamos que haverá diferentes datas. Dessa forma, as consultas podem utilizar este campo como filtro, visando um melhor desempenho. E por fim, definimos a tabela como Delta Table a partir do trecho USING DELTA. String statement = "CREATE OR REPLACE TABLE orders (" + "id STRING, " + "date_order STRING," + "customer STRING," + "product STRING," + "unit INTEGER," + "price DOUBLE) " + "USING DELTA " + "PARTITIONED BY (date_order) "; sparkSession.sql(statement); Entendendo o trecho acima No trecho anterior estamos criando uma tabela Delta chamada orders e em seguida executamos a criação. Operações DML Delta suporta operações como Delete, Update e Upsert utilizando Merge Utilizando Merge junto com Insert e Update Neste passo, vamos executar um Merge que possibilita controlar o fluxo de inserção e atualização de dados através de uma tabela, Dataframe ou view. O Merge trabalha a partir de row matches que ficará mais compreensível no trecho seguinte. String mergeStatement = "Merge into orders " + "using global_temp.order_view as orders_view " + "ON orders.id = orders_view.id " + "WHEN MATCHED THEN " + "UPDATE SET orders.product = orders_view.product," + "orders.price = orders_view.price " + "WHEN NOT MATCHED THEN INSERT * "; sparkSession.sql(mergeStatement); Entendendo o trecho acima No trecho acima estamos executando o Merge a partir da view order_view criada nos passos anteriores. No mesmo trecho temos uma condição orders.id = orders_view.id que vai auxiliar nos matches seguintes. Caso a condição anterior seja verdadeira, ou seja o MATCHED seja verdadeiro. Os dados serão atualizados. Caso a condição não seja verdadeira, NOT MATCHED. Os dados serão inseridos. No caso acima, os dados serão inseridos, pois até então não existia dados na tabela orders. Execute o comando abaixo para visualizar os dados inseridos. sparkSession.sql("select * from orders").show(); Atualize o arquivo datasource/order.json alterando o campo product, price e execute todos os trechos novamente. Você verá que todos os registros serão atualizados. Comando Update É possível executar Update sem a necessidade de usar o Merge, basta executar o comando abaixo: String updateStatement = "update orders " + "set product = 'Milk-Shake' " + "where id = 2"; sparkSession.sql(updateStatement); Comando Delete String deleteStatement = "delete from pedidos where id = 2"; sparkSession.sql(deleteStatement); Além de poder executar o comando Delete, é possível utilizar este comando junto ao Merge. Entendendo o Delta Lake Transaction Log (DeltaLog) Além de dar suporte a transações ACID, o delta gera alguns arquivos JSON que servem como uma forma de auditar e manter o histórico de cada transação, desde comandos DDL e DML Com este mecanismo é possível até voltar em um estado específico da tabela caso necessário. Para cada transação executada um arquivo JSON é criado dentro da pasta _delta_log. O arquivo inicial sempre será 000000000.json, contendo os commits da transação. Neste nosso cenário, este primeiro arquivo contém os commits da criação da tabela orders. Para visualizar melhor, acesse a pasta local que provavelmente foi criada na raiz do seu projeto chamada spark-warehouse. Esta pasta foi criada pelo Hive para alocar os recursos criados desde os arquivos JSON e os parquets. Dentro dela terá uma estrutura de pastas conforme imagem abaixo: Perceba que os arquivos são criados em ordem crescente a partir de cada transação executada. Acesse cada arquivo JSON e verá cada transação que foi executado através do campo operation, além de outras informações. 00000000000000000000.json "operation":"CREATE OR REPLACE TABLE" 00000000000000000001.json "operation":"MERGE" 00000000000000000002.json "operation":"UPDATE" 00000000000000000003.json "operation":"DELETE" Perceba também que os arquivos parquets foram gerados particionados em pastas pelo campo date_order. Utilizar partição visa consultas com melhores desempenho, mas não entraremos em detalhes neste post, futuramente falaremos mais sobre isso. Espero que neste post foi possível esclarecer algumas dúvidas sobre o que é o Delta Lake e seu funcionamento. Até a próxima!

  • Mensageria com Google Cloud Pub/Sub

    A comunicação assíncrona via mensagens é um dos modelos mais utilizados atualmente entre microsserviços. Vamos fazer um exemplo bem simples usando a plataforma do Google. Vou começar mostrando o código e depois algumas configurações que precisaremos fazer. OK? Vamos lá!!! Para começar, vamos adicionar as seguintes dependências no projeto: (Caso tenha dúvidas em como iniciar um projeto spring boot, veja nesse post) org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-starter-web org.springframework.cloud spring-cloud-gcp-starter 1.1.1.RELEASE org.springframework.cloud spring-cloud-gcp-starter-pubsub 1.1.1.RELEASE org.springframework.boot spring-boot-starter-test test Agora, vamos para o código de fato: Primeiramente vamos criar um VO que vamos usar para representar o nosso evento. public class EventVO { private String name; private String email; [...] Getters/Setters and Constructor } Agora , vamos disponibilizar um endpoint para facilitar a publicação da mensagem. import com.coffee.tipsgcp.vo.EventVO; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.gcp.pubsub.core.publisher.PubSubPublisherTemplate; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/producer-event") public class ProducerEventController { @Autowired PubSubPublisherTemplate pubsubPublisher; @Autowired ObjectMapper objectMapper; @PostMapping() public void sendEvent(@RequestBody EventVO event) throws JsonProcessingException { pubsubPublisher.publish("topico-test", objectMapper.writeValueAsString(event)); System.out.println("Mensagem enviada para o tópico !!!"); } } No exemplo acima, nós injetamos a classe PubSubPublisherTemplate que é responsável por publicar a mensagem com o método publish(). Nele informamos o nome do tópico e transformamos o nosso objeto EventVO em json para ser enviado. E finalizando a parte do código, vamos criar um método para consumir as mensagens que publicamos. Lembrando que como estamos falando de microsserviços, o produtor e consumidor ficam em aplicações diferentes, aqui vamos colocar na mesma aplicação para facilitar o exemplo. import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.cloud.gcp.pubsub.core.PubSubTemplate; import org.springframework.stereotype.Component; @Component public class TopicSubscriber implements ApplicationRunner { @Autowired PubSubTemplate pubSubTemplate; @Override public void run(ApplicationArguments args) { pubSubTemplate.subscribe("topico-test-assinatura", msg -> { System.out.println("Consumindo mensagem \n" + msg.toString()); msg.ack(); }); } } A classe acima implementa ApplicationRunner para que o código no método run() seja executado assim que a aplicação comece a rodar. Além disso, injetamos a classe PubSubTemplate para consumir as mensagens que chegam ao tópico especificado por meio do método subscribe(). Por fim, o metodo ack(), notifica o serviço do google que a mensagem foi recebida. Agora que finalizamos a parte do código, vamos a algumas configurações que teremos que fazer no Google Cloud Console. Isso pode ser feito por um client diretamento do terminal ou no próprio google console. Vou mostrar pelo console. Após criar um projeto no google console, precisaremos ativar uma chave para autenticação. Para isso, procure por Credentials na barra de busca: Após entrar nessa sessão, você encontrará uma listas com as contas que estão disponíveis para o seu usuário. Escolha a conta que deseja usar e clique em editar. Na próxima tela, será exibida a aba CHAVES. Nela terá a opção de adicionar uma nova chave. Clique na opção e será gerado um arquivo com a chave para autenticação no serviço. Faça dowload do arquivo. Após baixar o arquivo de autenticação, vamos criar uma variável de ambiente com o path do arquivo. Isso pode ser feito de várias formas, inclusive pode ser feito via código ao invés de variável de ambiente. Aqui, vou mostrar como foi feito na IDE Intellij. Clique em Edit Configurations e em, Environment Variables adicione: GOOGLE_APPLICATION_CREDENTIALS=[file_path]. Caso não seja especificado um arquivo de autenticação no google ou se a configuração estiver errada, a aplicação não vai nem conseguir iniciar. Além do arquivo de autenticação, vamos configurar agora o tópico e subscrição que vamos utilizar. Na barra de busca do Google Console, procure por Pub/Sub: Após abrir essa seção, clique no botão Criar Tópico e crie um tópico com o nome que você especificou no código. Depois de criado o tópico, clique em mais ações (3 pontinhos) no lado direito, e crie a assinatura com o mesmo nome especificado no código. Ótimo, agora sim nossa aplicação já está pronta!! Vamos subir a aplicação e fazer um POST para o nosso controller: Após fazer o POST, a saída do console será essa: Note que após a mensagem ser enviada, imediatamente ela é consumida pela outra ponta. É isso galera, espero ter contribuído. Até a próxima!

  • Spring Data REST: Um CRUD pronto em 5 minutos

    O módulo data rest do spring nos ajuda a disponibilizar operações CRUD com o mínimo de esforço possível. Imagine que você precise implementar um cadastro de produtos com regras complexas, mas que, antes disso, também tenha que ter um cadastro de “categoria de produtos”, que simplesmente insere uma nova categoria sem nenhuma regra complexa para se preocupar. Nesse contexto, o spring data rest pode facilitar bastante o trabalho, disponibilizando todas as operações no padrão REST para isso. Vamos lá!!! A primeira coisa que vamos precisar é incluir a dependência no projeto. org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-starter-data-rest org.springframework.boot spring-boot-starter-data-jpa com.h2database h2 org.springframework.boot spring-boot-starter-test test Feito isso, vamos criar a entidade PERSON, que será utilizada para o exemplo: @Entity public class Person { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String name; private String document; [...] //Getters and Setters } E para finalizar(SIM, já estamos finalizando), criamos a classe Repository da entidade, onde vamos ter a anotação responsável por disponibilizar as operações rest. @RepositoryRestResource(collectionResourceRel = "persons", path = "persons") public interface PersonRepository extends JpaRepository { } Pronto!!! Já temos várias operações REST funcionando. Vamos testar? Lembrando que foi usado o banco H2 para facilitar a implementação. Vamos fazer um POST para a url http://localhost:8080/persons, com o seguinte payload: { "name": "Steve Rogers", "document": "0000000001" } Nesse caso temos como response um 201 Created e o body: { "name": "Steve Rogers", "document": "0000000001", "_links": { "self": { "href": "http://localhost:8080/persons/1 " }, "person": { "href": "http://localhost:8080/persons/1 " } } } Note que o retorno já faz referência a url GET do próprio registro. Para fazer update dos dados, podemos fazer um POST para a url http://localhost:8080/persons/1 com o seguinte payload: { "name": "Tony Stark", "document": "0000000001" } E para deletar fazemos DELETE para a mesma url, e nesse caso receberemos como retorno o código 204 No Content. Após isso, se fizermos um GET para a url acima, passaremos a receber um 404 Not Found, já que o registro foi deletado. Então é isso pessoal, exemplo simples, mas que pode ajudar no ganho de produtividade no dia a dia. Até a próxima!!

  • Salesforce: disponibilizando um endpoint para chamadas externas

    Salesforce é uma plataforma com vários módulos específicos para fazer a gestão do relacionamento do cliente em várias etapas da jornada, como venda e pós-venda, suporte, marketing, etc. O desenvolvimento com na plataforma Salesforce é uma das várias áreas do mundo dev que mais cresce nos últimos anos. É bem provável que se você está trabalhando com o CRM, também vai precisar fazer algumas integrações com outros sistemas ou base de dados da sua empresa, e para quem está iniciando nessa jornada, aqui vai um exemplo simples com a implementação de um endpoint no Salesforce e uma chamada externa a ele. Vamos lá!!! O primeiro passo é liberar o Salesforce para receber chamadas externas de URLs específicas. Por padrão, o Salesforce não aceita chamadas externas, então para liberar, você deve seguir os seguintes passos: Logar no Salesforce com acesso de administrador. Ir em Setup Na barra de busca procure por “Remote Site Settings” Crie um novo registro com a url da aplicação que fará a chamada REST ao Salesforce. Feito isso, agora podemos implementar um endpoint no salesforce como no modelo abaixo: @RestResource(urlMapping='/coffeeandtips/exemplo/*') global with sharing class ExemploController { @HttpPost global static void recebeDadosESalva(List req) { String requestData = JSON.serialize(req); [...] } } No próximo passo, vamos precisar fazer mais algumas configurações no salesforce. Logar no Salesforce com acesso de administrador. Ir em Setup Na barra de busca procure por “Connected Apps” Procure pelas informações “Consumer Key” e “Consumer Secret” Pronto! Agora já conseguimos fazer chamadas para o endpoint que acabamos de criar. Para isso, antes de fazer a chamada de fato, vamos precisar obter um token utilizando a key e secret do passo anterior. A chamada deve ser feita com os seguintes parâmetros: POST para https://minhaurl.salesforce.com/services/oauth2/token Content-type : application/x-www-form-urlencoded Parametros: grant_type : {esse parâmetro será sempre do tipo “password”} client_id: {Consumer Key obtida no passo anterior} client_secret : {Consumer Secret obtida no passo anterior} username: {username de um usuário com permissões para fazer chamadas externas (pode ser o usuario que você usou para logar no salesforce)} password: {senha de um usuário com permissões para fazer chamadas externas (pode ser o usuario que você usou para logar no salesforce)} Você receberá um token como resposta desse POST. E Finalmente podemos fazer uma chamada rest para o endpoint que criamos no Salesforce. POST para https://minhaurl.salesforce.com/services/apexrest/coffeeandtips/exemplo Content-type: application/json Parametros: Authorization : Bearer “Token Obtido no passo anterior” É isso pessoal. Espero ter contribuído. Até a próxima!

  • MySQL: Criando um schema e migrando dados

    Não é raro que em meio a um projeto apareça a necessidade de fazer uma migração de dados. E quando pensamos na arquitetura de micro-serviços, começar separando os dados por schemas pode ser um primeiro passo para deixar o monolito para trás. Vamos lá!! O primeiro passo é criar um novo schema no MySQL, que pode ser feito com o seguinte comando: CREATE SCHEMA new_schema; Pronto! Agora já podemos iniciar a migração para o novo schema. A primeira coisa é copiar a estrutura de todas as tabelas que você deseja migrar. Da seguinte forma: CREATE TABLE new_schema.table_1 LIKE old_schema.table_1; CREATE TABLE new_schema.table_2 LIKE old_schema.table_2; CREATE TABLE new_schema.table_3 LIKE old_schema.table_3; Se fizermos um select agora em uma das tabelas do novo schema, vamos perceber que a tabela está criada exatamente com a mesma estrutura da antiga, porém estão todas vazias. Então, por fim, vamos fazer a migração dos dados. INSERT new_schema.table_1 SELECT * FROM old_schema.table_1; INSERT new_schema.table_2 SELECT * FROM old_schema.table_2; INSERT new_schema.table_3 SELECT * FROM old_schema.table_3; Um lembrete. Antes de fazer a cópia dos dados, é importante “desligar” qualquer aplicação que faça operações na base antiga para evitar perda de dados. Então é isso, seus dados já estão migrados e você já pode começar a usá-los. Até a próxima!!!

  • Java para iniciantes: Lendo e escrevendo arquivos de forma simples

    Existem muitas formas diferentes de manipular arquivos em Java. Algumas soluções podem chegar facilmente a 10 linhas de código (dependendo também da formatação do código) só para ler um arquivo e fazer um print no console. Felizmente, com as evoluções na linguagem através dos anos, essa tarefa se tornou bastante simples. Então, aqui vai um exemplo bem simples para vocês. Vamos lá!!! Para esse exemplo, vamos precisar importar as seguintes classes: import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; Para ler um arquivo de texto por exemplo, podemos usar a seguinte solução: private void read() throws IOException { String filePath = "/tmp/filetoread.txt"; Path path = Paths.get(filePath); Files.lines(path).forEach(line -> System.out.println(line)); } Essa solução vai funcionar em um ambiente linux, por causa do formato da string filePath. Para que funcione em um ambiente windows, podemos simplesmente alterar para: String filePath = "C:\\coffeeandtips\\tests\\filetoread.txt"; Bom, então após ler um arquivo com três linhas de código (que ainda pode ser reduzido para duas), vamos escrever um arquivo de forma bem resumida. private void write() throws IOException { String filePath = "/tmp/filewrited.txt"; Files.write(Path.of(filePath), "Write a phrase.".getBytes()); } Da mesma forma que o exemplo anterior, esse formato de path só irá funcionar no ambiente linux, para executar em ambiente windows é só alterar para: String filePath = "C:\\coffeeandtips\\tests\\filewrited.txt"; Então é isso pessoal. Espero ter contribuído. Até a próxima.

  • Upload de arquivo no S3 com AWS SDK e Java

    A Amazon Web Services AWS é um dos serviços de Cloud Computing mais tradicionais e com mais recursos no mercado. Neste post vamos ensinar como fazer um upload de arquivo para um bucket S3. Neste post vamos criar um código capaz de fazer um upload de arquivo no S3 utilizando Java e a SDK da AWS. Dependências Maven com.amazonaws aws-java-sdk-s3 com.amazonaws aws-java-sdk-bom 1.11.327 pom import Código de Upload import com.amazonaws.regions.Regions; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3ClientBuilder; import com.amazonaws.services.s3.model.ObjectMetadata; import com.amazonaws.services.s3.model.PutObjectRequest; import java.io.File; public class UploadService { public void upload() throws Exception { try { String BUCKET = "SEU-BUCKET"; AmazonS3 amazonS3Client = AmazonS3ClientBuilder .standard().withRegion(Regions.US_EAST_1) .build(); File file = new File("imagem.jpg"); PutObjectRequest putObjectRequest = new PutObjectRequest(BUCKET, "nome-do-arquivo", file); ObjectMetadata objectMetadata = new ObjectMetadata(); objectMetadata.setContentType("jpg"); putObjectRequest.setMetadata(objectMetadata); amazonS3Client.putObject(putObjectRequest); } catch (Exception e) { throw new Exception(e); } } } No código acima, temos um exemplo simples de upload de arquivos para o S3. Nele estamos enviando um arquivo do tipo .jpg. Passo a passo A variável BUCKET deve ser substituído pelo seu Bucket já criado O objeto amazonS3Client recebe as configurações necessárias para efetuar o upload. Nesta configuração é necessário configurar a região, neste caso estamos utilizando a região US-EAST-1 Em seguida carregamos o arquivo chamado imagem.jpg para o objeto do tipo File para efetuar o upload O objeto putObjectRequest é criado com base no Bucket, nome do arquivo e o objeto do tipo File criado anteriormente. Dessa forma o objeto putObjectRequest possui todas as informações para efetuar o upload. O objeto objectMetadata possibilita configurar detalhes do arquivo, como tipo do conteúdo, header, criptografia e etc. E em seguida ele é setado no objeto putObjectRequest. E por fim, a requisição final utilizando o método putObject que será responsável por fazer o upload do arquivo contendo todas as informações e configurações setadas nos passos anteriores. Agora, acesso o S3 e verifique se o arquivo esteja presente e pronto. É isso, curtiu? Até mais!

bottom of page