<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title><![CDATA[Dados de indexação - Elasticsearch Labs]]></title>
    <description><![CDATA[Articles and tutorials from the Search team at Elastic]]></description>
    <copyright><![CDATA[© 2026. Elasticsearch B.V. All Rights Reserved]]></copyright>
    <image>
      <title><![CDATA[Dados de indexação - Elasticsearch Labs]]></title>
      <url>https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1121c0bf0e8a6e65/6a88da6340a1841030ef456f/search-labs-thumbnail.png</url>
      <link>https://www.elastic.co/pt/search-labs/blog/category/index-data</link>
    </image>
    <link>https://www.elastic.co/pt/search-labs/blog/category/index-data</link>
    <atom:link href="https://www.elastic.co/pt/search-labs/rss/category/index-data.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[pt]]></language>
    <lastBuildDate>Mon, 28 Sep 2026 00:42:02 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Quando o TSDS encontra o ILM: projetando fluxos de dados de séries temporais que aceitam dados tardios]]></title>
    <description><![CDATA[Como os limites de tempo do TSDS interagem com as fases do ILM e como projetar políticas que tolerem métricas atrasadas.]]></description>
    <content:encoded><![CDATA[<p>Recentemente, migrei o cluster de métricas de um cliente de "tudo na camada ativa" para uma arquitetura hot/cold/frozen. Era uma mudança que eu já havia feito dezenas de vezes antes. Em poucos minutos, o Logstash parou completamente de avançar os dados.</p><p>O Elasticsearch estava rejeitando métricas de chegada tardia. Essas rejeições fizeram o pipeline ficar atrasado, resultando em dados mais tardios, o que desencadeou ainda mais rejeições. Com o tempo, o pipeline parou completamente.</p><p>Tivemos que restaurar a partir do snapshot, reindexar os dados e redesenhar o pipeline de ingestão para recuperar.</p><p>A causa raiz não era a gestão de ciclo de vida de índices (ILM) em si. Tratava-se de fluxos de dados de séries temporais (TSDS) e como eles aplicam índices de apoio com limite temporal.</p><p>O TSDS pode reduzir os requisitos de armazenamento para métricas em 40–70%, mas as mudanças na arquitetura que tornam o TSDS eficiente também alteram a forma como os índices se comportam ao longo do tempo. Essas mudanças são importantes ao projetar políticas de ILM ou quando seus pipelines de ingestão podem produzir dados tardios.</p><h2>TL;DR</h2><p>Ao usar o TSDS:</p><ul><li><p>Índices de suporte aceitam apenas documentos dentro de uma janela de tempo específica.</p></li><li><p>Se dados tardios chegarem após um índice se tornar frio ou congelado, o Elasticsearch rejeitará esses documentos ou os encaminhará para o armazenamento de falhas, caso esteja configurado.</p></li></ul><p>Regra de design:</p>warm_min_age &gt; rollover_max_age + maximum_expected_lateness<h2>O que é um fluxo de dados de séries temporais?</h2><p>Um<em> fluxo de dados de série temporal</em> (TSDS) é um fluxo de dados especializado otimizado para dados métricos. Os dados são roteados de modo que documentos relacionados fiquem localizados dentro dos mesmos fragmentos, otimizando-os para consulta e recuperação. Como o Elasticsearch faz isso:</p><p>Cada documento contém:</p><ul><li><p>Um registro de data e hora.</p></li><li><p>Campos dimensionais que identificam a série de tempo.</p></li><li><p>Campos métricos representando valores medidos.</p></li></ul><p>Alguns exemplos:</p><ul><li><p>Uso da CPU por host.</p></li><li><p>Solicitar latência por serviço.</p></li><li><p>Leituras de temperatura por sensor.</p></li></ul><p><em>As dimensões </em>identificam o que queremos medir, enquanto <em>as métricas </em>representam valores que mudam com o tempo.</p><h3>Dimensões</h3><p>Dimensões descrevem a entidade medida.</p><p>Exemplos:</p>host.name
service.name
container.id<p>Definimos eles em mapeamentos com:</p>time_series_dimension: true<h3>Métricas</h3><p>Métricas representam valores numéricos e são definidas usando:</p>time_series_metric<p>Tipos comuns de métricas:</p><ul><li><p>Indicador: Valores que sobem e descem.</p></li><li><p>Contador: valores que aumentam até serem reiniciados.</p></li></ul><p>O Elastic Agent coleta principalmente métricas e dados de log. Mesmo que você não tenha habilitado manualmente nenhum índice TSDS, ainda pode tê-los no seu cluster.</p><h3>O campo _tsid</h3><p>O Elasticsearch gera internamente um valor <code>_tsid</code> a partir dos campos de dimensão. Isso permite que documentos com dimensões idênticas sejam roteados para o mesmo shard, melhorando:</p><ul><li><p>Compressão.</p></li><li><p>Local da consulta.</p></li><li><p>Desempenho de agregações.</p></li></ul><h2>A principal diferença: índices de apoio com prazo definido</h2><p>Os fluxos de dados tradicionais sempre gravam no índice de suporte mais recente, chamado <em>índice de gravação</em>, mas o TSDS se comporta de maneira diferente.</p><p>Cada índice de apoio TSDS tem uma janela de tempo definida e aceita apenas documentos com <code>@timestamp</code> valores que se encaixam nessa janela:</p>GET _data_stream/my-metrics-data-stream


     "index_mode": "time_series",
     "time_series": {
       "temporal_ranges": [
         {
           "start": "2026-01-15T14:35:50.000Z",
           "end": "2026-03-16T11:34:40.000Z"
         }
       ]
     }<p>Quando um documento é indexado, o Elasticsearch encaminha o documento para o índice de suporte responsável por aquele timestamp, o que significa que, ao contrário dos índices tradicionais, um TSDS pode gravar em vários índices de suporte simultaneamente.</p><p>Por exemplo:</p><ul><li><p>Dados em tempo real → índice mais recente.</p></li><li><p>Dados tardios → índice anterior cobrindo esse intervalo de tempo.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7b001853af30d5f8/6a17dc2cfaa9137a7d93c751/31af2bb3b3dc24db8342e791e1db77a44659ba7a-1589x502.png" alt="Linha do tempo mostrando como um documento tardio é direcionado para um índice mais antigo, enquanto um documento atual vai para o índice mais recente." /><h2>Projetando para dados tardios</h2><p>Os pipelines de ingestão reais raramente entregam métricas perfeitamente no prazo. As métricas podem ser atrasadas por interrupções de rede, acúmulos no caminho, ingestão em lote e perda de dispositivos de borda, que se reconectam e começam a recuperar o atraso.</p><p>Índices tradicionais absorvem silenciosamente esses atrasos. O TSDS não.</p><p>Se o carimbo de data/hora de um documento estiver fora da faixa de índices de apoio graváveis, o Elasticsearch o rejeitará, o que significa que sua política de ILM deve considerar os dados tardios.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6e8eae1b2ddad142/6a17dc2e1d1b8335a793e35c/32a103b95b20e31615c214271e27811a7ee315ae-1999x691.png" alt="Linha do tempo do ciclo de vida do índice" /><h2>A restrição crítica</h2><p>Os índices de suporte precisam permanecer com permissão de escrita por tempo suficiente para receber dados com atraso.</p><p>Em termos práticos:</p>time_until_readonly &gt; maximum_expected_lateness<p>Como o ILM mede o tempo de existência a partir do rollover, a regra operacional passa a ser:</p>warm_or_cold_min_age &gt; rollover_max_age + maximum_expected_lateness<p></p><p>Por exemplo, se as métricas podem chegar até seis horas atrasadas, os índices devem permanecer graváveis pelo menos seis horas após o rollover.</p><p></p><p>Desconsiderar essa restrição foi exatamente o que causou a falha de ingestão descrita anteriormente. Os dados tardios eram direcionados para um índice anterior, que já estava na camada cold e, portanto, era bloqueado para escrita.</p><p></p><h2>Tratamento de documentos rejeitados</h2><p>Quando o TSDS rejeita um documento, o Elasticsearch retorna um erro, indicando que o carimbo de data e hora não está dentro da faixa de índices graváveis. Como seu pipeline de ingestão lida com esse erro determina se você perde dados ou trava a ingestão de dados.</p><p>O principal mecanismo para lidar com documentos rejeitados é o armazenamento de falhas.</p><h3>Repositório de falhas (recomendado no Elasticsearch 9.1+)</h3><p>O Elasticsearch 9.1 introduziu o armazenamento de falhas, que captura automaticamente documentos rejeitados. Em vez de retornar erros aos clientes, o Elasticsearch grava documentos rejeitados em um índice dedicado de falhas dentro do fluxo de dados.</p><p>Você pode inspecionar falhas usando:</p>GET metrics-myapp::failures/_search<p>O uso do armazenamento de falhas impede que os pipelines de ingestão travem devido a erros de rejeição, enquanto preserva os dados com falha para análise ou <a href="https://www.elastic.co/docs/manage-data/data-store/data-streams/reindex-tsds">reindexação</a>.</p><h2>Monitoramento de questões de rejeição</h2><p>Os problemas de chegada tardia geralmente aparecem primeiro como anomalias de ingestão. Você pode notá-los primeiro como:</p><ul><li><p>Quedas repentinas na taxa de indexação.</p></li><li><p>Picos nos documentos rejeitados.</p></li><li><p>Um número crescente de entradas de lojas que falham.</p></li><li><p>Diferenças de incompatibilidade entre entradas e saídas do pipeline contagem.</p></li></ul><p>Alertas nesses sinais permitem que os operadores detectem problemas antes que os pipelines parem. Fluxos de trabalho, trabalhos de Machine Learning e outros mecanismos podem ser usados para automatizar a detecção e notificação.</p><h2>Lista de verificação de migração para TSDS + ILM</h2><p>Se você estiver migrando um cluster de métricas para o TSDS, introduzindo a hierarquização do ILM ou atualizando para uma versão do Elasticsearch em que as métricas são TSDS por padrão, revise esses itens primeiro.</p><h3><strong>1. Medir a latência de ingestão</strong></h3><p>Antes de mudar as políticas de ILM, determine:</p><ul><li><p>Atraso normal na ingestão de dados.</p></li><li><p>Pior caso de atraso durante os incidentes.</p></li><li><p>Atrasos causados por pipelines em lote.</p></li></ul><p>O projeto do seu ILM deve acomodar o máximo de atraso realista.</p><h3><strong>2. Verificar as janelas de tempo do índice</strong></h3><p>Inspecione seus índices de respaldo de TSDS:</p>GET _data_stream/&lt;your-stream&gt;<p>Analise:</p><ul><li><p><code>time_series.start_time</code></p></li><li><p><code>time_series.end_time</code></p></li></ul><p>Esses limites determinam quais índices podem aceitar documentos. Entender essas janelas pode ajudar a determinar o quanto os dados podem estar atrasados antes de serem rejeitados.</p><h3><strong>3. Dimensione o nível hot para chegadas tardias</strong></h3><p>Garanta que os índices backing permaneçam graváveis por tempo suficiente para os dados tardios.</p><p>Regra operacional:</p><ul><li><p><code>warm_min_age &gt; rollover_max_age + maximum_expected_lateness</code></p></li></ul><p>Lembre-se, os índices devem permanecer graváveis por pelo menos seis horas se as métricas chegarem com seis horas de atraso.</p><h3><strong>4. Decida o que fazer com documentos rejeitados</strong></h3><p>Escolha uma estratégia antes de ativar o TSDS:</p><ul><li><p>Armazenamento de falhas (recomendado no Elasticsearch 9.1+).</p></li><li><p>Fila de dead letter do Logstash.</p></li><li><p>Índice de contingência para chegadas tardias.</p></li><li><p>Aceitar a perda limitada de dados.</p></li></ul><h3><strong>5. Monitorar a saúde da ingestão</strong></h3><p>Adicionar alertas para:</p><ul><li><p>A taxa de indexação cai.</p></li><li><p>Documentos rejeitados.</p></li><li><p>Crescimento do armazenamento de falhas.</p></li><li><p>Desajustes de entrada/saída do pipeline.</p></li></ul><p>Problemas de dados tardios geralmente aparecem primeiro como anomalias de ingestão.</p><h2>Resumo</h2><p>Fluxos de dados de séries temporais oferecem grandes melhorias de armazenamento e desempenho para cargas de trabalho de métricas, mas introduzem uma mudança arquitetônica importante: os índices de suporte têm limite temporal, o que afeta o comportamento do ILM.</p><p>Ao usar o TSDS:</p><ul><li><p>Os índices devem permanecer graváveis tempo suficiente para aceitar dados tardios.</p></li><li><p>Os pipelines de ingestão devem lidar com documentos rejeitados com segurança.</p></li></ul><p>A regra fundamental a lembrar é:</p>warm_min_age &gt; rollover_max_age + maximum_expected_lateness<p>Se você projetar políticas de ILM em torno dessa restrição, o TSDS funcionará extremamente bem para cargas de trabalho de métricas.</p><p>Se ignorar isso, seu pipeline de ingestão pode descobrir esses limites de tempo da pior forma.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/tsds-ilm-elasticsearch</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/tsds-ilm-elasticsearch</guid>
    <category><![CDATA[Dados de indexação]]></category>
    <category><![CDATA[Banco de dados vetorial]]></category>
    <dc:creator><![CDATA[Bret Wortman]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcacf154aeacb29d8/6a17dc30dbb4ffc7ddfb557f/e4c46e4a6f746d9c845857e80de036f5d51cd4e7-1280x720.png" length="0" type="image/png"/>
    <pubDate>Thu, 02 Apr 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Elastic Open Web Crawler como código]]></title>
    <description><![CDATA[Aprenda a usar o GitHub Actions para gerenciar as configurações do Elastic Open Crawler, de forma que, sempre que enviarmos alterações para o repositório, elas sejam aplicadas automaticamente à instância implantada do crawler.]]></description>
    <content:encoded><![CDATA[<p>Com <a href="https://github.com/elastic/crawler">o Elastic Open Web Crawler</a> e sua arquitetura orientada por linha de comando, ter configurações de crawler versionadas e um pipeline de CI/CD com testes locais agora é bastante simples de se obter.</p><p>Tradicionalmente, o gerenciamento de rastreadores era um processo manual e propenso a erros. Isso envolvia editar configurações diretamente na interface do usuário e ter dificuldades com a clonagem de configurações de rastreamento, reversão, controle de versão e muito mais. Tratar as configurações do rastreador como código resolve isso, proporcionando os mesmos benefícios que esperamos no desenvolvimento de software: repetibilidade, rastreabilidade e automação.</p><p>Esse fluxo de trabalho facilita a integração do Open Web Crawler ao seu pipeline de CI/CD para reversões, backups e migrações — tarefas que eram muito mais complicadas com versões anteriores do Elastic Crawler, como o Elastic Web Crawler ou o App Search Crawler.</p><p>Neste artigo, vamos aprender como:</p><ul><li><p>Gerencie nossas configurações de rastreamento usando o GitHub.</p></li><li><p>Ter um ambiente local para testar pipelines antes da implantação.</p></li><li><p>Criar um ambiente de produção para executar o rastreador web com novas configurações sempre que enviarmos alterações para nossa branch principal.</p></li></ul><p>Você pode encontrar o repositório do projeto <a href="https://github.com/llermaly/elastic-open-crawler-as-code"><em><strong>aqui</strong></em></a><em><strong>. </strong></em><em>No momento em que escrevo, estou usando o Elasticsearch 9.1.3 e o Open Web Crawler 0.4.2.</em></p><h2>Pré-requisitos</h2><ul><li><p>Docker Desktop</p></li><li><p>instância do Elasticsearch</p></li><li><p>Máquina virtual com acesso SSH (por exemplo, AWS EC2) e Docker instalado.</p></li></ul><h2>Etapas</h2><ol><li><p>Estrutura de pastas</p></li><li><p>Configuração do rastreador</p></li><li><p>Arquivo Docker-compose (ambiente local)</p></li><li><p>Ações do GitHub</p></li><li><p>Testando localmente</p></li><li><p>Implantação em produção</p></li><li><p>Realizar alterações e redistribuir</p></li></ol><h2>Estrutura de pastas</h2><p>Para este projeto, teremos a seguinte estrutura de arquivos:</p>├── docker-compose.yml # Local elasticsearch + crawler
├── config/crawler-config.yml # Crawler config
├── .github/workflows/deploy.yml # GH Action to deploy changes
├── local.sh # Script to run our local crawler<h2>Configuração do rastreador</h2><p>Em <code>crawler-config.yml,</code> colocaremos o seguinte:</p>output_sink: elasticsearch
output_index: web-crawl-index
max_crawl_depth: 1

elasticsearch:
  host: ${ES_HOST}
  api_key: ${ES_API_KEY}
     
domains:
  - url: https://web-scraping.dev
    seed_urls:
      - https://web-scraping.dev/product/1
      - https://web-scraping.dev/product/2
      - https://web-scraping.dev/product/3<p>Este script irá extrair dados de <a href="https://web-scraping.dev/products">https://web-scraping.dev/products</a>, um site fictício para produtos. Iremos rastrear apenas as três primeiras páginas de produtos. A configuração <code>max_crawl_depth</code> impedirá que o rastreador descubra mais páginas do que as definidas como <code>seed_urls</code> , não abrindo os links dentro delas.</p><p>Elasticsearch <code>host</code> e <code>api_key</code> serão preenchidos dinamicamente dependendo do ambiente em que estamos executando o script.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7d37b966aafbd3c1/6a17ef9842022946e929f6b9/f9831034e1c4ccb554d37bdd188f2824338355a0-890x624.png" alt="Página do produto &quot;Caixa de Balas de Chocolate&quot; do domínio web-scraping.dev, um site simulado para testes de web scraping. A página exibe o título do produto, a imagem, a descrição e os elementos HTML para o preço e os botões de compra." /><h2>Arquivo Docker-compose (ambiente local)</h2><p>Para o ambiente local <code>docker-compose.yml,</code> implantaremos o rastreador e um único cluster Elasticsearch + Kibana, para que possamos visualizar facilmente os resultados do rastreamento <em><strong>antes</strong></em> da implantação em produção.</p>services:
  es01:
    image: docker.elastic.co/elasticsearch/elasticsearch:9.1.3
    environment:
      - discovery.type=single-node
      - xpack.security.enabled=false
      - ES_JAVA_OPTS=-Xms1g -Xmx1g
    ports:
      - "9200:9200"
    networks: [esnet]
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9200"]
      interval: 5s
      timeout: 5s
      retries: 10

  kibana:
    image: docker.elastic.co/kibana/kibana:9.1.3
    environment:
      - ELASTICSEARCH_HOSTS=http://es01:9200
    ports:
      - "5601:5601"
    networks: [esnet]
    depends_on: [es01]

  crawler:
    image: docker.elastic.co/integrations/crawler:0.4.2
    environment:
      - ES_HOST=http://es01:9200
      - CRAWLER_JRUBY_OPTS=--server
    container_name: crawler
    volumes:
      - ./config:/home/app/config
    networks: [esnet]
    entrypoint: ["/home/app/bin/crawler", "crawl", "/home/app/config/crawl-config-final.yml"]
    stdin_open: true
    tty: true

networks:
  esnet:
    driver: bridge<p>Observe como o rastreador aguarda até que o Elasticsearch esteja pronto para ser executado.</p><h2>Ações do GitHub</h2><p>Agora precisamos criar uma ação do GitHub que copie as novas configurações e execute o rastreador em nossa máquina virtual a cada push para o repositório principal. Isso garante que sempre tenhamos a configuração mais recente implantada, sem precisar entrar manualmente na máquina virtual para atualizar arquivos e executar o rastreador. Vamos usar o AWS EC2 como provedor de máquinas virtuais.</p><p>O primeiro passo é adicionar o host (<code>VM_HOST</code>), o usuário da máquina (<code>VM_USER</code>), a chave SSH RSA (<code>VM_KEY</code>), o host do Elasticsearch (<code>ES_HOST</code>) e a chave da API do Elasticsearch (<code>ES_API_KEY</code>) aos segredos da ação do GitHub:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb5a0fcfff9b7f997/6a17ef9a6df731d7d40a0fdf/e1075bc54151b4b94eac2a6bd2682e9997e6c709-1106x707.png" alt="Uma página de configuração de &quot;ações, segredos e variáveis&quot;, que exibe segredos do repositório, como VM_HOST, VM_KEY e VM_USER, em uma interface baseada na web." /><p>Dessa forma, a ação poderá acessar nosso servidor para copiar os novos arquivos e executar a indexação.</p><p>Agora, vamos criar nosso arquivo <code>.github/workflows/deploy.yml</code> :</p>name: Deploy

on:
  push:
    branches: [main]

jobs:
  Deploy:
    name: Deploy to EC2
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v5

      - name: Deploy crawler
        env:
          HOSTNAME: ${{ secrets.VM_HOST }}
          USER_NAME: ${{ secrets.VM_USER }}
          PRIVATE_KEY: ${{ secrets.VM_KEY }}
          ES_HOST: ${{ secrets.ES_HOST }}
          ES_API_KEY: ${{ secrets.ES_API_KEY }}
        run: |
          # Save private key
          echo "$PRIVATE_KEY" &gt; private_key
          chmod 600 private_key

          # Generate final config locally
          envsubst &lt; config/crawler-config.yml &gt; config/crawl-config-final.yml

          # Copy the config folder to VM
          scp -o StrictHostKeyChecking=no -i private_key -r config ${USER_NAME}@${HOSTNAME}:~/config

          # SSH into VM and run crawler
          ssh -o StrictHostKeyChecking=no -i private_key ${USER_NAME}@${HOSTNAME} &lt;&lt; EOF
            docker run --rm \
              -v ~/config:/config \
              docker.elastic.co/integrations/crawler:latest jruby \
              bin/crawler crawl /config/crawl-config-final.yml
          EOF<p>Essa ação executará os seguintes passos sempre que enviarmos alterações para o arquivo de configuração do rastreador:</p><ol><li><p>Preencha o arquivo de configuração YAML com o host e a chave da API do Elasticsearch.</p></li><li><p>Copie a pasta de configuração para a nossa máquina virtual.</p></li><li><p>Conecte-se à nossa VM via SSH.</p></li><li><p>Execute o rastreamento com a configuração que acabamos de copiar do repositório.</p></li></ol><h2>Testando localmente</h2><p>Para testar nosso rastreador localmente, criamos um script bash que popula o host do Elasticsearch com a versão local do Docker e inicia uma busca. Você pode executar <code>./local.sh</code> para executá-lo.</p>#!/bin/bash

# Exit on any error
set -e

# Load environment variables
export ES_HOST="http://es01:9200"

# Generate final crawler config
envsubst &lt; ./config/crawler-config.yml &gt; ./config/crawl-config-final.yml

# Bring everything up
docker compose up --build<p>Vamos verificar as Ferramentas de Desenvolvedor do Kibana para confirmar se o campo<code> web-crawler-index</code> foi preenchido corretamente:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt989660368fe14db8/6a17ef9b9da390c79ce46562/18551635e8265866e389a9632c4e4540958e4468-990x723.png" alt="Código do Kibana DevTools para confirmar se o índice do rastreador web está configurado corretamente." /><h2>Implantação em produção</h2><p>Agora estamos prontos para enviar a alteração para a branch principal, o que implantará o crawler em sua máquina virtual e começará a enviar logs para sua instância do Elasticsearch Serverless.</p>git add .
git commit -m "First commit"
git push<p>Isso acionará a ação do GitHub, que executará o script de implantação na máquina virtual e iniciará a indexação.</p><p>Você pode confirmar se a ação foi executada acessando o repositório do GitHub e visitando a aba “Ações”:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt986f1a4e4f3288d2/6a17ef9c7f6f1584fdc09c10/67ba3a7164d7a8049fe5661264820826cb18ed64-667x325.png" alt="As ações são implantadas na aba EC2 de um repositório GitHub." /><h2>Realizar alterações e redistribuir</h2><p>Algo que você pode ter notado é que o <code>price</code> de cada produto faz parte do corpo do documento. O ideal seria armazenar o preço em um campo separado para que pudéssemos aplicar filtros a ele.</p><p>Vamos adicionar essa alteração ao arquivo <code>crawler.yml</code> para usar <a href="https://github.com/elastic/crawler/blob/main/docs/features/EXTRACTION_RULES.md">regras de extração</a> para extrair o preço da classe CSS <code>product-price</code> :</p>output_sink: elasticsearch
output_index: web-crawl-index
max_crawl_depth: 1

elasticsearch:
  host: ${ES_HOST}
  api_key: ${ES_API_KEY}
     
  # Index ingest pipeline to process documents before indexing          
  pipeline_enabled: true
  pipeline: pricing-pipeline

domains:
  - url: https://web-scraping.dev
    seed_urls:
      - https://web-scraping.dev/product/1
      - https://web-scraping.dev/product/2
      - https://web-scraping.dev/product/3
    extraction_rulesets:
      - url_filters:
          - type: ends
            pattern: /product/*
        rules:
          - action: extract
            field_name: price
            selector: .product-price
            join_as: string
            source: html<p>Também vemos que o preço inclui um sinal de dólar (<code>$</code>), que devemos remover se quisermos executar consultas de intervalo. Podemos usar um pipeline de ingestão para isso. Observe que estamos fazendo referência a ele em nosso novo arquivo de configuração do rastreador acima:</p>PUT _ingest/pipeline/pricing-pipeline
{
  "processors": [
    {
      "script": {
        "source": """
                ctx['price'] = ctx['price'].replace("$","")
            """
      }
    }
  ]
}<p>Podemos executar esse comando em nosso cluster Elasticsearch de produção. Para o desenvolvimento, como é efêmero, podemos fazer com que a criação do pipeline faça parte do arquivo <code>docker-compose.yml</code> adicionando o seguinte serviço. Observe que também adicionamos um <code>depends_on</code> ao serviço de rastreamento para que ele seja iniciado após a criação bem-sucedida do pipeline.</p> crawler:
    image: docker.elastic.co/integrations/crawler:0.4.2
    environment:
      - ES_HOST=http://es01:9200
      - CRAWLER_JRUBY_OPTS=--server
    container_name: crawler
    volumes:
      - ./config:/home/app/config
    networks: [esnet]
    entrypoint: ["/home/app/bin/crawler", "crawl", "/home/app/config/crawl-config-final.yml"]
    depends_on:
      pipeline-init:
        condition: service_completed_successfully
    stdin_open: true
    tty: true  


  pipeline-init:
    image: curlimages/curl:latest
    depends_on:
      es01:
        condition: service_healthy
    networks: [esnet]
    entrypoint: &gt;
        sh -c "
        echo 'Creating ingest pipeline...';
        curl -s -X PUT http://es01:9200/_ingest/pipeline/pricing-pipeline \\
          -H 'Content-Type: application/json' \\
          -d '{\"processors\":[{\"script\":{\"source\":\"ctx.price = ctx.price.replace(\\\"$\\\", \\\"\\\")\"}}]}';
        echo 'Pipeline created!';
        "<p>Agora vamos executar <code>`./local.sh`</code> para ver a alteração localmente:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0f390aedf67cb4fe/6a17ef9eaf47b62bd2cde05b/dc1801599344a9f69f072b07ff828c4ba3815d7b-738x473.png" alt="Executando `./local.sh` para ver a alteração de preço localmente." /><p>Ótimo! Agora vamos impulsionar a mudança:</p>git add crawler-config.yml
git commit -m "added price CSS selector"
git push<p>Para confirmar se tudo funciona corretamente, você pode verificar seu Kibana de produção, que deverá refletir as alterações e mostrar o preço como um novo campo sem o símbolo de dólar.</p><h2>Conclusão</h2><p>O Elastic Open Web Crawler permite que você gerencie seu crawler como código, o que significa que você pode automatizar todo o pipeline — do desenvolvimento à implantação — e adicionar ambientes locais efêmeros e testes com os dados rastreados programaticamente, para citar alguns exemplos.</p><p>Você está convidado a clonar o repositório oficial e começar a indexar seus próprios dados usando este fluxo de trabalho. Você também pode ler <a href="https://www.elastic.co/search-labs/blog/semantic-search-open-crawler">este artigo</a> para aprender como executar uma pesquisa semântica em índices produzidos pelo rastreador.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elastic-open-crawler-config-as-code</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elastic-open-crawler-config-as-code</guid>
    <category><![CDATA[Dados de indexação]]></category>
    <category><![CDATA[Operações]]></category>
    <dc:creator><![CDATA[Gustavo Llermaly]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt00e7c95012dc38cc/6a17efa0fbc5f80dad491b93/0ac41f55c85ad3f647cb0e0d750ed80bacd397f3-1036x581.png" length="0" type="image/png"/>
    <pubDate>Mon, 22 Sep 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Como exibir os campos de um índice do Elasticsearch]]></title>
    <description><![CDATA[Aprenda como exibir os campos de um índice do Elasticsearch usando as APIs _mapping e _search, subcampos, _source sintético e campos de tempo de execução.]]></description>
    <content:encoded><![CDATA[<p>Neste artigo, discutiremos como exibir os campos de um índice do Elasticsearch. Isso pode ser útil para entender a estrutura dos seus dados, identificar campos específicos e solucionar problemas. Abordaremos os seguintes tópicos:</p><ol><li><p>Utilizando a API <code>_mapping</code> para recuperar informações de campo</p></li><li><p>Utilizando a API <code>_search</code> para exibir valores de campo</p></li><li><p>Exibição de subcampos</p></li><li><p>_source sintética</p></li><li><p>Campos de tempo de execução</p></li></ol><h2>1. Utilizando a API _mapping para recuperar informações de campo</h2><p>A API <code>_mapping</code> permite recuperar a definição de mapeamento para um índice ou vários índices. Isso inclui informações sobre os campos, seus tipos de dados e outras propriedades. Para recuperar o mapeamento de um índice específico, utilize a seguinte solicitação:</p>GET /&lt;index_name&gt;/_mapping<p>Por exemplo, se você tiver um índice chamado <code>my_index</code>, poderá recuperar seu mapeamento com a seguinte solicitação:</p>GET /my_index/_mapping<p>A resposta incluirá a definição de mapeamento para o índice, que contém informações sobre os campos e suas propriedades.</p><p>Também é possível recuperar o mapeamento de um campo específico. Isso pode ser útil se o seu mapeamento for muito extenso e você quiser se concentrar apenas em um campo específico. Para obter o mapeamento de um campo específico, utilize a seguinte solicitação:</p>GET /my_index/_mapping/field/my_field<p>Você também pode recuperar os mapeamentos de vários campos separando seus nomes por vírgulas, como na seguinte solicitação:</p>GET /my_index/_mapping/field/my_field_1,my_field_2,my_field_3<h2>2. Usando a API _search para exibir valores de campo</h2><p>Para exibir os valores dos campos em um índice do Elasticsearch, você pode usar a API <code>_search</code> . A API <code>_search</code> oferece várias maneiras de controlar quais campos são retornados; as duas principais são:</p><ol><li><p><strong><code>_source</code></strong>O campo <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/mapping-source-field"><code>_source</code></a> contém o corpo original do documento JSON exatamente como foi indexado, incluindo quaisquer alterações feitas pelos pipelines de ingestão ou etapas de pré-processamento. Para exibir campos específicos do documento de origem, implemente a filtragem de origem, como veremos a seguir.</p></li><li><p><strong><code>fields</code></strong>O parâmetro <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/retrieve-selected-fields"><code>fields</code></a> permite recuperar campos específicos dos seus documentos ao realizar uma pesquisa, com base no mapeamento do índice. Ao contrário de <code>_source</code>, <code>fields</code> também pode retornar valores de campos armazenados, valores de documentos ou campos de tempo de execução sem fazer referência a <code>_source</code>, embora para campos padrão sem valores de documentos ou configurações armazenadas, ele recorra a <code>_source</code>. Isso pode trazer muitos benefícios, como melhoria de desempenho e outros, como veremos a seguir.</p></li></ol><h3>Usando o campo _source</h3><p>Por padrão, a API<code> _search</code> retorna o campo <code>_source</code> , que contém o documento JSON original que foi indexado. Para exibir campos específicos, você pode adicionar filtros no parâmetro <code>_source </code>da solicitação de pesquisa; isso é chamado de filtragem de origem.</p><p>Aqui está um exemplo de uma solicitação de pesquisa que retorna os valores dos campos <code>title </code>e <code>author</code> para documentos no índice <code>my_index</code> :</p>GET /my_index/_search
{
  "query": {
    "match_all": {}
  },
  "_source": ["title", "author"]
}<p>Neste exemplo, o parâmetro <code>_source</code> especifica os campos a serem retornados.</p><p>Se você precisar de ainda mais controle, pode usar as propriedades <code>includes</code> e <code>excludes </code>do objeto <code>_source</code> . Por exemplo, a consulta abaixo retorna o campo de nível superior <code>title</code> e todos os subcampos de <code>author</code> exceto <code>author.description</code>.</p>GET /my_index/_search
{
  "query": {
    "match_all": {}
  },
  "_source": {
     “includes”: [“title”, “author.*],
     “excludes”: [“author.description”]
  }
}<p>Neste exemplo, usamos o padrão <code>author.* </code>para recuperar todos os subcampos diretos do objeto <code>author </code> . Então excluímos explicitamente <code>author.description </code>para que apenas os outros campos de autor sejam retornados. Note que isso não traz nenhuma melhoria de desempenho, já que ainda precisa carregar e analisar o JSON de origem, mas pode reduzir o tamanho da resposta enviada pela rede.</p><h3>Usando o parâmetro de campos</h3><p>Você pode usar o parâmetro <code>fields</code> para filtrar os campos retornados na resposta da pesquisa. O uso de <code>fields</code> em vez de <code>_source</code> oferece diversas vantagens, incluindo:</p><ul><li><p><strong>Desempenho aprimorado: </strong><code>fields </code>pode retornar valores diretamente de <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/mapping-store">campos armazenados</a> ou <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/doc-values">valores de documentos</a> sem ter que carregar o <code>_source</code> completo, tornando o tamanho da carga útil da resposta menor.</p></li><li><p><strong>Saída formatada:</strong> Para campos padrão,<code> fields</code> pode recorrer a <code>_source</code> para obter os valores, mas ele analisa o mapeamento do índice para formatar corretamente a saída, como datas formatadas, tornando-as consistentes com o que é usado para agregações e classificação.</p></li><li><p><strong>Acesso a campos de tempo de execução:</strong> <code>fields</code> pode retornar campos de tempo de execução, que não existem no <code>_source</code> original.</p></li><li><p>Você pode encontrar mais benefícios <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/retrieve-selected-fields#search-fields-param">aqui</a>.</p></li></ul><p>Por exemplo, para retornar apenas os campos <code>title</code> e <code>author</code> no índice <code>my_index</code> , você pode usar a seguinte solicitação de pesquisa:</p>GET /my_index/_search
{
  "query": {
    "match_all": {}
  },
  "fields": ["title", "author"],
  "_source": false
}<p>Na consulta acima, definimos o campo <code>_source </code>como falso para não retornarmos o documento de origem. Isso pode minimizar drasticamente o tamanho da carga útil da resposta, mas lembre-se de que isso só funciona porque os campos <code>title</code> e <code>author</code> são do tipo de campo <code>keyword </code> , que têm <code>doc_values</code> habilitado por padrão. Se o campo não tiver <code>doc_values</code> habilitado e <code>_source</code> estiver definido como falso, o Elasticsearch não terá como recuperá-los e eles serão ignorados na resposta.</p><p>É importante notar que a resposta <code>fields</code> sempre retorna uma matriz de valores para cada campo, mesmo que haja apenas um único valor. Isso ocorre porque o Elasticsearch não possui um tipo de array dedicado, e qualquer campo pode ter vários valores. Para obter mais informações sobre arrays no Elasticsearch, clique <a href="http://elastic.co/docs/reference/elasticsearch/mapping-reference/array">aqui</a>.</p><h3>Outras formas de recuperar campos</h3><p>Embora a recuperação de campos usando <code>_source</code> ou <code>fields</code> sejam os métodos recomendados, existem outros métodos disponíveis para casos de uso específicos, como:</p><p><strong>Campos de valor do documento:</strong> Se você quiser evitar <code>_source</code> completamente, você pode pesquisar usando o parâmetro <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/retrieve-selected-fields#docvalue-fields"><code>docvalue_fields</code></a> . Os valores do documento armazenam os mesmos valores de campo que <code>_source</code> , mas em uma estrutura de dados em disco, otimizada para classificação e agregações.</p><p>Como é separado dos valores armazenados com <code>_source</code>, você pode solicitar campos específicos sem carregar todo o <code>_source</code>. Isso é útil se você estiver consultando documentos grandes, mas precisar apenas de alguns campos pequenos que suportem valores do tipo "doc". Outro caso de uso para usar <code>docvalue_fields </code>é quando você deseja usar formatação personalizada nos campos <code>date</code> e <code>numeric</code> , como veremos no exemplo abaixo.</p><p>Observe que isso só funciona para campos que você habilita <code>doc_values</code> ou para tipos de campo que o têm habilitado por padrão, como <code>keyword</code>, <code>date</code>, tipos numéricos e <code>boolean</code>, não para <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/text"><code>text</code></a> ou <a href="https://www.elastic.co/docs/reference/elasticsearch/plugins/mapper-annotated-text-usage"><code>annotated_text</code></a>.</p><p>Neste exemplo, usamos o parâmetro <code>docvalue_fields</code> para recuperar os campos <code>title</code>, <code>author</code> e <code>published</code> sem carregar o documento <code>_source</code> completo:</p>GET /my_index/_search
{
  "query": {
    "match_all": {}
  },
  "docvalue_fields": [
    "title",
    "author",
    {
      "field": "published",
      "format": "epoch_millis"
    }
  ],
  "_source": false
}<p>Quando esta consulta é executada, o Elasticsearch obtém os valores diretamente de seu armazenamento colunar em disco, em vez de referenciar o <code>_source </code>para cada documento. O campo <code>published</code> é retornado com o formato <code>epoch_millis</code> em vez do formato padrão, graças ao parâmetro <code>format</code> fornecido na consulta.</p><p><strong>Campos armazenados:</strong> Se você marcou explicitamente campos específicos como <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/mapping-store">armazenados</a> no mapeamento, você pode usar o parâmetro <code>stored_fields</code> para filtrar esses campos. Isso é útil se você deseja respostas resumidas apenas com esses campos específicos ou para campos que você armazenou deliberadamente para recuperação posterior. É armazenado separadamente de <code>_source</code>, portanto, este método também é útil para evitar a necessidade de carregar <code>_source</code>.</p><p>É importante notar que esta opção está desativada por padrão e geralmente não é recomendada. Em vez disso, utilize a filtragem de origem para retornar determinados subconjuntos do documento de origem original.</p><p>Na consulta de exemplo abaixo, usamos o parâmetro <code>stored_fields</code> para recuperar o campo <code>summary</code> , que tem a configuração de mapeamento de índice de ”<code>store”: true</code>.</p>GET /my_index/_search
{
  "query": {
    "match_all": {}
  },
  "stored_fields": ["summary"]
}<p>Quando esta consulta é executada, o Elasticsearch verifica se este campo foi marcado com <code>”store”: true</code>, se não o encontrar, irá ignorar o campo completamente.</p><h2>3. Exibição de subcampos</h2><p>Se o seu índice contiver subcampos, você pode usar a notação de ponto para especificar o caminho do campo no parâmetro <code>fields</code> . Note que os subcampos são diferentes do <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/nested">tipo de campo aninhado</a>. Por exemplo, se você tiver um subcampo chamado <code>address.city</code>, poderá incluí-lo na resposta da pesquisa desta forma:</p>GET /my_index/_search
{
  "query": {
    "match_all": {}
  },
  "fields": ["title", "author", "address.city"],
  "_source": false
}<p>Neste exemplo, a resposta da pesquisa incluirá os valores dos campos <code>title</code>, <code>author</code> e <code>address.city</code> .</p><h2>4. Fonte sintética</h2><p>Se você quiser manter a funcionalidade de usar<code> _source</code> , mas também economizar espaço em disco, você tem a opção de usar <code>_source</code> sintético em seu mapeamento de índice. <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/mapping-source-field#synthetic-source"><code>_source</code></a> <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/mapping-source-field#synthetic-source">sintético </a>é um recurso que permite ao Elasticsearch reconstruir o <code>_source</code> a partir de dados existentes, como campos armazenados e valores de documentos, mesmo quando <code>_source</code> está desativado. Isso permite economizar bastante espaço de armazenamento, ao custo de velocidades ligeiramente menores no momento da consulta, já que a reconstrução ocorre em tempo real. Ative este recurso usando os valores abaixo nas configurações do seu índice:</p>PUT idx
{
  "settings": {
    "index": {
      "mapping": {
        "source": {
          "mode": "synthetic"
        }
      }
    }
  }
}<p>Algumas vantagens de usar <code>_source </code>sintético incluem: exibição do documento completo ao usar a API <code>_search</code> , filtragem de origem e compatibilidade com outros recursos e ferramentas como o Kibana que esperam que <code>_source</code> esteja disponível, tudo isso evitando a necessidade de armazenar o documento <code>_source</code> completo.</p><h2>5. Campos de tempo de execução</h2><p><a href="https://www.elastic.co/docs/manage-data/data-store/mapping/runtime-fields">Os campos de tempo de execução</a> permitem definir campos com script no momento da consulta ou no mapeamento do índice, dentro de um bloco de tempo de execução. Esses campos nunca são indexados, portanto, adicionar um campo de tempo de execução não aumenta o tamanho do índice, mas nunca aparecerá em <code>_source</code>. Os campos de tempo de execução definidos no mapeamento são persistentes e estão disponíveis para todas as consultas, enquanto os campos de tempo de execução definidos no momento da consulta são temporários e estão disponíveis apenas nessa solicitação de pesquisa.</p><p>A principal vantagem de usar campos em tempo de execução é a capacidade de adicionar campos aos documentos depois de já os ter importado, simplificando as decisões de mapeamento. Os campos de tempo de execução também são ótimos para enriquecer seus documentos com valores que não existem no documento original, mas são gerados por meio de um script, como formatar uma string ou calcular uma pontuação.</p><p>Vale ressaltar também que os campos de tempo de execução podem prejudicar o desempenho, pois será necessário executar um script para cada documento no conjunto de resultados. Para <a href="https://www.elastic.co/docs/manage-data/data-store/mapping/retrieve-runtime-field">recuperar um campo de tempo de execução</a>, você também pode usar o parâmetro <code>fields</code> na API <code>_search</code> .</p><h2>Conclusão</h2><p>A exibição de campos de um índice Elasticsearch pode variar desde a simples recuperação de valores usando o mapeamento de índice ou o <code>_source</code>, até métodos mais avançados usando <code>fields</code>, <code>docvalue_fields</code> ou campos de tempo de execução para maior controle e eficiência. Compreender as vantagens e desvantagens de diferentes métodos é fundamental para otimizar suas experiências de busca. Seja para otimizar payloads, enriquecer documentos ou usar dados sintéticos <code>_source</code> para economizar armazenamento, o Elasticsearch oferece diversas ferramentas e recursos para encontrar os dados que você precisa, da maneira que você precisa. Essas técnicas podem ajudá-lo a entender a estrutura de seus dados, identificar campos específicos e solucionar problemas.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elasticsearch-index-show-fields</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elasticsearch-index-show-fields</guid>
    <category><![CDATA[Dados de indexação]]></category>
    <category><![CDATA[Mapeamentos]]></category>
    <dc:creator><![CDATA[JD Armada]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd041e871a8935448/6a17de320b0bedf404dd34ab/23b96aaa1a38b1f4747b4a87695d816f24c0cf70-720x421.jpg" length="0" type="image/jpeg"/>
    <pubDate>Wed, 06 Aug 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Scripting em Ruby no Logstash]]></title>
    <description><![CDATA[Saiba mais sobre o plugin de filtro Ruby para Logstash, que permite a transformação avançada de dados em seu pipeline Logstash.]]></description>
    <content:encoded><![CDATA[<p>O Logstash é um pipeline de processamento de dados que ingere dados de múltiplas fontes, os transforma e os envia para os destinos escolhidos. Os plugins de filtro são essenciais para esse processo; eles executam operações específicas nos seus dados à medida que estes percorrem o pipeline.</p><p>O Logstash inclui diversos filtros integrados para tarefas comuns, como analisar, enriquecer e modificar dados. Mas, às vezes, você encontrará cenários que exigem lógica personalizada que vai além do que esses filtros padrão podem fornecer. É aí que entra o <a href="https://www.elastic.co/docs/reference/logstash/plugins/plugins-filters-ruby">plugin de filtro Ruby</a> .</p><p><strong>O plugin de filtro Ruby permite executar código Ruby personalizado diretamente no seu pipeline Logstash.</strong> Quando os filtros padrão não são suficientes, o filtro Ruby permite lidar com transformações de dados complexas, implementar lógica de negócios personalizada ou integrar-se a sistemas externos.</p><p>Neste blog, vamos explorar como usar filtros em Ruby, desde o uso básico até o avançado.</p><h2>Quando você deve usar o filtro Ruby?</h2><p>Como arquiteto consultor da Elastic, vejo frequentemente clientes usando o Logstash para o pipeline de processamento de dados, embora atualmente ele não seja um mecanismo de processamento de dados de última geração. Eles frequentemente enfrentam dificuldades com as limitações dos filtros padrão quando se trata de manipulação complexa de dados ou lógica personalizada. Nesses casos, o filtro Ruby pode ajudar a superar esses desafios.</p><p>O filtro Ruby é útil quando os filtros padrão do Logstash não atendem às suas necessidades específicas. Aqui estão alguns casos de uso comuns:</p><ul><li><p><strong>Manipulação de dados aninhados em profundidade</strong>: Modifique estruturas JSON complexas, arrays dentro de arrays ou reestruture dados dinamicamente com base no conteúdo.</p></li><li><p><strong>Processamento avançado de strings</strong>: Analise e extraia dados estruturados de textos não estruturados.</p></li><li><p><strong>Implementação de lógica de negócios complexa</strong>: Crie transformações personalizadas que exigem lógica condicional, loops ou cálculos complexos.</p></li></ul><h2>Uso básico</h2><p>Vamos começar com um exemplo simples para entender como funciona o filtro Ruby.</p><h3>Configurando o filtro Ruby</h3><p>Ao criar um pipeline Logstash, você deve colocar o arquivo de configuração no diretório <code>/etc/logstash/conf.d</code> . Alternativamente, você pode usar a opção <code>-f</code> para especificar o caminho para o arquivo de configuração ao iniciar o Logstash manualmente, para que você possa experimentar seus pipelines facilmente.</p>$ ./bin/logstash -f /path/to/your_pipeline.conf<p>O arquivo de configuração deve ter a extensão <code>.conf</code> .</p><p>Para usar o filtro Ruby, defina um filtro <code>ruby</code> na seção de filtro do seu arquivo de configuração do pipeline Logstash (*.conf). Eis um exemplo básico:</p>filter {
  ruby {
    code =&gt; "
      event.set('new_field', 'Hello from Ruby!')
    "
  }
}<p>Este filtro Ruby embutido define uma instância de filtro Ruby dentro da sua configuração do Logstash. O parâmetro <code>code</code> fornece o script Ruby embutido que o Logstash executará para cada evento processado por este filtro. Dentro desse script, há uma variável <code>event</code> disponível que representa o próprio evento. O objeto de evento contém os dados originais enviados ao Logstash e quaisquer campos adicionais criados durante os estágios de filtragem do Logstash. Você pode acessar esses campos por meio da API de Eventos do Logstash, como <code>event.get()</code> e <code>event.set()</code>. Neste exemplo de código, <code>event.set('new_field', 'Hello from Ruby!')</code> definiu um novo campo chamado <code>new_field</code> com o valor da string <code>Hello from Ruby!</code>. Você pode adicionar qualquer outro código neste bloco <code>code</code> conforme necessário.</p><p>Note que este objeto <code>event</code> não é um objeto hash comum do Ruby, embora funcione como um contêiner de dados do tipo chave-valor. Consulte <a href="https://www.elastic.co/docs/reference/logstash/event-api">esta documentação oficial</a> para saber mais sobre a API de Eventos.</p><h3>Externalizar script Ruby</h3><p>Para transformações simples, o código Ruby embutido é conveniente. Porém, para lógica complexa ou funções reutilizáveis, recomenda-se mover o código para um script Ruby externo. Isso melhora a capacidade de manutenção e mantém a configuração do seu pipeline Logstash organizada.</p><p>Primeiro, crie um script Ruby e salve-o como <code>my_ruby_script.rb</code>. O script deve definir um método <code>filter</code> que processa o evento. Ela recebe um objeto de evento como argumento, que representa o evento atual que está sendo processado. O método <code>filter</code> precisa retornar uma matriz de eventos para emitir. Para descartar o evento, retorne um array vazio.</p><p>Por exemplo, o seguinte script lê o campo <code>message</code> , calcula seu comprimento e armazena o resultado em um novo campo chamado <code>message_length</code>.</p>def register(params)
  # This method is called when the plugin is loaded.
  # You can use it to initialize any instance variables or perform setup tasks.
end

def filter(event)
  message = event.get('message')

  if message
    event.set('message_length', message.length)
  end

  return [event]
end<p>Em seguida, defina a configuração do filtro Ruby para referenciar o script usando a opção <code>path</code> . Isso instrui o Logstash a carregar e executar o script externo. Ao usar scripts externos, certifique-se de que o arquivo existe e possui as permissões corretas.</p>filter {
  ruby {
    path =&gt; "/path/to/my_ruby_script.rb"
  }
}<p>Agora, cada evento é passado para o método <code>filter</code> em <code>my_ruby_script.rb</code> e é processado por ele.</p><p>Essa abordagem ajuda você a gerenciar lógicas complexas com mais eficiência, facilitando o teste, a depuração e a reutilização do seu código Ruby.</p><h2>Uso avançado</h2><p>Nesta seção, exploraremos alguns exemplos avançados de uso do filtro Ruby no Logstash. Estes exemplos demonstrarão como realizar transformações de dados, enriquecer eventos e implementar lógica personalizada usando Ruby.</p><h3>Manipulando estruturas de dados aninhadas</h3><p>Um evento do Logstash é a estrutura de dados principal que o Logstash processa. Pode conter diversos campos, incluindo estruturas de dados aninhadas, como arrays e hashes. O filtro Ruby permite manipular essas estruturas aninhadas com facilidade.</p><p>O filtro Ruby consegue lidar com estruturas de dados aninhadas, como hashes e arrays, permitindo que você modifique ou adicione campos dentro dessas estruturas. Isso é útil ao lidar com formatos de dados complexos como JSON.</p>input {
  generator {
    lines =&gt; [
      '{"nested": {"key1": "value1", "key2": "value2"}}'
    ]
    count =&gt; 1
    codec =&gt; "json"
    ecs_compatibility =&gt; "disabled"
  }
}

filter {
  ruby {
    code =&gt; "
      nested_data = event.get('nested')

      if nested_data.is_a?(Hash)
        nested_data['key3'] = 'value3'
        event.set('nested', nested_data)
      end
    "
  }
}

output {
  stdout { codec =&gt; rubydebug }
}<p>Este exemplo inclui um objeto JSON aninhado nos dados de entrada. O filtro Ruby modifica os dados aninhados adicionando um novo par chave-valor. Esse tipo de manipulação de dados aninhados não é possível com os filtros padrão do Logstash, o que torna o filtro Ruby uma opção prática para estruturas de dados complexas.</p><h3>Dividir um único evento em vários eventos.</h3><p>Os filtros Ruby também podem ser usados para dividir um único evento em vários eventos. Isso é útil quando você tem um único evento contendo uma matriz de itens e deseja criar eventos separados para cada item.</p><p>Note que nem o pipeline de ingestão do Elasticsearch nem os processadores do Beats/Elastic Agent suportam a divisão de eventos. Este é um dos casos de uso mais fortes para o Logstash.</p><h4>Com filtro dividido</h4><p>Você pode usar o filtro <code>split</code> para dividir um evento em vários eventos com base em um campo especificado. No entanto, se precisar realizar transformações ou lógicas adicionais durante a divisão, você pode usar o filtro Ruby em combinação com o filtro de divisão.</p><p>No exemplo a seguir, temos um feed RSS como uma única linha de texto XML. Contém múltiplos elementos <code>&lt;item&gt;</code> . O filtro Ruby é usado para extrair os elementos <code>&lt;item&gt;</code> do XML e armazená-los em um novo campo chamado <code>items</code>. O filtro de divisão é então usado para dividir o evento em vários eventos com base no campo <code>items</code> .</p>input {
  generator {
    lines =&gt; [
      '&lt;rss version="2.0"&gt;&lt;channel&gt;&lt;title&gt;Sample RSS&lt;/title&gt;&lt;item&gt;&lt;title&gt;Article 1&lt;/title&gt;&lt;link&gt;http://example.com/1&lt;/link&gt;&lt;description&gt;Desc 1&lt;/description&gt;&lt;/item&gt;&lt;item&gt;&lt;title&gt;Article 2&lt;/title&gt;&lt;link&gt;http://example.com/2&lt;/link&gt;&lt;description&gt;Desc 2&lt;/description&gt;&lt;/item&gt;&lt;/channel&gt;&lt;/rss&gt;'
    ]
    count =&gt; 1
    codec =&gt; "plain"
    ecs_compatibility =&gt; "disabled"
  }
}

filter {
  xml {
    source =&gt; "message"
    target =&gt; "rss"
    store_xml =&gt; true
    force_array =&gt; false
  }
  ruby {
    code =&gt; "event.set('items', event.get('[rss][channel][item]')) if event.get('[rss][channel][item]')"
  }
  split {
    field =&gt; "items"
  }
  ruby {
    code =&gt; "
      item = event.get('items')
      event.set('title', item['title']) if item['title']
      event.set('link', item['link']) if item['link']
      event.set('description', item['description']) if item['description']
    "
  }
  mutate {
    remove_field =&gt; ["@timestamp", "@version", "sequence", "host", "event", "message", "rss", "items"]
  }
}

output {
  stdout { codec =&gt; rubydebug }
}<p>Isso resultará no seguinte:</p>{
          "title" =&gt; "Article 1",
           "link" =&gt; "http://example.com/1",
    "description" =&gt; "Desc 1"
}
{
          "title" =&gt; "Article 2",
           "link" =&gt; "http://example.com/2",
    "description" =&gt; "Desc 2"
}<p>Como você deve ter percebido, o filtro <code>ruby</code> não é essencial neste caso. O filtro <code>split</code> pode ser usado para dividir o evento em vários eventos com base no campo <code>items</code> e o filtro <code>mutate</code> pode ser usado para remover campos desnecessários. No entanto, se você precisar realizar transformações ou lógicas adicionais durante a divisão, poderá usar o filtro Ruby.</p><h4>Use script Ruby embutido</h4><p>Você também pode usar um script Ruby embutido para dividir um único evento em vários eventos usando o método <code>event.clone</code> e o <code>new_event_block variable</code>, como <code>new_event_block.call(new_event)</code>. Isso permite criar novos eventos com base no evento original, preservando seus dados.</p><p>Aqui está um exemplo de como usar o filtro Ruby para dividir um único evento em vários eventos. A entrada e a saída são as mesmas do exemplo anterior.</p>filter {
  xml {
    source =&gt; "message"
    target =&gt; "rss"
    store_xml =&gt; true
    force_array =&gt; false
  }
  ruby {
    code =&gt; "
      items = event.get('[rss][channel][item]')
      if items.is_a?(Array)
        items.each do |item|
          new_event = event.clone
          new_event.set('title', item['title'])
          new_event.set('link', item['link'])
          new_event.set('description', item['description'])
          new_event_block.call new_event
        end
        event.cancel
      elsif items.is_a?(Hash)
        event.set('title', items['title'])
        event.set('link', items['link'])
        event.set('description', items['description'])
      end
    "
  }
  mutate {
    remove_field =&gt; ["@timestamp", "@version", "sequence", "host", "event", "message", "rss", "items"]
  }
}<h4>Utilizar script Ruby externo</h4><p>Você também pode usar um script Ruby externo para dividir um único evento em vários eventos.</p><p>Arquivo de configuração:</p>filter {
  xml {
    source =&gt; "message"
    target =&gt; "rss"
    store_xml =&gt; true
    force_array =&gt; false
  }
  ruby {
    path =&gt; "path/to/ruby/split_event.rb"
  }
  mutate {
    remove_field =&gt; ["@timestamp", "@version", "sequence", "host", "event", "message", "rss", "items"]
  }
}<p>O script Ruby precisa ser externalizado como <code>split_event.rb</code>:</p>def filter(event)
  items = event.get('[rss][channel][item]')
  events = []
  if items.is_a?(Array)
    items.each do |item|
      new_event = event.clone
      new_event.set('title', item['title'])
      new_event.set('link', item['link'])
      new_event.set('description', item['description'])
      events &lt;&lt; new_event
    end
    return events
  elsif items.is_a?(Hash)
    event.set('title', items['title'])
    event.set('link', items['link'])
    event.set('description', items['description'])
    return [event]
  else
    return []
  end
end<p>Lembre-se, o método <code>filter</code> deve retornar uma matriz de eventos. Você pode retornar vários eventos clonando um objeto de evento recebido e adicionando-os à matriz, ou pode retornar um único evento como uma matriz com um único elemento.</p>return events
# or
# return [event]<p>Isso permite dividir um único evento em vários eventos.</p><h3>Executar comandos externos e analisar seus resultados.</h3><p>O plugin Logstash exec input permite executar comandos externos, e a saída desses comandos será um evento do Logstash. O resultado do comando será armazenado no campo <code>message</code> do evento.</p><p>Normalmente, a saída dos comandos do sistema é legível para humanos, mas não está estruturada em JSON ou outros formatos que o Logstash possa analisar facilmente. Para lidar com isso, você pode usar o filtro Ruby para analisar a saída e extrair as informações dela.</p><p>Aqui está um exemplo de uso do plugin de entrada <code>exec</code> para executar o comando <code>ps -ef</code> , que lista todos os processos em execução em um sistema do tipo Unix. A saída será analisada pelo filtro Ruby para extrair informações relevantes sobre cada processo.</p>input {
  exec {
    command =&gt; "ps -ef"
    interval =&gt; 60
  }
}

filter {
  ruby {
    code =&gt; '
      processes = []
      lines = event.get("message").split("\n")  
      lines.each_with_index do |line, index|
        # Skip header line and empty lines
        next if index == 0 || line.strip.empty?
        entry = nil
        
        # Use regex to match the ps -ef output format more flexibly
        # This pattern accounts for variable spacing and different time formats
        if line =~ /^\s*(\S+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\S+)\s+(\S+)\s+([\d:]+\.?\d*)\s+(.+)$/
          uid, pid, ppid, c, stime, tty, time, cmd = $1, $2, $3, $4, $5, $6, $7, $8
          
          entry = {
            "UID" =&gt; uid,
            "PID" =&gt; pid,
            "PPID" =&gt; ppid,
            "C" =&gt; c,
            "STIME" =&gt; stime,
            "TTY" =&gt; tty,
            "TIME" =&gt; time,
            "CMD" =&gt; cmd.strip
          }
        elsif line =~ /^\s*(\S+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(.+)$/
          # Fallback pattern for lines that might not match the exact format
          # Split the remaining part more carefully
          uid, pid, ppid, c, remainder = $1, $2, $3, $4, $5
          
          # Split remainder into STIME, TTY, TIME, CMD
          parts = remainder.strip.split(/\s+/, 4)
          if parts.length &gt;= 4
            stime, tty, time, cmd = parts[0], parts[1], parts[2], parts[3]
            
            entry = {
              "UID" =&gt; uid,
              "PID" =&gt; pid,
              "PPID" =&gt; ppid,
              "C" =&gt; c,
              "STIME" =&gt; stime,
              "TTY" =&gt; tty,
              "TIME" =&gt; time,
              "CMD" =&gt; cmd
            }
          end
        end
        if entry &amp;&amp; entry["UID"] == "0"
          original_line = line.strip
          entry["original_line"] = original_line if original_line.length &gt; 0
          processes.push(entry)
        end
      end
      event.set("processes", processes)
      event.remove("message")
      event.remove("event")
    '
  }
}

output {
  stdout { codec =&gt; rubydebug }
}<p>Este exemplo usa o plugin de entrada <code>exec</code> para executar o comando <code>ps -ef</code> a cada 60 segundos. O filtro Ruby processa a saída, extraindo campos relevantes como UID, PID, PPID, uso da CPU (C), hora de início (STIME), TTY, tempo total da CPU (TIME) e o comando (CMD) executado. Funciona bem no meu ambiente macOS, mas você pode precisar ajustar os padrões regex para corresponder ao formato de saída do comando <code>ps -ef</code> no seu sistema.</p><h3>Utilize bibliotecas integradas</h3><p>O plugin de filtro Ruby permite usar bibliotecas Ruby integradas, o que pode ser muito útil para diversas tarefas. Por exemplo, você pode usar a biblioteca <code>json</code> para analisar strings JSON ou a biblioteca <code>date</code> para manipular datas.</p><p>Aqui está um exemplo de como usar a biblioteca <code>json</code> para analisar uma string JSON armazenada em um campo:</p>require 'json'

def filter(event)
  json_string = event.get('message')
  parsed_json = JSON.parse(json_string)
  event.set('parsed_json', parsed_json)
  return [event]
end<p>Para evitar exigir a biblioteca sempre, você deve externalizar seu código Ruby para que possa usar a instrução <code>require</code> no início do seu script de filtro Ruby. Isso carregará a biblioteca uma única vez e a tornará disponível para uso em seu script.</p><p>Para verificar quais bibliotecas estão disponíveis em seu ambiente, você pode listar as bibliotecas integradas executando o seguinte código no filtro Ruby:</p>Gem.loaded_specs.sort_by { |name, _| name }.each do |name, spec|
  puts "#{name}: #{spec.version}"
end<p><strong>Observação: </strong>as bibliotecas integradas não são oficialmente suportadas pelo Logstash e seu comportamento pode mudar ou elas podem não estar disponíveis em versões futuras. Use-os por sua conta e risco.</p><h2>Conclusão</h2><p>O filtro Logstash Ruby permite personalizar e ampliar as funcionalidades dos seus pipelines Logstash. Neste post, abordamos os conceitos básicos do uso do filtro Ruby e fornecemos exemplos de uso avançado.</p><p>Ao utilizar o filtro Ruby, você pode lidar com tarefas complexas de processamento de dados que exigem lógica personalizada ou manipulação avançada. Seja trabalhando com estruturas de dados aninhadas, dividindo eventos ou analisando e convertendo texto complexo/não estruturado em JSON estruturado, o filtro Ruby oferece a flexibilidade necessária para atender às suas necessidades específicas.</p><p>Esperamos que este guia tenha lhe fornecido o conhecimento e a inspiração necessários para explorar todo o potencial do filtro Logstash Ruby. Boa programação!</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/ruby-scripting-logstash</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/ruby-scripting-logstash</guid>
    <category><![CDATA[Dados de indexação]]></category>
    <category><![CDATA[Ruby]]></category>
    <dc:creator><![CDATA[Dai Sugimori]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt503d18396642e73e/6a17f62aaf47b68527cde121/b1bcd63c033ccbde102c20ba3085f165f9289a71-1600x1000.png" length="0" type="image/png"/>
    <pubDate>Tue, 24 Jun 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Exibindo campos em um índice do Elasticsearch]]></title>
    <description><![CDATA[Explorando técnicas para exibir campos em um índice do Elasticsearch.
]]></description>
    <content:encoded><![CDATA[<p>Neste artigo, discutiremos como exibir campos em um índice do Elasticsearch. Isso pode ser útil para entender a estrutura dos seus dados, identificar campos específicos e solucionar problemas. Abordaremos os seguintes tópicos:</p><ol><li><p><a href="https://www.elastic.co/search-labs/blog/displaying-fields-in-an-elasticsearch-index#1.-using-the--mapping-api-to-retrieve-field-information">Utilizando a </a><a href="https://www.elastic.co/search-labs/blog/displaying-fields-in-an-elasticsearch-index#1.-using-the--mapping-api-to-retrieve-field-information"> API</a><a href="https://www.elastic.co/search-labs/blog/displaying-fields-in-an-elasticsearch-index#1.-using-the--mapping-api-to-retrieve-field-information"><code>_mapping</code></a>para recuperar informações de campo</p></li><li><p><a href="https://www.elastic.co/search-labs/blog/displaying-fields-in-an-elasticsearch-index#2.-using-the--search-api-to-display-field-values">Utilizando a </a><a href="https://www.elastic.co/search-labs/blog/displaying-fields-in-an-elasticsearch-index#2.-using-the--search-api-to-display-field-values"> API</a><a href="https://www.elastic.co/search-labs/blog/displaying-fields-in-an-elasticsearch-index#2.-using-the--search-api-to-display-field-values"><code>_search</code></a>para exibir valores de campo</p></li><li><p><a href="https://www.elastic.co/search-labs/blog/displaying-fields-in-an-elasticsearch-index#3.-filtering-fields-using-the-fields-parameter">Filtrar campos usando o </a><a href="https://www.elastic.co/search-labs/blog/displaying-fields-in-an-elasticsearch-index#3.-filtering-fields-using-the-fields-parameter"> parâmetro</a><a href="https://www.elastic.co/search-labs/blog/displaying-fields-in-an-elasticsearch-index#3.-filtering-fields-using-the-fields-parameter"><code>fields</code></a></p></li><li><p><a href="https://www.elastic.co/search-labs/blog/displaying-fields-in-an-elasticsearch-index#4.-displaying-nested-fields">Exibindo campos aninhados</a></p></li></ol><h2>1. Utilizando a API _mapping para recuperar informações de campo</h2><p>A API <code>_mapping</code> permite recuperar a definição de mapeamento para um índice ou vários <a href="https://opster.com/guides/elasticsearch/glossary/elasticsearch-index/">índices</a>. Isso inclui informações sobre os campos, seus tipos de dados e outras propriedades. Para recuperar o mapeamento de um índice específico, utilize a seguinte solicitação:</p>GET /&lt;index_name&gt;/_mapping<p>Por exemplo, se você tiver um índice chamado <code>my_index</code>, poderá recuperar seu mapeamento com a seguinte solicitação:</p>GET /my_index/_mapping<p>A resposta incluirá a definição de mapeamento para o índice, que contém informações sobre os campos e suas propriedades.</p><p>Também é possível recuperar o mapeamento de um campo específico. Isso pode ser útil se o seu mapeamento for muito extenso e você quiser se concentrar apenas em um campo específico. Para obter o mapeamento de um campo específico, utilize a seguinte solicitação:</p>GET /my_index/_mapping/field/my_field<p>Você também pode recuperar os mapeamentos de vários campos separando seus nomes com vírgulas, como na seguinte solicitação:</p>GET /my_index/_mapping/field/my_field_1,my_field_2,my_field_3<h2>2. Usando a API _search para exibir valores de campo</h2><p>Para exibir os valores dos campos em um índice do Elasticsearch, você pode usar a API <code>_search</code> . Por padrão, a API <code>_search</code> retorna o campo <code>_source</code> , que contém o documento JSON original que foi indexado. Para exibir apenas campos específicos, você pode usar o parâmetro <code>_source</code> na solicitação de pesquisa.</p><p>Aqui está um exemplo de uma solicitação de pesquisa que retorna os valores dos campos <code>title</code> e <code>author</code> para documentos no índice <code>my_index</code> :</p>GET /my_index/_search
{
  "query": {
    "match_all": {}
  },
  "_source": ["title", "author"]
}<p>Neste exemplo, o parâmetro <code>_source</code> especifica os campos a serem retornados.</p><h2>3. Filtrar campos usando o parâmetro fields</h2><p>Você também pode usar o parâmetro <code>fields</code> para filtrar os campos retornados na resposta da pesquisa. Isso pode ser útil se você precisar apenas de campos específicos e quiser reduzir o tamanho da resposta. O parâmetro <code>fields</code> aceita uma matriz de nomes de campos ou padrões curinga.</p><p>Por exemplo, para retornar apenas os campos <code>title</code> e <code>author</code> para documentos no índice <code>my_index</code> , você pode usar a seguinte solicitação de pesquisa:</p>GET /my_index/_search
{
  "query": {
    "match_all": {}
  },
  "fields": ["title", "author"],
  "_source": false
}<p>Note que o parâmetro <code>_source</code> está definido como falso para não retornar o documento de origem.</p><p>Para retornar todos os campos com o tipo de dados <code>text</code> , você pode usar um padrão curinga como este:</p>GET /my_index/_search
{
  "query": {
    "match_all": {}
  },
  "fields": ["*.text"],
  "_source": false
}<h2>4. Exibição de campos aninhados</h2><p>Se o seu índice contiver campos aninhados, você pode usar a notação de ponto para especificar o caminho do campo aninhado no parâmetro <code>fields</code> . Por exemplo, se você tiver um campo aninhado chamado <code>address.city</code>, poderá incluí-lo na resposta da pesquisa desta forma:</p>GET /my_index/_search
{
  "query": {
    "match_all": {}
  },
  "fields": ["title", "author", "address.city"],
  "_source": false
}<p>Neste exemplo, a resposta da pesquisa incluirá os valores dos campos <code>title</code>, <code>author</code> e <code>address.city</code> .</p><h2>Conclusão</h2><p>Em conclusão, a exibição de campos em um índice do Elasticsearch pode ser realizada usando a API <code>_mapping</code> para recuperar informações do campo e a API <code>_search</code> para exibir os valores do campo. Você pode filtrar os campos retornados na resposta da pesquisa usando os parâmetros <code>_source</code> ou <code>fields</code> e exibir campos aninhados usando a notação de ponto. Essas técnicas podem ajudá-lo a entender a estrutura de seus dados, identificar campos específicos e solucionar problemas.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/displaying-fields-in-an-elasticsearch-index</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/displaying-fields-in-an-elasticsearch-index</guid>
    <category><![CDATA[Dados de indexação]]></category>
    <dc:creator><![CDATA[Kofi Bartlett]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3a1fcc771a2504e5/6a17f817abe0f23038dfebca/fa386d7bbaeab6855e62897ace8d7dca91a060b4-720x420.jpg" length="0" type="image/jpeg"/>
    <pubDate>Mon, 26 May 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Excluindo campos do Elasticsearch da indexação]]></title>
    <description><![CDATA[Aprenda como configurar o Elasticsearch para excluir campos, os principais motivos para excluir campos da indexação e as práticas recomendadas a serem seguidas.]]></description>
    <content:encoded><![CDATA[<p>No Elasticsearch, indexação refere-se ao processo de armazenar e organizar dados de forma que eles possam ser facilmente pesquisados. Embora indexar todos os campos de um documento possa ser útil em alguns casos, existem situações em que você pode querer excluir determinados campos da indexação. Isso pode ajudar a melhorar o desempenho, reduzir os custos de armazenamento e minimizar o tamanho geral do seu índice Elasticsearch.</p><p>Neste artigo, discutiremos os motivos para excluir campos da indexação, como configurar o Elasticsearch para excluir campos específicos e algumas práticas recomendadas a serem seguidas ao fazer isso.</p><h2>Motivos para excluir campos da indexação</h2><ol><li><p><strong>Desempenho: </strong>Indexar todos os campos de um documento pode aumentar o tempo de indexação e tornar a pesquisa mais lenta. Ao excluir campos que não são necessários para pesquisa ou agregação, você pode melhorar o desempenho geral do seu cluster Elasticsearch.</p></li><li><p><strong>Armazenamento: </strong>A indexação de campos consome espaço de armazenamento. Excluir campos que não são necessários para pesquisa ou agregação pode ajudar a reduzir os requisitos de armazenamento do seu cluster Elasticsearch.</p></li><li><p><strong>Tamanho do índice: </strong>O tamanho de um índice do Elasticsearch está diretamente relacionado ao número de campos indexados. Ao excluir campos desnecessários, você pode minimizar o tamanho do seu índice, o que pode levar a um desempenho de pesquisa e indexação mais rápido.</p></li></ol><h2>Configurando o Elasticsearch para excluir campos</h2><p>Para excluir um campo da indexação no Elasticsearch, você pode usar a propriedade "index" no mapeamento do campo. Ao definir a propriedade “index” como “false”, o Elasticsearch não indexará o campo, e ele não será pesquisável nem estará disponível para agregações.</p><p>Aqui está um exemplo de como excluir um campo da indexação usando o mapeamento do Elasticsearch:</p>PUT /my_index
{
  "mappings": {
    "properties": {
      "field_to_exclude": {
        "type": "text",
        "index": false
      }
    }
  }
}<p>Neste exemplo, estamos criando um novo índice chamado “my_index” com um único campo chamado “field_to_exclude”. Ao definir a propriedade “index” como “false”, estamos dizendo ao Elasticsearch para não indexar esse campo. O campo ainda estará disponível no documento original.</p><h2>Melhores práticas para excluir campos da indexação</h2><ol><li><p><strong>Analise seus dados: </strong>Antes de excluir campos da indexação, é essencial analisar seus dados e entender quais campos são necessários para pesquisa e agregação. Isso ajudará você a tomar decisões informadas sobre quais campos excluir.</p></li><li><p><strong>Teste suas alterações: </strong>Ao excluir campos da indexação, é crucial testar as alterações para garantir que a funcionalidade de pesquisa e agregação continue funcionando conforme o esperado. Isso pode ajudar você a evitar problemas inesperados ou falhas de desempenho.</p></li><li><p><strong>Monitore o desempenho:</strong> após excluir campos da indexação, monitore o desempenho do seu cluster Elasticsearch para garantir que as alterações tenham surtido o efeito desejado. Isso pode ajudar a identificar quaisquer otimizações adicionais que possam ser necessárias.</p></li><li><p><strong>Utilize a filtragem por origem:</strong> Se você precisa armazenar um campo no Elasticsearch, mas não deseja que ele seja pesquisável ou disponível para agregações, considere usar a filtragem por origem. Isso permite armazenar o campo no campo _source, mas excluí-lo do índice.</p></li></ol><h2>Conclusão</h2><p>Excluir campos da indexação no Elasticsearch pode ajudar a melhorar o desempenho, reduzir os custos de armazenamento e minimizar o tamanho geral do seu índice. Ao analisar cuidadosamente seus dados e entender quais campos são necessários para pesquisa e agregação, você pode tomar decisões informadas sobre quais campos excluir. Sempre teste suas alterações e monitore o desempenho do seu cluster Elasticsearch para garantir que suas otimizações tenham o efeito desejado.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/excluding-elasticsearch-fields-from-indexing</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/excluding-elasticsearch-fields-from-indexing</guid>
    <category><![CDATA[Dados de indexação]]></category>
    <dc:creator><![CDATA[Kofi Bartlett]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt399bcc5a2e55bfe0/6a1708b45091684557e1ba3c/3aa0b481994d2445ba979d3c79fff64c5ee6676a-720x420.jpg" length="0" type="image/jpeg"/>
    <pubDate>Mon, 12 May 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Criação de modelos de índice no Elasticsearch: Como usar modelos compostos]]></title>
    <description><![CDATA[Veja como criar templates componíveis e de componentes no Elasticsearch para garantir mapeamentos consistentes e automatizar a configuração dos índices.]]></description>
    <content:encoded><![CDATA[<p>Um índice do Elasticsearch pode ser configurado por meio de mapeamento, configurações e aliases: </p><ul><li><p>As definições de mapeamento especificam o esquema de dados.</p></li><li><p>As configurações definem o tamanho dos fragmentos e as taxas de atualização. </p></li><li><p>Os aliases são usados para dar nomes alternativos ao índice.</p></li></ul><p>Ao indexar um documento pela primeira vez ou criar um índice vazio usando a API Criar Índice, o índice será criado com as configurações padrão, sem esquema de dados e sem aliases. Essas configurações padrão funcionam muito bem em ambientes de desenvolvimento e teste, mas talvez seja necessário personalizar nossos índices para ambientes de produção.</p><p>Trabalhar com os mapeamentos e configurações padrão em produção pode resultar em indexação e desempenho de pesquisa deficientes. A criação manual de índices é um processo tedioso e demorado. Recriar esses índices em todos os ambientes é especialmente impraticável se tivermos um esquema de mapeamento complexo, além de configurações e aliases personalizados.</p><p>Felizmente, o Elasticsearch nos fornece uma ferramenta para aplicar automaticamente uma configuração predefinida ao criar índices na forma de modelos <em>de índice</em> <em>.</em></p><h2>Modelos de índice</h2><p>Os modelos de índice permitem criar índices com configurações definidas pelo usuário. Um índice pode obter a configuração desses modelos, por exemplo, um número definido de shards e réplicas ou mapeamentos de campos, durante sua instanciação. Um modelo será definido com um padrão de nome e algumas configurações. Se o nome do índice corresponder ao padrão de nomenclatura do modelo, o novo índice será criado com a configuração definida no modelo.</p><p>O Elasticsearch atualizou sua funcionalidade de modelos na versão 7.8 com modelos compostos. Esta versão mais recente oferece muito mais modelos de índice reutilizáveis, como demonstrado neste artigo.</p><h3>Tipos de modelo de índice</h3><p>Os modelos de índice podem ser classificados em duas categorias:</p><ul><li><p><strong>Modelos de índice (ou modelos de índice componíveis)</strong>: Os modelos de índice componíveis podem existir por si só ou podem ser compostos por nenhum ou mais modelos componentes (consulte a segunda categoria).</p></li><li><p><strong>Modelos de componentes:</strong> O modelo de componente é um modelo <em>reutilizável</em> que define a configuração necessária. Normalmente, espera-se que o modelo de componente esteja associado a um modelo de índice. Cada um dos modelos de componentes pode ser associado a um ou mais modelos de índice. </p></li></ul><p>Como você pode ver na imagem abaixo, os modelos de índice A e B compartilham modelos de componentes (neste caso, apenas um – o Modelo 3) entre si. Um modelo de índice pode não conter nenhum ou vários modelos de componentes, e cada um dos modelos de componentes pode não estar associado a nenhum ou a vários modelos de índice. Ambos os tipos de modelos podem existir por si só, porém os modelos de componentes são inúteis a menos que estejam anexados a um modelo de índice.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7fca132e0eb86c50/6a17f5b7ec0f8982a65a678c/96c0aac29d3992e54a79be34e14cf909e0ca2ea9-1202x556.png" alt="Modelos de indexação no Elasticsearch e os componentes." /><p>A ideia geral é desenvolver um catálogo de modelos de componentes para uma organização usar em diversas necessidades (por exemplo, especificar os vários modelos de componentes para ambientes individuais) e associá-los a vários índices por meio de modelos de índice componíveis.</p><h2>Como criar modelos (de índice) componíveis</h2><p>O Elasticsearch fornece um endpoint _index_template para gerenciar modelos de índice. Neste modelo, o usuário fornece todos os mapeamentos, configurações e aliases necessários, juntamente com um padrão de nome de índice. Vamos analisar um exemplo de criação de um modelo para um aplicativo de microsserviços chamado <em>customer-order-service</em> , responsável pela lógica de geração de pedidos. </p><p>Digamos que nossa necessidade seja criar um modelo para pedidos de clientes, representado por um padrão com caracteres curinga: *pedidos. Espera-se que este modelo tenha determinados mapeamentos e configurações, como o campo order_date, bem como números de shards e réplicas.</p><p>Qualquer índice que corresponda a este modelo durante a sua criação herdará as configurações definidas neste modelo. Por exemplo, um índice black_friday_orders terá o campo order_date, o número de shards será definido como 5 e o número de réplicas como 2. Além disso, <em>todos</em> os índices criados a partir deste modelo também herdarão um único nome <a href="https://opster.com/guides/elasticsearch/glossary/elasticsearch-alias/">de alias</a> ! Vamos criar este modelo de pedidos (orders_template) com um padrão de índice definido como *orders e com um esquema de mapeamento que consiste em um único campo order_date com um formato de data predefinido dd-MM-yyyy. O código abaixo mostra como criar esse modelo de índice.</p>PUT _index_template/orders_template
{
  "index_patterns": ["*orders"],
  "priority": 300,
  "template": {
    "mappings": {
      "properties": {
        "order_date": {
          "type": "date",
          "format":"dd-MM-yyyy"
        }
      }
    },
    "settings":{
      "number_of_shards":5,
      "number_of_replicas":2
    },
    "aliases":{
      "all_orders":{}
    }
  }
}<p>Ao executar essa consulta nas DevTools do Kibana, o modelo é criado com o padrão de índice *orders, juntamente com o mapeamento predefinido, as configurações e um alias. O `index_patterns` é uma matriz de padrões de correspondência; qualquer índice que corresponda a esse padrão derivará a configuração do modelo. Você pode executar o seguinte comando para recuperar o modelo persistido, que deverá reiterar o que fizemos:</p>GET _index_template/orders_template <p>Existe também uma prioridade, um número positivo, definida ao criar o atributo de modelo definido no modelo: cada modelo é definido com uma prioridade, de forma que quaisquer alterações conflitantes de modelos diferentes sejam resolvidas usando esse valor, com precedência dada ao valor de prioridade mais alto. A seguir, analisaremos a prioridade dos modelos com mais detalhes.</p><h2>Criando um índice com o modelo</h2><p>Agora que temos um modelo – um projeto para criar índices – o próximo passo é criar um índice. Quando o nome do índice corresponde ao padrão fornecido, as configurações do modelo são aplicadas automaticamente. Para comprovar esse ponto, como mostra o código abaixo, vamos criar um novo índice chamado: blackfriday_orders:</p>PUT blackfriday_orders<p>Como o nome do índice (blackfriday_orders) corresponde ao padrão de nomenclatura definido no modelo (ou seja, *pedidos), o índice deve obter toda a configuração derivada do modelo. Vamos recuperar esse índice recém-criado e verificar se isso é realmente verdade executando o seguinte código:</p>GET blackfriday_orders<p>Isso deve retornar:</p>{
  "blackfriday_orders" : {
    "aliases" : {
      "all_orders" : { }
    },
    "mappings" : {
      "properties" : {
        "order_date" : {
          "type" : "date",
          "format" : "dd-MM-yyyy"
        }
      }
    },
    "settings" : {
      "index" : {
         ...
        "number_of_shards" : "5",
        "number_of_replicas" : "2"
      }
    }
  }
}<p>Conforme indicado na resposta, a configuração do blackfriday_orders foi herdada do modelo. Podemos tentar várias combinações de índices que herdarão com sucesso a configuração do modelo:</p>PUT blackfriday_orders
PUT americaorders
PUT cancelled--orders
PUT undefined101orders<p>No entanto, os seguintes índices não herdarão a configuração, pois o nome não corresponderá ao padrão:</p>PUT blackfriday_orders2
PUT open_orders_
PUT allorders_total<p>Um ponto importante a lembrar é que todos os índices derivados de um modelo têm o mesmo alias – all_orders – neste caso. Existe uma vantagem em ter um alias desse tipo: podemos simplesmente consultar esse único alias em vez de vários índices.</p>GET blackfriday_orders,americaorders,undefined101orders/_search
GET all_orders/_search 
{
  "query": {
    "range": {
      "order_date": {
        "gte": "01-12-2021",
        "lte": "31-12-2021"
      }
    }
  }
}<p>Embora criemos um modelo para *pedidos, espera-se que qualquer índice correspondente adote a configuração do modelo. Normalmente, consciente ou inconscientemente, as equipes podem criar alguns modelos adicionais por diversos motivos. Isso significa que, às vezes, o nome do índice pode corresponder a dois padrões de modelo diferentes! O Elasticsearch precisa decidir qual das configurações desses modelos deve ser aplicada. Felizmente, esse dilema pode ser resolvido usando a prioridade do modelo.</p><h2>Como criar modelos de componentes</h2><p>Aprendemos sobre modelos de índice na parte anterior deste artigo. Existem algumas desvantagens em criar modelos com a configuração já integrada – uma delas é que a configuração não pode ser exportada para outros modelos. Se desejarmos ter uma configuração semelhante, por exemplo, para modelos relacionados a clientes (*clientes), talvez tenhamos que recriar todo o modelo. Isso significa que podemos estar criando dezenas deles em uma organização típica (e você pode ter alguns outros dependendo do ambiente).</p><p>Como sempre buscamos a reutilização, o Elasticsearch redesenhou os modelos levando isso em consideração. Os modelos de componentes atendem a essa necessidade. Se você tem experiência em DevOps, provavelmente precisará criar índices com uma configuração predefinida para cada um dos ambientes. Em vez de aplicar manualmente cada uma dessas configurações de forma tediosa, você pode criar um modelo de componente para cada um dos ambientes.</p><p>Um modelo de componente nada mais é do que um bloco reutilizável de configurações que podemos usar para criar mais modelos de índice. Note que os modelos de componentes não têm utilidade a menos que sejam combinados com modelos de índice. Eles são expostos através de um endpoint _component_template. Vamos ver como tudo isso se encaixa.</p><h3>Configurações em um modelo de índice</h3><p>Vamos extrair as configurações que definimos anteriormente em nosso modelo de índice e criar um modelo de componente a partir delas. Espera-se que o settings_component_template tenha cinco shards primários com duas réplicas por shard primário. O primeiro passo, como mostra o código abaixo, é declarar e executar um modelo de componente com essa configuração.</p>PUT _component_template/settings_component_template
{
  "template":{
    "settings":{
      "number_of_shards":5,
      "number_of_replicas":2
    }
  }
}<p>Como mostra o código acima, usamos o endpoint _component_template para criar um modelo de componente. O corpo da solicitação contém as informações do modelo em um objeto de modelo. O modelo settings_component_template agora está disponível para uso em outros locais nos modelos de índice. Uma diferença notável é que este modelo não define nenhum padrão de índice; é simplesmente um bloco de código que configura algumas propriedades para nós.</p><h3>Modelo de mapeamento</h3><p>Da mesma forma, vamos criar outro modelo. Desta vez, vamos extrair o esquema de mapeamento que definimos anteriormente nos modelos de índice independentes. O código abaixo mostra o script:</p>PUT _component_template/mappings_component_template
{
  "template": {
    "mappings": {
      "properties": {
        "order_date": {
          "type": "date",
          "format":"dd-MM-yyyy"
        }
      }
    }
  }
}<h3>Modelo de aliases</h3><p>Seguindo a mesma linha de raciocínio, também podemos ter um modelo de componente com os aliases – dois aliases (all_orders e sales_orders):</p>PUT _component_template/aliases_component_template
{
  "template": {
    "aliases": {
      "all_orders": {},
      "sales_orders":{}
    }
  }
}<h3>Modelo de índice componível</h3><p>Agora que temos esses três modelos de componentes, o próximo passo é colocá-los em uso. Podemos fazer isso permitindo que um modelo de índice, digamos, para pedidos de Natal, o utilize:</p>PUT _index_template/composed_orders_template
{
  "index_patterns": [
    "*orders"
  ],
  "priority": 500,
  "composed_of": [
    "settings_component_template",
    "mappings_component_template",
    "aliases_component_template"
  ]
}<p>A tag `composed_of` é uma coleção de todos os modelos de componentes que compõem este modelo. Neste caso, estamos escolhendo as configurações, os mapeamentos e os modelos de componentes de aliases. Também estamos aumentando a prioridade, então este modelo terá precedência sobre qualquer outro. Assim que o modelo estiver pronto, quaisquer índices que correspondam ao padrão *orders herdarão a configuração desses três modelos de componentes.</p><p>Dito isso, caso desejemos criar um novo modelo, digamos, para clientes, utilizando apenas um dos modelos existentes (settings_component_template) e um modelo de aliases recém-criado (aliases_component_template – veja abaixo), podemos fazê-lo da seguinte forma:</p>PUT _component_template/aliases_component_template2
{
  "template": {
    "aliases": {
      "all_customers": {}
    }
  }
}<p>O modelo de índice é o seguinte:</p>PUT _index_template/composed_customers_template
{
  "index_patterns": [
    "*customers*"
  ],
  "priority": 200,
  "composed_of": [
    "settings_component_template",
    "aliases_component_template2"
  ]
}<p>Você percebeu que o settings_component_template foi (re)utilizado em dois templates diferentes? Esse é o poder dos modelos de componentes.</p><h2>Prioridade do modelo de índice</h2><p>Existe a possibilidade de os desenvolvedores criarem vários modelos de índice sem analisar o estoque existente. É importante definir uma prioridade para cada um desses modelos, de forma que aquele com maior prioridade seja utilizado. Por exemplo, o modelo `my_orders_template_1` sobrescreve o modelo `my_orders_template_2` no seguinte trecho de código:</p>PUT _index_template/my_orders_template_1
{
  "index_patterns": ["*orders"],
  "priority": 1000,
  "template": { ... }
}
PUT _index_template/my_orders_template2
{
  "index_patterns": ["*orders"],
  "priority": 300,
  "template": { ... }
}<p>Quando você tem vários modelos que correspondem aos índices que estão sendo criados, o Elasticsearch aplica todas as configurações de todos os modelos correspondentes, mas sobrescreve qualquer configuração que tenha prioridade mais alta.</p><h2>Precedência dos modelos</h2><p>Por fim, você pode estar se perguntando sobre a precedência dos modelos – a configuração definida no modelo do componente substitui a definida no próprio modelo do índice principal? Ou vice-versa? Bem, existem algumas regras:</p><ul><li><p>Um índice criado com configurações explícitas tem precedência sobre tudo – isso significa que, se você criar um índice com configuração explícita, não espere que ela seja substituída pelos modelos.</p></li><li><p>Os modelos legados (modelos criados antes da versão 7.8) têm uma prioridade menor do que os modelos componíveis.</p></li></ul><h2>Resumo</h2><ul><li><p>Um índice contém mapeamentos, configurações e aliases: os mapeamentos definem o esquema dos campos, as configurações definem os parâmetros do índice, como o número de shards e réplicas, e os aliases fornecem nomes alternativos ao índice.</p></li><li><p>Os modelos permitem criar índices com configurações predefinidas. Ao atribuir um nome a um índice que corresponda ao padrão de índice definido em um modelo específico, esse índice será configurado automaticamente de acordo com o modelo.</p></li><li><p>O Elasticsearch introduziu modelos de índice componíveis na versão 7.8. Os modelos de índice combináveis permitem modularidade e versionamento dos modelos.</p></li><li><p>Os modelos componíveis consistem em nenhum ou mais modelos de componentes.</p></li><li><p>Um modelo de índice também pode ter sua própria configuração definida.</p></li><li><p>Um modelo de componente é um modelo reutilizável com configuração predefinida, assim como um modelo de índice composto.</p></li><li><p>No entanto, espera-se que os modelos de componentes façam parte de um modelo de índice; eles são inúteis se não forem "compostos" em um modelo de índice.</p></li><li><p>Os modelos de componentes não têm um padrão de índice definido neles – o que é mais um motivo pelo qual "se espera" que façam parte de um modelo de índice.</p></li><li><p>Cada um dos modelos tem uma prioridade – um número positivo. Quanto maior o número, maior a prioridade para a aplicação desse modelo.</p></li></ul>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/index-composable-templates</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/index-composable-templates</guid>
    <category><![CDATA[Dados de indexação]]></category>
    <dc:creator><![CDATA[Kofi Bartlett]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt98737a72caa74fe4/6a17f5b84b055d278d43236a/510750708df50bf79463586a1bbf35bf94acfa30-1200x628.png" length="0" type="image/png"/>
    <pubDate>Fri, 02 May 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Como ingerir dados no Elasticsearch através do Airbyte]]></title>
    <description><![CDATA[Utilizando o Airbyte para ingerir dados no Elasticsearch. Vamos abordar os pré-requisitos, a configuração do Airbyte e a integração passo a passo.]]></description>
    <content:encoded><![CDATA[<p>O Airbyte é uma ferramenta de integração de dados que permite mover informações de diversas fontes para diferentes destinos de forma automatizada e escalável. Permite extrair dados de APIs, bancos de dados e outros sistemas e carregá-los em plataformas como o Elasticsearch, que oferece pesquisa avançada e análise eficiente.</p><p>Neste artigo, explicaremos como configurar o Airbyte para ingerir dados no Elasticsearch, abordando conceitos-chave, pré-requisitos e integração passo a passo.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt99eabff95c587c00/6a17e300e8fbce2d303a18a9/ea7af907dfd4c0b7e8673164467ee236623282d2-1360x802.png" alt="Configure o Airbyte para ingerir dados no Elasticsearch." /><h2>Conceitos fundamentais do Airbyte</h2><p>O Airbyte possui diversos conceitos essenciais para sua utilização. A seguir, destacamos os principais:</p><ul><li><p>Fontes: Define a origem dos dados que serão extraídos.</p></li><li><p>Destinos: Define onde os dados serão enviados e armazenados.</p></li><li><p>Conexões: Configura a relação entre a origem e o destino, incluindo a frequência de sincronização.</p></li></ul><h2>Integração do Airbyte com o Elasticsearch</h2><p>Nesta demonstração, realizaremos uma integração onde os dados armazenados em um bucket do S3 serão migrados para um índice do Elasticsearch. Mostraremos como configurar a origem (S3) e o destino (Elasticsearch) no Airbyte.</p><h3>Pré-requisitos</h3><p>Para acompanhar esta demonstração, os seguintes pré-requisitos devem ser atendidos:</p><ol><li><p>Crie um bucket na AWS onde os arquivos JSON contendo os dados serão armazenados.</p></li><li><p><a href="https://docs.airbyte.com/using-airbyte/getting-started/oss-quickstart">Instale o Airbyte localmente</a> usando o Docker.</p></li><li><p>Crie um cluster Elasticsearch no Elastic Cloud para armazenar os dados ingeridos.</p></li></ol><p>A seguir, detalharemos cada uma dessas etapas.</p><h4>Instalando o Airbyte</h4><p>O Airbyte pode ser executado localmente usando o Docker ou na nuvem, onde existem custos associados ao uso. Para esta demonstração, usaremos a versão local com Docker.</p><p>A instalação pode levar alguns minutos. Após seguir as instruções de instalação, o Airbyte estará disponível em: http://localhost:8000.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0f9149be887b5500/6a17e302abe0f2b1c6dfe956/66147b5121413ad9baecb10c6886288e917f7c09-1600x1102.png" alt="Instalando o Airbyte" /><p></p><p>Após efetuar o login, podemos começar a configurar a integração.</p><h4>Criando o balde</h4><p>Nesta etapa, você precisará de uma conta da AWS para criar um bucket do S3. Além disso, é essencial definir as permissões corretas criando uma política e um usuário IAM para permitir o acesso ao bucket.</p><p>No bucket, carregaremos arquivos JSON contendo diferentes registros de log, que posteriormente serão migrados para o Elasticsearch. Os arquivos de registro contêm o seguinte:</p>{
   "timestamp": "2025-02-15T14:00:12Z",
   "level": "INFO",
   "service": "data_pipeline",
   "message": "Pipeline execution started",
   "details": {
       "pipeline_id": "abc123",
       "source": "MySQL",
       "destination": "Elasticsearch"
   }
}<p>Abaixo estão os arquivos carregados no bucket:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltbf769c5e9bdb5dfe/6a17e3043e9e45a360ba13f7/f3e7f5889002e3a804121a880d97f1d93044e2f7-1600x680.png" alt="Arquivos carregados no bucket do Airbyte" /><h4>Configuração do Elastic Cloud</h4><p>Para facilitar a demonstração, usaremos o Elastic Cloud. Se você ainda não possui uma conta, pode criar uma conta de avaliação gratuita aqui: <a href="https://cloud.elastic.co/registration">Cadastro no Elastic Cloud</a>.</p><p>Após configurar a implantação no Elastic Cloud, você precisará obter:</p><ul><li><p>O URL do servidor Elasticsearch.</p></li><li><p>Um usuário para acessar o Elasticsearch.</p></li></ul><p>Para obter a URL, acesse Implantações &gt; Minha implantação, em Aplicativo, encontre Elasticsearch e clique em 'Copiar endpoint'.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltddfaaf863168e2bb/6a17e305faa913e29793c7e4/2e38c0bfb2cea83d9ef90dba0e673559fe358199-1368x1056.png" alt="Configuração do Elastic Cloud" /><p>Para criar o usuário, siga os passos abaixo:</p><ol><li><p>Acesse Kibana &gt; Gerenciamento de Pilha &gt; Usuários.</p></li><li><p>Crie um novo usuário com a função de superusuário.</p></li><li><p>Preencha os campos para criar o usuário.</p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltca15b0d3084f4c67/6a17e3073e9e4507e2ba13fb/54d098805087a2d60772475cbb31784083a38c25-1600x1026.png" alt="Criando usuários no Elastic Cloud" /><p>Agora que está tudo configurado, podemos começar a configurar os conectores no Airbyte.</p><h3>Configurando o conector de origem</h3><p>Nesta etapa, criaremos o conector de origem para o S3. Para isso, acessaremos a interface do Airbyte e selecionaremos a opção Fonte no menu. Em seguida, procuraremos o conector S3. A seguir, detalhamos os passos necessários para configurar o conector:</p><ol><li><p>Acesse o Airbyte e vá para o menu Fontes.</p></li><li><p>Procure e selecione o conector S3.</p></li><li><p>Configure os seguintes parâmetros:</p><ol><li><p>Nome da fonte: Defina um nome para a fonte de dados.</p></li><li><p>Método de entrega: Selecione "Replicar registros" (recomendado para dados estruturados).</p></li><li><p>Formato de dados: Selecione o formato JSON.</p></li><li><p>Nome do fluxo: Defina o nome do índice no Elasticsearch.</p></li><li><p>Nome do bucket: Insira o nome do bucket na AWS.</p></li><li><p>Chave de acesso da AWS e chave secreta da AWS: Insira as credenciais de acesso.</p></li></ol></li></ol><p>Clique em Configurar fonte e aguarde a validação.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdca1fb8d8f5d034f/6a17e30963baff75bc741bb2/f83566ab5ebad07ad9fd61dc20353ca5a95c8c92-1600x1099.png" alt="Aguarde a validação da ingestão de dados do Airbyte e do Elasticsearch." /><h3>Conector de destino de configuração</h3><p>Nesta etapa, configuraremos o conector de destino, que será o Elasticsearch. Para isso, acessaremos o menu e selecionaremos a opção Destino. Em seguida, pesquisaremos por Elasticsearch e clicaremos no resultado retornado. Agora, vamos prosseguir com a configuração desta conexão:</p><ol><li><p>Acesse o Airbyte e vá para o menu Destinos.</p></li><li><p>Pesquise e selecione o conector Elasticsearch.</p></li><li><p>Configure os seguintes parâmetros:</p><ol><li><p>Método de autenticação: Escolha Nome de usuário/Senha.</p></li><li><p>Nome de usuário e senha: Utilize as credenciais criadas no Kibana.</p></li><li><p>Endpoint do servidor: Cole a URL copiada do Elastic Cloud.</p></li></ol></li></ol><p>Clique em <strong>Configurar destino</strong> e aguarde a validação.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt72056179d048e027/6a17e30b033c8d5d9d6bb115/f9246b54cc77e0589c0bf658ffc274fd28f766d5-1600x941.png" alt="Crie um destino no Elastic Cloud para ingestão de dados do Airbyte." /><h3>Criando a conexão de origem e destino</h3><p>Após a criação da Origem e do Destino, a conexão entre eles será estabelecida, concluindo assim a integração. </p><p>A seguir, as instruções para criar a conexão:</p><p>1. No menu, acesse Conexões e clique em Criar primeira conexão.</p><p>2. Na tela seguinte, você poderá selecionar uma fonte existente ou criar uma nova. Como já temos uma Origem criada, selecionaremos a Origem S3.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc7f1e01215a7a328/6a17e30c63baff53d7741bb6/14937ccb2686bbde7cb99ffe7e13f7f4e35d7a31-1600x393.png" alt="Selecione uma fonte existente ou crie uma nova no Airbyte." /><p>3. O próximo passo será selecionar o destino. Como já criamos o conector Elasticsearch, ele será selecionado para finalizar a configuração.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltece5c720f28eee00/6a17e30d505ac3dc68ad8aa3/d10962bc175f9ce0b2745ea913d739d3c40ba3b6-1600x431.png" alt="Selecione o destino no Airbyte" /><p>Na próxima etapa, será necessário definir o Modo de Sincronização e qual esquema será utilizado. Como apenas o esquema de log foi criado, essa será a única opção disponível para seleção.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7cbcccad9cfd5a8d/6a17e30f414c64d32d9450e9/d5d3a2e20038d17ef701822fe7ccc38d6e175c50-1600x805.png" alt="Defina o modo de sincronização no Airbyte" /><p>4. Vamos prosseguir para a etapa de Configuração de Conexão. Aqui, podemos definir o nome da conexão e a frequência de execução da integração. A frequência pode ser configurada de três maneiras:</p><ul><li><p><strong>Cron</strong>: Executa as sincronizações com base na expressão cron definida pelo usuário (ex: 0 0 15 * * ?, Às 15:00 todos os dias);</p></li><li><p><strong>Agendado</strong>: Executa as sincronizações no intervalo de tempo especificado (por exemplo, a cada 24 horas, a cada 2 horas);</p></li><li><p><strong>Manual</strong>: Execute as sincronizações manualmente.</p></li></ul><p>Para esta demonstração, selecionaremos a opção Manual.</p><p>Por fim, ao clicar em <strong>Configurar conexão</strong>, a conexão entre a origem e o destino será estabelecida.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4f5fc0e51035b733/6a17e311af47b67ac8cddeff/1a0470f6dff341cb90e6ecfd8ae87a7d2243cbf4-1600x626.png" alt="Ao clicar em Configurar conexão no Airbyte" /><h3>Sincronizando dados do S3 para o Elasticsearch</h3><p>Ao retornar à tela Conexões, você poderá ver a conexão que foi criada. Para executar o processo, basta clicar em Sincronizar. A partir desse momento, terá início a migração de dados do S3 para o Elasticsearch.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9b0ad7a7446f9d58/6a17e3121d1b83b4c593e3c3/c1ce54b129eafb2533b638e4df2b96f3a266ad62-1600x347.png" alt="Sincronizando dados do S3 para o Elasticsearch no Airbyte" /><p>Se tudo correr bem, você receberá o status de sincronização.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt857cdad5bd7fe03f/6a17e313be608646e00046b9/6fe9d5826787066bd8bf0f5e17905df9f8d698e6-1600x361.png" alt="Status sincronizado do S3 para o Elasticsearch no Airbyte" /><h3>Visualizando dados no Kibana</h3><p>Agora, vamos ao Kibana para analisar os dados e verificar se foram indexados corretamente. Na seção Kibana Discovery, criaremos uma visualização de dados chamada logs. Com isso, poderemos explorar os dados existentes apenas no índice de logs, que foi criado após a sincronização.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1bc137f7c04e50ee/6a17e3151480094f2eb486cf/6b6909647ac3187d0fee477cfd732741314f82cf-1600x566.png" alt="Visualizando dados no Kibana: Airbyte e Elastic" /><p>Agora podemos visualizar os dados indexados e realizar análises sobre eles. Dessa forma, validamos todo o fluxo de migração usando o Airbyte, onde carregamos os dados presentes no bucket e os indexamos no Elasticsearch.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd8c0a36a83ee4bb1/6a17e317b1e1135ea679f20e/ca8e9b3d7f7112291af58acf514f4573b44037e8-1600x806.png" alt="Airbyte e Elastic: visualize os dados indexados e realize análises neles no Kibana." /><h2>Conclusão: Integração do Airbyte e do Elasticsearch</h2><p>O Airbyte provou ser uma ferramenta eficiente para integração de dados, permitindo-nos conectar diversas fontes e destinos de forma automatizada. Neste tutorial, demonstramos como ingerir dados de um bucket S3 em um índice Elasticsearch, destacando as principais etapas do processo.</p><p>Essa abordagem facilita a ingestão de grandes volumes de dados e permite análises dentro do Elasticsearch, como buscas complexas, agregações e visualizações de dados.</p><h2>Referências</h2><p><strong>Guia rápido do Airbyte:</strong></p><p><a href="https://docs.airbyte.com/using-airbyte/getting-started/oss-quickstart#part-1-install-abctl">https://docs.airbyte.com/using-airbyte/getting-started/oss-quickstart#part-1-install-abctl</a></p><p><strong>Conceitos básicos:</strong></p><p><a href="https://docs.airbyte.com/using-airbyte/core-concepts/">https://docs.airbyte.com/using-airbyte/core-concepts/</a></p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/airbyte-elasticsearch-ingest-data</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/airbyte-elasticsearch-ingest-data</guid>
    <category><![CDATA[Dados de indexação]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5defe5e12935b233/6a17e318505ac3ed7fad8aa7/dce2bad9949006163af95ed05b5a1eacf5393dc7-1200x628.png" length="0" type="image/png"/>
    <pubDate>Fri, 14 Mar 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Como ingerir dados no Elasticsearch através do LlamaIndex]]></title>
    <description><![CDATA[Um guia passo a passo sobre como ingerir dados e realizar buscas usando RAG com LlamaIndex.]]></description>
    <content:encoded><![CDATA[<p>Neste artigo, implementaremos um mecanismo de busca para FAQs usando o LlamaIndex para indexar os dados. O Elasticsearch servirá como nosso banco de dados de vetores, permitindo a busca vetorial, enquanto o RAG (Retrieval-Augmented Generation) enriquecerá o contexto, fornecendo respostas mais precisas.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte5895fbc057ffc1b/6a17f4cf3e9e45288bba15ef/7ac65a686bdd76c145e903f5c3110c62875a525f-972x501.png" alt="LlamaIndex e Elasticsearch: Ingestão de documentos e criação de uma busca de FAQs" /><h2>O que é o LlamaIndex?</h2><p>O LlamaIndex é uma estrutura que facilita a criação de agentes e fluxos de trabalho baseados em Modelos de Linguagem de Grande Porte (LLMs, na sigla em inglês) para interagir com dados específicos ou privados. Permite a integração de dados de diversas fontes (APIs, PDFs, bases de dados) com LLMs, possibilitando tarefas como pesquisa, extração de informações e geração de respostas contextualizadas.</p><p><strong>Conceitos-chave:</strong></p><ul><li><p>Agentes: Assistentes inteligentes que utilizam LLMs para executar tarefas, desde respostas simples até ações complexas.</p></li><li><p>Fluxos de trabalho: Processos de várias etapas que combinam agentes, conectores de dados e ferramentas para tarefas avançadas.</p></li><li><p>Aumento de contexto: uma técnica que enriquece o modelo de aprendizagem linear (LLM) com dados externos, superando suas limitações de treinamento.</p></li></ul><p><strong>Integração do</strong> <strong>LlamaIndex com o Elasticsearch:</strong></p><p>O Elasticsearch pode ser usado de diversas maneiras com o LlamaIndex:</p><ul><li><p>Fonte de dados: Utilize o Elasticsearch Reader para extrair os documentos.</p></li><li><p>Modelo de embeddings: Codifica dados em vetores para buscas semânticas.</p></li><li><p>Armazenamento vetorial: Utilize o Elasticsearch como repositório para busca de documentos vetorizados.</p></li><li><p>Armazenamento avançado: configure estruturas como resumos de documentos ou grafos de conhecimento.</p></li></ul><h2>Utilizando LlamaIndex e Elasticsearch para construir uma busca de perguntas frequentes (FAQ). </h2><h3>Preparação de dados</h3><p>Usaremos as <a href="https://www.elastic.co/guide/en/cloud/current/ec-faq-getting-started.html">Perguntas Frequentes do Elasticsearch Service</a> como exemplo. Cada pergunta foi extraída do site e salva em um arquivo de texto individual. Você pode usar qualquer abordagem para organizar os dados; neste exemplo, optamos por salvar os arquivos localmente.</p><p>Arquivo de exemplo:</p>File Name: what-is-elasticsearch-service.txt
Content: Elasticsearch Service is hosted and managed Elasticsearch and Kibana brought to you by the creators of Elasticsearch. Elasticsearch Service is part of Elastic Cloud and ships with features that you can only get from the company behind Elasticsearch, Kibana, Beats, and Logstash. Elasticsearch is a full text search engine that suits a range of uses, from search on websites to big data analytics and more.<p>Após salvar todas as perguntas, o diretório ficará assim:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt43467eb9c5579103/6a17f4d02f4a5cc60bfa8a62/1f367d57f2e650334671a2c03156ef4412c0c615-962x704.png" alt="" /><h3>Instalação de dependências</h3><p>Implementaremos a ingestão e a pesquisa usando a linguagem Python, sendo a versão utilizada a 3.9. Como pré-requisito, será necessário instalar as seguintes dependências:</p>llama-index-vector-stores-elasticsearch
llama-index
openai<p>O Elasticsearch e o Kibana serão criados com o Docker, configurados via docker-compose.yml para executar a versão 8.16.2. Isso facilita a criação do ambiente local.</p>version: '3.8'
services:

 elasticsearch:
   image: docker.elastic.co/elasticsearch/elasticsearch:8.16.2
   container_name: elasticsearch-8.16.2
   environment:
     - node.name=elasticsearch
     - xpack.security.enabled=false
     - discovery.type=single-node
     - "ES_JAVA_OPTS=-Xms1024m -Xmx1024m"
   ports:
     - 9200:9200
   networks:
     - shared_network

 kibana:
   image: docker.elastic.co/kibana/kibana:8.16.2
   container_name: kibana-8.16.2
   restart: always
   environment:
     - ELASTICSEARCH_URL=http://elasticsearch:9200
   ports:
     - 5601:5601
   depends_on:
     - elasticsearch
   networks:
     - shared_network

networks:
 shared_network:<h3>Ingestão de documentos usando LlamaIndex</h3><p>Os documentos serão indexados no Elasticsearch usando o LlamaIndex. Primeiro, carregamos os arquivos com <strong>SimpleDirectoryReader</strong>, que permite carregar arquivos de um diretório local. Após carregar os documentos, iremos indexá-los usando o <strong>VectorStoreIndex</strong>.</p>documents = SimpleDirectoryReader("./faq").load_data()

storage_context = StorageContext.from_defaults(vector_store=es)
index = VectorStoreIndex(documents, storage_context=storage_context, embed_model=embed_model)<p>Os Vector Stores no LlamaIndex são responsáveis por armazenar e gerenciar incorporações de documentos. O LlamaIndex suporta diferentes tipos de armazenamentos vetoriais e, neste caso, usaremos o Elasticsearch. No StorageContext, configuramos a instância do Elasticsearch. Como o contexto é local, não foram necessários parâmetros adicionais. Para configurações em outros ambientes, consulte a documentação para verificar os parâmetros necessários: <a href="https://docs.llamaindex.ai/en/stable/examples/vector_stores/ElasticsearchIndexDemo/#configuring-elasticsearchstore">Configuração do ElasticsearchStore</a>.</p><p>Por padrão, o LlamaIndex usa o modelo <strong>text-embedding-ada-002</strong> da OpenAI para gerar embeddings. No entanto, neste exemplo, usaremos o modelo <strong>text-embedding-3-small</strong> . É importante ressaltar que será necessária uma chave de API da OpenAI para usar o modelo.</p><p>Abaixo está o código completo para ingestão de documentos.</p>import openai
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, StorageContext
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.vector_stores.elasticsearch import ElasticsearchStore

openai.api_key = os.environ["OPENAI_API_KEY"]

es = ElasticsearchStore(
   index_name="faq",
   es_url="http://localhost:9200"
)

def format_title(filename):
   filename_without_ext = filename.replace('.txt', '')
   text_with_spaces = filename_without_ext.replace('-', ' ')
   formatted_text = text_with_spaces.title()

   return formatted_text


embed_model = OpenAIEmbedding(model="text-embedding-3-small")

documents = SimpleDirectoryReader("./faq").load_data()

for doc in documents:
   doc.metadata['title'] = format_title(doc.metadata['file_name'])

storage_context = StorageContext.from_defaults(vector_store=es)
index = VectorStoreIndex(documents, storage_context=storage_context, embed_model=embed_model)<p>Após a execução, os documentos serão indexados no índice <strong>de perguntas frequentes</strong> , conforme mostrado abaixo:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt391ae1bfc1daefbf/6a17f4d22f4a5c9887fa8a66/d59b85ed1f57bf80e84d6cb0d6d722a2d12ae4c0-1600x745.png" alt="" /><h3>Pesquisar com RAG</h3><p>Para realizar buscas, configuramos o cliente <strong>ElasticsearchStore</strong> , definindo os campos <strong>index_name</strong> e <strong>es_url</strong> com a URL do Elasticsearch. Em <strong>retrieval_strategy</strong>, definimos a <strong>AsyncDenseVectorStrategy</strong> para buscas vetoriais. Outras estratégias, como <strong>AsyncBM25Strategy</strong> (busca por palavra-chave) e <strong>AsyncSparseVectorStrategy</strong> (vetores esparsos), também estão disponíveis. Mais detalhes podem ser encontrados na <a href="https://docs.llamaindex.ai/en/stable/api_reference/storage/vector_store/elasticsearch/">documentação oficial</a>.</p>es = ElasticsearchStore(
   index_name="faq",
   es_url="http://localhost:9200",
   retrieval_strategy=AsyncDenseVectorStrategy(
   )
)<p>Em seguida, será criado um objeto <strong>VectorStoreIndex</strong> , onde configuraremos o <strong>vector_store</strong> usando o objeto ElasticsearchStore. Com o método <strong>as_retriever</strong> , realizamos a busca pelos documentos mais relevantes para uma consulta, definindo o número de resultados retornados para 5 através do parâmetro <strong>similarity_top_k</strong> .</p>   index = VectorStoreIndex.from_vector_store(vector_store=es)
   retriever = index.as_retriever(similarity_top_k=5)
   results = retriever.retrieve(query)<p>O próximo passo é o RAG. Os resultados da busca vetorial são incorporados a um prompt formatado para o LLM, permitindo uma resposta contextualizada com base nas informações recuperadas.</p><p>No PromptTemplate, definimos o formato do prompt, que inclui:</p><ul><li><p>Contexto ({context_str}): documentos recuperados pelo recuperador.</p></li><li><p>Consulta ({query_str}): a pergunta do usuário.</p></li><li><p>Instruções: diretrizes para o modelo responder com base no contexto, sem depender de conhecimento externo.</p></li></ul>qa_prompt = PromptTemplate(
   "You are a helpful and knowledgeable assistant."
   "Your task is to answer the user's query based solely on the context provided below."
   "Do not use any prior knowledge or external information.\n"
   "---------------------\n"
   "Context:\n"
   "{context_str}\n"
   "---------------------\n"
   "Query: {query_str}\n"
   "Instructions:\n"
   "1. Carefully read and understand the context provided.\n"
   "2. If the context contains enough information to answer the query, provide a clear and concise answer.\n"
   "3. Do not make up or guess any information.\n"
   "Answer: "
)<p>Por fim, o LLM processa a solicitação e retorna uma resposta precisa e contextualizada.</p>llm = OpenAI(model="gpt-4o")
context_str = "\n\n".join([n.node.get_content() for n in results])
response = llm.complete(
   qa_prompt.format(context_str=context_str, query_str=query)
)

print("Answer:")
print(response)<p>O código completo está abaixo:</p>es = ElasticsearchStore(
   index_name="faq",
   es_url="http://localhost:9200",
   retrieval_strategy=AsyncDenseVectorStrategy(
   )
)


def print_results(results):
   for rank, result in enumerate(results, start=1):
       title = result.metadata.get("title")
       score = result.get_score()
       text = result.get_text()
       print(f"{rank}. title={title} \nscore={score} \ncontent={text}")


def search(query: str):
   index = VectorStoreIndex.from_vector_store(vector_store=es)

   retriever = index.as_retriever(similarity_top_k=10)
   results = retriever.retrieve(QueryBundle(query_str=query))
   print_results(results)

   qa_prompt = PromptTemplate(
       "You are a helpful and knowledgeable assistant."
       "Your task is to answer the user's query based solely on the context provided below."
       "Do not use any prior knowledge or external information.\n"
       "---------------------\n"
       "Context:\n"
       "{context_str}\n"
       "---------------------\n"
       "Query: {query_str}\n"
       "Instructions:\n"
       "1. Carefully read and understand the context provided.\n"
       "2. If the context contains enough information to answer the query, provide a clear and concise answer.\n"
       "3. Do not make up or guess any information.\n"
       "Answer: "
   )

   llm = OpenAI(model="gpt-4o")
   context_str = "\n\n".join([n.node.get_content() for n in results])
   response = llm.complete(
       qa_prompt.format(context_str=context_str, query_str=query)
   )

   print("Answer:")
   print(response)


question = "Elastic services are free?"
print(f"Question: {question}")
search(question)<p>Agora podemos realizar nossa busca, por exemplo, "Os serviços da Elastic são gratuitos?" e obter uma resposta contextualizada com base nos próprios dados das perguntas frequentes.</p>Question: Elastic services are free?
Answer:
Elastic services are not entirely free. However, there is a 14-day free trial available for exploring Elastic solutions. After the trial, access to features and services depends on the subscription level.<p>Para gerar esta resposta, foram utilizados os seguintes documentos:</p>1. title=Can I Try Elasticsearch Service For Free 
score=1.0 
content=Yes, sign up for a 14-day free trial. The trial starts the moment a cluster is created.
During the free trial period get access to a deployment to explore Elastic solutions for Enterprise Search, Observability, Security, or the latest version of the Elastic Stack.

2. title=Do You Offer Elastic S Commercial Products 
score=0.9941274512218439 
content=Yes, all Elasticsearch Service customers have access to basic authentication, role-based access control, and monitoring.
Elasticsearch Service Gold, Platinum and Enterprise customers get complete access to all the capabilities in X-Pack: Security, Alerting, Monitoring, Reporting, Graph Analysis &amp; Visualization. Contact us to learn more.

3. title=What Is Elasticsearch Service 
score=0.9896776845746571 
content=Elasticsearch Service is hosted and managed Elasticsearch and Kibana brought to you by the creators of Elasticsearch. Elasticsearch Service is part of Elastic Cloud and ships with features that you can only get from the company behind Elasticsearch, Kibana, Beats, and Logstash. Elasticsearch is a full text search engine that suits a range of uses, from search on websites to big data analytics and more.

4. title=Can I Run The Full Elastic Stack In Elasticsearch Service 
score=0.9880631561979476 
content=Many of the products that are part of the Elastic Stack are readily available in Elasticsearch Service, including Elasticsearch, Kibana, plugins, and features such as monitoring and security. Use other Elastic Stack products directly with Elasticsearch Service. For example, both Logstash and Beats can send their data to Elasticsearch Service. What is run is determined by the subscription level.

5. title=What Is The Difference Between Elasticsearch Service And The Amazon Elasticsearch Service 
score=0.9835054890793161 
content=Elasticsearch Service is the only hosted and managed Elasticsearch service built, managed, and supported by the company behind Elasticsearch, Kibana, Beats, and Logstash. With Elasticsearch Service, you always get the latest versions of the software. Our service is built on best practices and years of experience hosting and managing thousands of Elasticsearch clusters in the Cloud and on premise. For more information, check the following Amazon and Elastic Elasticsearch Service comparison page.
Please note that there is no formal partnership between Elastic and Amazon Web Services (AWS), and Elastic does not provide any support on the AWS Elasticsearch Service.<h2>Conclusão</h2><p>Utilizando o LlamaIndex, demonstramos como criar um sistema de busca de FAQs eficiente com suporte para o Elasticsearch como banco de dados vetorial. Os documentos são ingeridos e indexados usando incorporações, possibilitando buscas vetoriais. Por meio de um PromptTemplate, os resultados da pesquisa são incorporados ao contexto e enviados ao LLM, que gera respostas precisas e contextualizadas com base nos documentos recuperados.</p><p>Este fluxo de trabalho integra a recuperação de informações com a geração de respostas contextualizadas para fornecer resultados precisos e relevantes.</p><h2>Referências</h2><p><a href="https://www.elastic.co/guide/en/cloud/current/ec-faq-getting-started.html">https://www.elastic.co/guide/en/cloud/current/ec-faq-getting-started.html</a></p><p><a href="https://docs.llamaindex.ai/en/stable/api_reference/readers/elasticsearch/">https://docs.llamaindex.ai/en/stable/api_reference/readers/elasticsearch/</a></p><p><a href="https://docs.llamaindex.ai/en/stable/module_guides/indexing/vector_store_index/">https://docs.llamaindex.ai/en/stable/module_guides/indexing/vector_store_index/</a></p><p><a href="https://docs.llamaindex.ai/en/stable/examples/query_engine/custom_query_engine/">https://docs.llamaindex.ai/en/stable/examples/query_engine/custom_query_engine/</a></p><p><a href="https://www.elastic.co/search-labs/integrations/llama-index">https://www.elastic.co/search-labs/integrations/llama-index</a></p><p></p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elasticsearch-llamaindex-ingest-data</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elasticsearch-llamaindex-ingest-data</guid>
    <category><![CDATA[Dados de indexação]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf9f88afa92e90390/6a17f4d33e03d7987d4f2dd0/b8b760bfd8694df43fd74ba90ae5fc1edbe4ce76-1150x628.png" length="0" type="image/png"/>
    <pubDate>Fri, 28 Feb 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Como ingerir dados no Elasticsearch via Apache Airflow]]></title>
    <description><![CDATA[Aprenda como ingerir dados no Elasticsearch usando o Apache Airflow.]]></description>
    <content:encoded><![CDATA[<h2>O que é o Apache Airflow?</h2><p>O Apache Airflow é uma plataforma projetada para criar, agendar e monitorar fluxos de trabalho. É utilizado para orquestrar processos ETL, pipelines de dados e outros fluxos de trabalho complexos, oferecendo flexibilidade e escalabilidade. Sua interface visual e recursos de monitoramento em tempo real tornam o gerenciamento de pipelines mais acessível e eficiente, permitindo acompanhar o progresso e os resultados de suas execuções. Abaixo estão seus quatro pilares principais:</p><ul><li><p><strong>Dinâmico: </strong>Os pipelines são definidos em Python, permitindo a geração de fluxos de trabalho dinâmicos e flexíveis.</p></li><li><p><strong>Extensível:</strong> O Airflow pode ser integrado a uma variedade de ambientes, operadores personalizados podem ser criados e códigos específicos podem ser executados conforme necessário.</p></li><li><p><strong>Elegante:</strong> os pipelines são escritos de forma clara e explícita.</p></li><li><p><strong>Escalável:</strong> Sua arquitetura modular utiliza uma fila de mensagens para orquestrar um número arbitrário de trabalhadores.</p></li></ul><p>Na prática, o Airflow pode ser usado em cenários como:</p><ul><li><p><strong>Importação de dados: </strong>Orquestre a ingestão diária de dados em um banco de dados como o Elasticsearch.</p></li><li><p><strong>Monitoramento de logs:</strong> Gerencie a coleta e o processamento de arquivos de log, que são então analisados no Elasticsearch para identificar erros ou anomalias.</p></li><li><p><strong>Integração de múltiplas fontes de dados:</strong> Combine informações de diferentes sistemas (APIs, bancos de dados, arquivos) em uma única camada no Elasticsearch, simplificando a busca e a geração de relatórios.</p></li></ul><h2>Entendendo os DAGs (Grafos Acíclicos Direcionados) no fluxo de ar</h2><p>No Airflow, os fluxos de trabalho são representados por DAGs (Grafos Acíclicos Direcionados). Um DAG (Grafo Acíclico Direcionado) é uma estrutura que define a sequência em que as tarefas serão executadas. As principais características dos DAGs são:</p><ul><li><p><strong>Composição por tarefas independentes:</strong> Cada tarefa representa uma unidade de trabalho e foi concebida para ser executada de forma independente.</p></li><li><p><strong>Sequenciamento: </strong>A sequência em que as tarefas são executadas é definida explicitamente no DAG (grafo acíclico direcionado).</p></li><li><p><strong>Reutilização:</strong> os DAGs são projetados para serem executados repetidamente, facilitando a automação de processos.</p></li></ul><h2>Componentes do fluxo de ar</h2><p>O ecossistema Airflow é composto por diversos componentes que trabalham em conjunto para orquestrar tarefas:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt25a23489b8725b3e/6a17dfcfe8fbceba103a1846/bacd83aff625026d62f023e0434baa5782a2761a-1046x628.png" alt="Componentes principais do fluxo de ar" /><ul><li><p><strong>Agendador:</strong> Responsável por agendar DAGs e enviar tarefas para execução pelos workers.</p></li><li><p><strong>Executor:</strong> Gerencia a execução de tarefas, delegando-as aos trabalhadores.</p></li><li><p><strong>Servidor Web:</strong> Fornece uma interface gráfica para interação com DAGs e tarefas.</p></li><li><p><strong>Pasta DAGs:</strong> Pasta onde armazenamos os DAGs escritos em Python.</p></li><li><p><strong>Metadados:</strong> Banco de dados que serve como repositório para a ferramenta, usado pelo agendador e pelo executor para armazenar o status da execução.</p></li></ul><h2>Apache Airflow e Elasticsearch</h2><p>Iremos demonstrar o uso do Apache Airflow e do Elasticsearch para orquestrar tarefas e indexar resultados no Elasticsearch. O objetivo desta demonstração é criar um fluxo de tarefas para atualizar registros em um índice do Elasticsearch. Este índice contém um banco de dados de filmes, onde os usuários podem avaliar e atribuir notas. Imaginando um cenário com centenas de avaliações diárias, é necessário manter o registro de avaliações atualizado. Para isso, será desenvolvido um DAG (Grafo Acíclico Direcionado) que será executado diariamente, responsável por obter as novas classificações consolidadas e atualizar os registros no índice.</p><p>No fluxo DAG, teremos uma tarefa para obter as classificações, seguida de uma tarefa para validar os resultados. Caso os dados não existam, o DAG será direcionado para uma tarefa de falha. Caso contrário, os dados serão indexados no Elasticsearch. O objetivo é atualizar o campo de classificação de filmes em um índice, recuperando as classificações por meio de um método com o mecanismo responsável pelo cálculo das pontuações.</p><h2>Utilizando Apache Airflow e Elasticsearch com Docker</h2><p>Para criar um ambiente conteinerizado, usaremos o Apache Airflow com o Docker. Siga as instruções do guia <a href="https://airflow.apache.org/docs/apache-airflow/stable/howto/docker-compose/index.html">"Executando o Airflow no Docker"</a> para configurar o Airflow na prática.</p><p>Quanto ao Elasticsearch, usarei um cluster no Elastic Cloud, mas, se preferir, você também pode configurar o Elasticsearch com o Docker. Já foi criado um índice contendo um catálogo de filmes, com os dados dos filmes indexados. O campo de 'classificação' desses filmes será atualizado.</p><h2>Criando o DAG</h2><p>Após a instalação via Docker, será criada uma estrutura de pastas, incluindo a pasta dags, onde devemos colocar nossos arquivos DAG para que o Airflow os reconheça.</p><p>Antes disso, precisamos garantir que as dependências necessárias estejam instaladas. Aqui estão as dependências deste projeto:</p>pip install apache-airflow apache-airflow-providers-elasticsearch<p>Criaremos o arquivo <code>update_ratings_movies.py</code> e começaremos a codificar as tarefas.</p><p>Agora, vamos importar as bibliotecas necessárias:</p>from airflow import DAG
from airflow.operators.python import PythonOperator, BranchPythonOperator
from airflow.providers.elasticsearch.hooks.elasticsearch import ElasticsearchPythonHook<p>Usaremos o <a href="https://airflow.apache.org/docs/apache-airflow-providers-elasticsearch/stable/hooks/elasticsearch_python_hook.html"><strong>ElasticsearchPythonHook</strong></a>, um componente que simplifica a integração entre o Airflow e um cluster Elasticsearch, abstraindo a conexão e o uso de APIs externas.</p><p>Em seguida, definimos o DAG, especificando seus principais argumentos:</p><ul><li><p><strong><code>dag_id</code></strong>: o nome do DAG.</p></li><li><p><strong><code>start_date</code></strong>: quando o DAG será iniciado.</p></li><li><p><strong><code>schedule</code></strong>: define a periodicidade (diária no nosso caso).</p></li><li><p><strong><code>doc_md</code></strong>Documentação que será importada e exibida na interface do Airflow.</p></li></ul><h2>Definindo as tarefas</h2><p>Agora, vamos definir as tarefas do DAG. A primeira tarefa será responsável por obter os dados de classificação dos filmes. Usaremos o <strong>PythonOperator</strong> com o <code>task_id</code> definido como <code>'get_movie_ratings'</code>. O parâmetro <code>python_callable</code> chamará a função responsável por obter as classificações.</p>get_ratings_operator = PythonOperator(
   task_id='get_movie_ratings',
   python_callable=get_movie_ratings_task
)<p>Em seguida, precisamos validar se os resultados são válidos. Para isso, usaremos uma condicional com um <strong>BranchPythonOperator</strong>. O <code>task_id</code> será <code>'validate_result'</code> e o <code>python_callable</code> chamará a função de validação. O parâmetro <code>op_args</code> será usado para passar o resultado da tarefa anterior, <code>'get_movie_ratings'</code>, para a função de validação.</p>validate_result = BranchPythonOperator(
   task_id='validate_result',
   python_callable=validate_result,
   op_args=["{{ task_instance.xcom_pull(task_ids='get_movie_ratings') }}"]
)<p>Se a validação for bem-sucedida, pegaremos os dados da tarefa <code>'get_movie_ratings'</code> e os indexaremos no Elasticsearch. Para alcançar isso, criaremos uma nova tarefa, <code>'index_movie_ratings'</code>, que usará o <strong>PythonOperator</strong>. O parâmetro <code>op_args</code> passará os resultados da tarefa <code>'get_movie_ratings'</code> para a função de indexação.</p>index_ratings_operator = PythonOperator(
   task_id='index_movie_ratings',
   python_callable=index_movie_ratings_task,
   op_args=["{{ task_instance.xcom_pull(task_ids='get_movie_ratings') }}"]
)<p>Se a validação indicar uma falha, o DAG prosseguirá para uma tarefa de notificação de falha. Neste exemplo, simplesmente imprimimos uma mensagem, mas em um cenário real, poderíamos configurar alertas para notificar sobre as falhas.</p>failed_get_rating_operator = PythonOperator(
   task_id='failed_get_rating_operator',
   python_callable=lambda: print('Ratings were False, skipping indexing.')
)<p>Por fim, definimos as dependências das tarefas, garantindo que elas sejam executadas na ordem correta:</p>get_ratings_operator &gt;&gt; validate_result &gt;&gt; [index_ratings_operator, failed_get_rating_operator]<p>Segue agora o código completo do nosso DAG:</p>"""
DAG update Rating Movies
"""
import ast
import random

from airflow import DAG
from datetime import datetime

from airflow.operators.python import PythonOperator, BranchPythonOperator
from airflow.providers.elasticsearch.hooks.elasticsearch import ElasticsearchPythonHook


def index_movie_ratings_task(movies):
   es_hook = ElasticsearchPythonHook(hosts=None,
                                     es_conn_args={
                                         "cloud_id": "cloud_id"
                                         "api_key": "api-key"
                                     })
   es_client = es_hook.get_conn
   actions = []
   for movie in ast.literal_eval(movies):
       actions.append(
           {
               "update": {
                   "_id": movie["id"],
                   "_index": "movies"
               }
           }
       )
       actions.append(
           {
               "doc": {
                   "rating": movie["rating"]
               },
               "doc_as_upsert": True
           }
       )
   result = es_client.bulk(operations=actions)
   print(f"Ingestion completed.")
   print(result)
   return True


def get_movie_ratings_task():
   movies = [
       {"id": i, "rating": round(random.uniform(1, 10), 1)}
       for i in range(1, 100)
   ]
   return movies

def validate_result(result):
   if not result:
       return 'failed_get_rating_operator'
   else:
       return 'index_movie_ratings'


with DAG(
       dag_id="update_ratings_movies_2024",
       start_date=datetime(2024, 12, 29),
       schedule="@daily",
       doc_md=__doc__,
):
   get_ratings_operator = PythonOperator(
       task_id='get_movie_ratings',
       python_callable=get_movie_ratings_task
   )

   validate_result = BranchPythonOperator(
       task_id='validate_result',
       python_callable=validate_result,
       op_args=["{{ task_instance.xcom_pull(task_ids='get_movie_ratings') }}"],
       provide_context=True
   )

   index_ratings_operator = PythonOperator(
       task_id='index_movie_ratings',
       python_callable=index_movie_ratings_task,
       op_args=["{{ task_instance.xcom_pull(task_ids='get_movie_ratings') }}"]
   )

   failed_get_rating_operator = PythonOperator(
       task_id='failed_get_rating_operator',
       python_callable=lambda: print('Ratings were False, skipping indexing.')
   )

get_ratings_operator &gt;&gt; validate_result &gt;&gt; [index_ratings_operator, failed_get_rating_operator]<h2>Visualizando a execução do DAG</h2><p>Na interface do Apache Airflow, podemos visualizar a execução dos DAGs (grafos acíclicos direcionados). Basta acessar a aba "DAGs" e localizar o DAG que você criou.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9c5de210a5a264ad/6a17dfd00b0bed0290dd34cf/905b9191c4e3191e8b5608174d4c555370bf25eb-1600x760.png" alt="Visualize a execução dos DAGs na interface do Apache Airflow com o Elasticsearch." /><p>Abaixo, podemos visualizar a execução das tarefas e seus respectivos status. Ao selecionar uma execução para uma data específica, podemos acessar os registros de cada tarefa. Observe que na tarefa <strong><code>index_movie_ratings</code></strong> , podemos ver os resultados da indexação no índice e que ela foi concluída com sucesso.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0beddf311a808d24/6a17dfd2033c8d76de6bb0ba/73c3f738d27500cf153377bedf1aa2b67a94a8c8-1600x648.png" alt="Visualize a execução das tarefas e seus respectivos status no Apache Airflow com o Elasticsearch." /><p>Nas outras abas, é possível acessar informações adicionais sobre as tarefas e o DAG, auxiliando na análise e resolução de possíveis problemas.</p><h2>Conclusão</h2><p>Neste artigo, demonstramos como integrar o Apache Airflow com o Elasticsearch para criar uma solução de ingestão de dados. Mostramos como configurar o DAG, definir as tarefas responsáveis por recuperar, validar e indexar dados de filmes, bem como monitorar e visualizar a execução dessas tarefas na interface do Airflow.</p><p>Essa abordagem pode ser facilmente adaptada a diferentes tipos de dados e fluxos de trabalho, tornando o Airflow uma ferramenta útil para orquestrar pipelines de dados em diversos cenários.</p><h2>Referências</h2><p>Apache AirFlow</p><p><a href="https://airflow.apache.org/">https://airflow.apache.org/</a></p><p>Instale o Apache Airflow com o Docker.</p><p><a href="https://airflow.apache.org/docs/apache-airflow/stable/howto/docker-compose/index.html">https://airflow.apache.org/docs/apache-airflow/stable/howto/docker-compose/index.html</a></p><p>Gancho Python do Elasticsearch</p><p><a href="https://airflow.apache.org/docs/apache-airflow-providers-elasticsearch/stable/hooks/elasticsearch_python_hook.html">https://airflow.apache.org/docs/apache-airflow-providers-elasticsearch/stable/hooks/elasticsearch_python_hook.html</a></p><p>Operador Python</p><p><a href="https://airflow.apache.org/docs/apache-airflow/stable/howto/operator/python.html">https://airflow.apache.org/docs/apache-airflow/stable/howto/operator/python.html</a></p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/apache-airflow-elasticsearch-ingest-data</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/apache-airflow-elasticsearch-ingest-data</guid>
    <category><![CDATA[Dados de indexação]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt28475ace97d1d989/6a1704c9286714d6dd93e1ec/5d4b47ac5d2ba453fc19dcc15efa2aed5f55d88b-1440x1355.png" length="0" type="image/png"/>
    <pubDate>Fri, 17 Jan 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Como ingerir dados no Elasticsearch através do Kafka]]></title>
    <description><![CDATA[Um guia passo a passo para integrar o Apache Kafka com o Elasticsearch para ingestão, indexação e visualização de dados de forma eficiente usando Python, Docker Compose e Kafka Connect.]]></description>
    <content:encoded><![CDATA[<p>Neste artigo, mostramos como integrar o Apache Kafka com o Elasticsearch para ingestão e indexação de dados. Iremos apresentar uma visão geral do Kafka, seu conceito de produtores e consumidores, e criaremos um índice de logs onde as mensagens serão recebidas e indexadas através do Apache Kafka. O projeto foi implementado em Python e o código está disponível no <a href="https://github.com/elastic/elasticsearch-labs/tree/main/supporting-blog-content/elasticsearch-through-apache-kafka">GitHub</a>.</p><h3><strong>Pré-requisitos</strong></h3><ul><li><p>Docker e Docker Compose: Certifique-se de ter o Docker e o Docker Compose instalados em sua máquina.</p></li><li><p>Python 3.x: Para executar os scripts do produtor e do consumidor.</p></li></ul><h3><strong>Introdução ao Apache Kafka</strong></h3><p>O Apache Kafka é uma plataforma de streaming distribuída que permite alta escalabilidade e disponibilidade, além de tolerância a falhas. No Kafka, o gerenciamento de dados ocorre por meio dos seguintes componentes principais:</p><ul><li><p><strong>Intermediário (Broker)</strong>: responsável por armazenar e distribuir mensagens entre produtores e consumidores.</p></li><li><p><strong>Zookeeper</strong>: gerencia e coordena os brokers do Kafka, controlando o estado do cluster, os líderes de partição e as informações do consumidor.</p></li><li><p><strong>Tópicos</strong>: canais onde os dados são publicados e armazenados para consumo.</p></li><li><p><strong>Consumidores e Produtores</strong>: enquanto os produtores enviam dados para os tópicos, os consumidores recuperam esses dados.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4aae32304d7417f6/6a17f7be577262b47c1bcdac/89a37243baec48bbdfa85e3298fc91082322ed4e-1600x868.png" alt="Diagrama do Apache Kafka" /><p>Esses componentes trabalham juntos para formar o ecossistema Kafka, fornecendo uma estrutura robusta para streaming de dados.</p><h3><strong>Estrutura do projeto</strong></h3><p>Para entender o processo de ingestão de dados, dividimos o processo em etapas:</p><ul><li><p><strong>Provisionamento de infraestrutura</strong>: configuração do ambiente Docker para suportar Kafka, Elasticsearch e Kibana.</p></li><li><p><strong>Criação do produtor</strong>: implementação do produtor Kafka, que envia dados para o tópico de logs.</p></li><li><p><strong>Criação do consumidor</strong>: desenvolvimento do consumidor Kafka para ler e indexar mensagens no Elasticsearch.</p></li><li><p><strong>Validação de ingestão</strong>: verificação e validação dos dados enviados e consumidos.</p></li></ul><h3><strong>Configuração de infraestrutura com Docker Compose</strong></h3><p>Utilizamos o Docker Compose para configurar e gerenciar os serviços necessários. A seguir, você encontrará o código Docker Compose que configura cada serviço necessário para a integração do Apache Kafka, Elasticsearch e Kibana, garantindo um processo de ingestão de dados.</p>version: "3"

services:

  zookeeper:
    image: confluentinc/cp-zookeeper:latest
    container_name: zookeeper
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181

  kafka:
    image: confluentinc/cp-kafka:latest
    container_name: kafka
    depends_on:
      - zookeeper
    ports:
      - "9092:9092"
      - "9094:9094"
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST:${HOST_IP}:9092
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1

  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.15.1
    container_name: elasticsearch-8.15.1
    environment:
      - node.name=elasticsearch
      - xpack.security.enabled=false
      - discovery.type=single-node
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    volumes:
      - ./elasticsearch:/usr/share/elasticsearch/data
    ports:
      - 9200:9200

  kibana:
    image: docker.elastic.co/kibana/kibana:8.15.1
    container_name: kibana-8.15.1
    ports:
      - 5601:5601
    environment:
      ELASTICSEARCH_URL: http://elasticsearch:9200
      ELASTICSEARCH_HOSTS: '["http://elasticsearch:9200"]'<p>Você pode acessar o arquivo diretamente do repositório <a href="https://github.com/andreluiz1987/elasticsearch-labs/tree/supporting-blog/elasticsearch-apache-kafka/supporting-blog-content/elasticsearch-through-apache-kafka">GitHub</a> do Elasticsearch Labs.</p><h3><strong>Envio de dados com o Kafka Producer</strong></h3><p>O produtor é responsável por enviar mensagens para o tópico de logs. Ao enviar mensagens em lotes, aumenta-se a eficiência do uso da rede, permitindo otimizações com as configurações <code>batch_size</code> e <code>linger_ms</code> , que controlam a quantidade e a latência dos lotes, respectivamente. A configuração <code>acks='all'</code> garante que as mensagens sejam armazenadas de forma durável, o que é essencial para dados de log importantes.</p>producer = KafkaProducer(
   bootstrap_servers=['localhost:9092'],  # Specifies the Kafka server to connect
   value_serializer=lambda x: json.dumps(x).encode('utf-8'),  # Serializes data as JSON and encodes it to UTF-8 before sending
   batch_size=16384,     # Sets the maximum batch size in bytes (here, 16 KB) for buffered messages before sending
   linger_ms=10,         # Sets the maximum delay (in milliseconds) before sending the batch
   acks='all'            # Specifies acknowledgment level; 'all' ensures message durability by waiting for all replicas to acknowledge
)


def generate_log_message():
   levels = ["INFO", "WARNING", "ERROR", "DEBUG"]
   messages = [
       "User login successful",
       "User login failed",
       "Database connection established",
       "Database connection failed",
       "Service started",
       "Service stopped",
       "Payment processed",
       "Payment failed"
   ]
   log_entry = {
       "level": random.choice(levels),
       "message": random.choice(messages),
       "timestamp": time.time()
   }
   return log_entry

def send_log_batches(topic, num_batches=5, batch_size=10):
   for i in range(num_batches):
       logger.info(f"Sending batch {i + 1}/{num_batches}")
       for  in range(batch_size):
           log_message = generate_log_message()
           producer.send(topic, value=log_message)
       producer.flush()


if __name__ == "__main__":
   topic = "logs"
   send_log_batches(topic)
   producer.close()<p>Ao iniciar o produtor, as mensagens são enviadas em lotes para o tópico, conforme mostrado abaixo:</p>INFO:kafka.conn:Set configuration …
INFO:log_producer:Sending batch 1/5 
INFO:log_producer:Sending batch 2/5
INFO:log_producer:Sending batch 3/5
INFO:log_producer:Sending batch 4/5<h3><strong>Consumo e indexação de dados com o Kafka Consumer.</strong></h3><p>O consumidor foi projetado para processar mensagens de forma eficiente, consumindo lotes do tópico de logs e indexando-os no Elasticsearch. Com <code>auto_offset_reset='latest'</code>, garante-se que o consumidor comece a processar as mensagens mais recentes, ignorando as mais antigas, e <code>max_poll_records=10</code> limita o lote a 10 mensagens. Com <code>fetch_max_wait_ms=2000</code>, o consumidor espera até 2 segundos para acumular mensagens suficientes antes de processar o lote.</p><p>Em seu loop principal, o consumidor consome mensagens de log, processa e indexa cada lote no Elasticsearch, garantindo a ingestão contínua de dados.</p>consumer = KafkaConsumer(
   'logs',                               
   bootstrap_servers=['localhost:9092'],
   auto_offset_reset='latest',            # Ensures reading from the latest offset if the group has no offset stored
   enable_auto_commit=True,               # Automatically commits the offset after processing
   group_id='log_consumer_group',         # Specifies the consumer group to manage offset tracking
   max_poll_records=10,                   # Maximum number of messages per batch
   fetch_max_wait_ms=2000                 # Maximum wait time to form a batch (in ms)
)

def create_bulk_actions(logs):
   for log in logs:
       yield {
           "_index": "logs",
           "_source": {
               'level': log['level'],
               'message': log['message'],
               'timestamp': log['timestamp']
           }
       }

if __name__ == "__main__":
   try:
       print("Starting message processing…")
       while True:

           messages = consumer.poll(timeout_ms=1000)  # Poll receive messages

           # process each batch messages
           for _, records in messages.items():
               logs = [json.loads(record.value) for record in records]
               bulk_actions = create_bulk_actions(logs)
               response = helpers.bulk(es, bulk_actions)
               print(f"Indexed {response[0]} logs.")
   except Exception as e:
       print(f"Erro: {e}")
   finally:
       consumer.close()
       print(f"Finish")<h3><strong>Visualizando dados no Kibana</strong></h3><p>Com o Kibana, podemos explorar e validar os dados ingeridos do Kafka e indexados no Elasticsearch. Ao acessar <strong>as Ferramentas de Desenvolvimento</strong> no Kibana, você pode visualizar as mensagens indexadas e confirmar se os dados estão conforme o esperado. Por exemplo, se o nosso produtor Kafka enviar 5 lotes de 10 mensagens cada, devemos ver um total de 50 registros no índice.</p><p>Para verificar os dados, você pode usar a seguinte consulta na seção <strong>Ferramentas de Desenvolvimento</strong> :</p>GET /logs/_search
{
  "query": {
    "match_all": {}
  }
}<p>Resposta.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc15fb278fe6f984e/6a17f7c0b1e1131ac279f404/f44f95fc27bba50991412d5c7e7728519b9bdec4-688x1024.png" alt="Resposta: verifique os dados - Kafka e Elasticsearch​" /><p>Além disso, o Kibana oferece a capacidade de criar visualizações e painéis que podem ajudar a tornar a análise mais intuitiva e interativa. Abaixo, você pode ver alguns exemplos dos painéis e visualizações que criamos, os quais ilustram os dados em vários formatos, aprimorando nossa compreensão das informações processadas.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltabc2856c9feedc47/6a17f7c13e9e4522bfba1651/a18e0ebb543e929136d4786651bc6cee32fa69bc-1600x470.png" alt="Visualização do Kibana - Kafka e Elasticsearch​" /><h3><strong>Ingestão de dados com Kafka Connect</strong></h3><p>O Kafka Connect é um serviço projetado para facilitar a integração entre fontes de dados e destinos (sinks), como bancos de dados ou sistemas de arquivos. Ele opera com conectores predefinidos que gerenciam a movimentação de dados automaticamente. Em nosso caso, o Elasticsearch funciona como o coletor de dados.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt53e3acaf62e7dbed/6a17f7c3577262c5151bcdb0/52a6982c864fdc04cb7a8a5fb02e67dca0ba8226-1600x819.png" alt="Ingestão de dados com Kafka Connect" /><p>Ao usar o Kafka Connect, podemos simplificar o processo de ingestão de dados, eliminando a necessidade de implementar manualmente o fluxo de trabalho de ingestão de dados no Elasticsearch. Com o conector apropriado, o Kafka Connect permite que os dados enviados para um tópico do Kafka sejam indexados diretamente no Elasticsearch com configuração mínima e sem necessidade de codificação adicional.</p><h4><strong>Trabalhando com o Kafka Connect</strong></h4><p>Para implementar o Kafka Connect, adicionaremos o<a href="https://github.com/andreluiz1987/es-apache-kafka/blob/main/docker-compose.yml#L31"> serviço kafka-connect </a>à nossa configuração do Docker Compose. Uma parte fundamental dessa configuração é a instalação do conector Elasticsearch, que ficará responsável pela indexação dos dados.</p><p>Após configurar o serviço e criar o contêiner do Kafka Connect, será necessário um arquivo de configuração para o conector do Elasticsearch. Este arquivo define parâmetros essenciais, tais como:</p><ul><li><p><code>connection.url</code>URL de conexão para o Elasticsearch.</p></li><li><p><code>topics</code>O tópico do Kafka que o conector irá monitorar (neste caso, "logs").</p></li><li><p><code>type.name</code>Tipo de documento no Elasticsearch (normalmente _doc).</p></li><li><p><code>value.converter</code>Converte mensagens do Kafka para o formato JSON.</p></li><li><p><code>value.converter.schemas.enable</code>Especifica se o esquema deve ser incluído.</p></li><li><p><code>schema.ignore</code> e <code>key.ignore</code>: Configurações para ignorar esquemas e chaves do Kafka durante a indexação.</p></li></ul><p>Abaixo está o comando <code>curl</code> para criar o conector Elasticsearch no Kafka Connect:</p>curl --location '{{url}}/connectors' \
--header 'Content-Type: application/json' \
--data '{
    "name": "elasticsearch-sink-connector",
    "config": {
        "connector.class": "io.confluent.connect.elasticsearch.ElasticsearchSinkConnector",
        "topics": "logs",
        "connection.url": "http://elasticsearch:9200",
        "type.name": "_doc",
        "value.converter": "org.apache.kafka.connect.json.JsonConverter",
        "value.converter.schemas.enable": "false",
        "schema.ignore": "true",
        "key.ignore": "true"
    }
}'<p>Com essa configuração, o Kafka Connect começará automaticamente a ingerir os dados enviados para o tópico "logs" e a indexá-los no Elasticsearch. Essa abordagem permite a ingestão e indexação de dados totalmente automatizadas, sem a necessidade de codificação adicional, simplificando assim todo o processo de integração.</p><h3><strong>Conclusão</strong></h3><p>A integração do Kafka e do Elasticsearch cria um poderoso pipeline para ingestão e análise de dados em tempo real. Este guia fornece uma abordagem fundamental para a construção de uma arquitetura robusta de ingestão de dados, com visualização e análise integradas no Kibana, pronta para se adaptar a requisitos mais complexos no futuro.</p><p>Além disso, o uso do Kafka Connect torna a integração entre o Kafka e o Elasticsearch ainda mais simplificada, eliminando a necessidade de código adicional para processar e indexar dados. O Kafka Connect permite que os dados enviados para um tópico específico sejam indexados automaticamente no Elasticsearch com configuração mínima.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elasticsearch-apache-kafka-ingest-data</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elasticsearch-apache-kafka-ingest-data</guid>
    <category><![CDATA[Dados de indexação]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt53e3acaf62e7dbed/6a17f7c3577262c5151bcdb0/52a6982c864fdc04cb7a8a5fb02e67dca0ba8226-1600x819.png" length="0" type="image/png"/>
    <pubDate>Tue, 24 Dec 2024 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Como ingerir dados no Elasticsearch usando o Apache Camel]]></title>
    <description><![CDATA[Aprenda como ingerir dados no Elasticsearch usando o Apache Camel com um exemplo prático.]]></description>
    <content:encoded><![CDATA[<p>A ingestão de dados no Elasticsearch usando o Apache Camel é um processo que combina a robustez de um mecanismo de busca com a flexibilidade de uma estrutura de integração. Neste artigo, exploraremos como o Apache Camel pode simplificar e otimizar a ingestão de dados no Elasticsearch. Para ilustrar essa funcionalidade, implementaremos uma aplicação introdutória que demonstra, passo a passo, como configurar e usar o Apache Camel para enviar dados para o Elasticsearch.</p><h2>O que é o Apache Camel?</h2><p>O Apache Camel é uma estrutura de integração de código aberto que simplifica a conexão de diversos sistemas, permitindo que os desenvolvedores se concentrem na lógica de negócios sem se preocuparem com as complexidades da comunicação entre sistemas. O conceito central do Camel é o de "rotas", que definem o caminho que uma mensagem percorre da origem ao destino, podendo incluir etapas intermediárias como transformações, validações e filtragem.</p><h3>Arquitetura Apache Camel</h3><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt05652327efd4d5d1/6a17e6dafbc5f8a588491a8b/bef8145623a8fa80f929f9faa57ce0c460be2d0b-884x458.png" alt="Arquitetura Apache Camel" /><p>O Camel usa "componentes" para se conectar a diferentes sistemas e protocolos, como bancos de dados e serviços de mensagens, e "pontos de extremidade" para representar os pontos de entrada e saída das mensagens. Esses conceitos proporcionam um design modular e flexível, facilitando a configuração e o gerenciamento de integrações complexas de forma eficiente e escalável.</p><h2>Utilizando Elasticsearch e Apache Camel</h2><p>Vamos demonstrar como configurar uma aplicação Java simples que utiliza o Apache Camel para ingerir dados em um cluster Elasticsearch. Os processos de criação, atualização e exclusão de dados no Elasticsearch usando rotas definidas no Apache Camel também serão abordados.</p><h3>1. Adicionando dependências</h3><p>O primeiro passo para configurar esta integração é adicionar as dependências necessárias ao arquivo <code>pom.xml</code> do seu projeto. Isso incluirá as bibliotecas Apache Camel e Elasticsearch. Usaremos a nova biblioteca Java API Client, portanto, devemos importar o componente <code>camel-elasticsearch</code> e a versão deve ser a mesma da biblioteca <code>camel-core</code> .</p><p>Se você deseja usar o cliente REST de baixo nível em Java, deve usar o componente Cliente REST de baixo nível do Elasticsearch.</p>&lt;dependency&gt;
   &lt;groupId&gt;org.apache.camel&lt;/groupId&gt;
   &lt;artifactId&gt;camel-core&lt;/artifactId&gt;
   &lt;version&gt;4.7.0&lt;/version&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
   &lt;groupId&gt;org.apache.camel&lt;/groupId&gt;
   &lt;artifactId&gt;camel-elasticsearch&lt;/artifactId&gt;
   &lt;version&gt;4.7.0&lt;/version&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
   &lt;groupId&gt;org.apache.camel&lt;/groupId&gt;
   &lt;artifactId&gt;camel-jackson&lt;/artifactId&gt;
   &lt;version&gt;4.7.0&lt;/version&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
   &lt;groupId&gt;co.elastic.clients&lt;/groupId&gt;
   &lt;artifactId&gt;elasticsearch-java&lt;/artifactId&gt;
   &lt;version&gt;8.14.3&lt;/version&gt;
&lt;/dependency&gt;
<h3>2. Configurando e executando o contexto do Camel</h3><p>A configuração começa com a criação de um novo contexto Camel usando a classe <code>DefaultCamelContext</code> , que serve como base para definir e executar rotas. Em seguida, configuramos o componente Elasticsearch, que permitirá que o Apache Camel interaja com um cluster Elasticsearch. A instância <code>ESlasticsearchComponent</code> está configurada para se conectar ao endereço <code>localhost:9200</code>, que é o endereço padrão para um cluster Elasticsearch local. Para uma configuração de ambiente que requer autenticação, você deve ler a documentação sobre como configurar o componente e habilitar a autenticação básica, referida como <strong>"Configurar o componente e habilitar a autenticação básica"</strong>.</p>public class ESComponent {

    public static ElasticsearchComponent getInstance() {
        var elasticsearch = new ElasticsearchComponent();
        elasticsearch.setHostAddresses("localhost:9200");
        return elasticsearch;
    }

    public static String getName() {
        return "elasticsearch";
    }
}
<p>Em seguida, esse componente é adicionado ao contexto do Camel, permitindo que as rotas definidas o utilizem para realizar operações no Elasticsearch.</p>try (var context = new DefaultCamelContext()) {
   context.addComponent(ESComponent.getName(), ESComponent.getInstance());
   context.addRoutes(new OperationBulkRoute());
   context.start();
}
<p>Em seguida, as rotas são adicionadas ao contexto. Criaremos rotas para indexação, atualização e exclusão em massa de documentos.</p><h3>3. Configurando rotas do Camel</h3><h4>Indexação de dados</h4><p>A primeira rota que configuraremos é para indexação de dados. Utilizaremos um arquivo JSON contendo um catálogo de filmes. A rota será configurada para ler o arquivo localizado em <a href="https://gist.github.com/andreluiz1987/40756874b5fbea0a29586f9376d7f1f4"><code>src/main/resources/movies.json</code></a>, desserializar o conteúdo JSON em objetos Java e, em seguida, aplicar uma estratégia de agregação para combinar várias mensagens em uma só, permitindo operações em lote no Elasticsearch. O tamanho configurado para 500 itens por mensagem é o seguinte: o processo em lote indexará 500 filmes por vez.</p><p>Roteamento Elasticsearch Operação em massa</p>String URI_BULK_OPERATION = String
       .format("elasticsearch://elasticsearch?operation=%s&amp;indexName=%s",
               IndexOperationConfig.BULK_OPERATION,
               INDEX_NAME);
public class OperationBulkRoute extends RouteBuilder {
   private static final Log log = LogFactory.getLog(OperationBulkRoute.class);
   private static final int BULK_SIZE = 500;

   @Override
   public void configure() {
       from("file:src/main/resources?fileName=movies.json&amp;noop=true")
               .routeId("route-bulk-ingest")
               .unmarshal().json()
               .split(body())
               .aggregate(constant(true), new BulkAggregationStrategy())
               .completionSize(BULK_SIZE)
               .to(URI_BULK_OPERATION)
               .process(exchange -&gt; {
                   var body = exchange.getIn().getBody(String.class);
                   log.info(String.format("Response: %s", body));
               })
               .end();
   }
}
<p>O lote de documentos será enviado para o endpoint de operações em lote do Elasticsearch. Essa abordagem garante eficiência e rapidez no processamento de grandes volumes de dados.</p><h4>Atualização de dados</h4><p>O próximo passo será atualizar os documentos. Na etapa anterior, indexamos alguns filmes e agora criaremos novas rotas para pesquisar um documento por código de referência e, em seguida, atualizar o campo de classificação.</p><p>Configuramos um contexto Camel <code>(DefaultCamelContext)</code>, onde um componente Elasticsearch é registrado e uma rota personalizada IngestionRoute é adicionada. A operação começa com o envio do código do documento através do ProducerTemplate, que inicia a rota a partir do endpoint direct:update-ingestion.</p>try (var context = new DefaultCamelContext()) {
    context.addComponent(ESComponent.getName(), ESComponent.getInstance());
    context.addRoutes(new IngestionRoute());
    context.start();
    ProducerTemplate producerTemplate = context.createProducerTemplate();
    producerTemplate.sendBody("direct:update-ingestion", documentCode);
    Thread.sleep(5000);
}
<p>Em seguida, temos o IngestionRoute, que é o ponto de extremidade de entrada para este fluxo. A rota executa diversas operações em dutos. Primeiro, é feita uma busca no Elasticsearch para localizar o documento pelo código <code>(direct:search-by-id)</code>, onde o SearchByCodeProcessor monta a consulta com base no código. Em seguida, o documento recuperado é processado pelo UpdateRatingProcessor, que converte o resultado em objetos Movie, atualiza a classificação do filme para um valor específico e prepara o documento atualizado para ser enviado de volta ao Elasticsearch para atualização.</p>public class IngestionRoute extends RouteBuilder {
    private static final Log log = LogFactory.getLog(IngestionRoute.class);

    @Override
    public void configure() throws Exception {

        from("direct:update-ingestion")
                .pipeline()
                .to("direct:search-by-id")
                .to(URI_SEARCH_OPERATION)
                .to("direct:update-rating")
                .to(URI_UPDATE_OPERATION)
                .process(exchange -&gt; {
                    var body = exchange.getIn().getBody(String.class);
                    log.info(String.format("Response: %s", body));
                })
                .end();

        from("direct:search-by-id")
                .process(new SearchByCodeProcessor());

        from("direct:update-rating")
                .process(new UpdateRatingProcessor());
    }
}
<p>O processador <code>SearchByCodeProcessor</code> foi configurado apenas para executar a consulta de pesquisa:</p>public class SearchByCodeProcessor implements Processor {
    @Override
    public void process(Exchange exchange) throws Exception {
        var code = exchange.getIn().getBody();

        String query = "{\n" +
                "  \"query\": {\n" +
                "   \"term\": {\n" +
                "     \"code\": {\n" +
                "       \"value\":" + code + "\n" +
                "     }\n" +
                "   }\n" +
                "  }\n" +
                "}";
        exchange.setProperty("document_code", code);
        exchange.getIn().setBody(query);
    }
}
<p>O processador <code>UpdateRatingProcessor</code> é responsável por atualizar o campo de classificação.</p>public class UpdateRatingProcessor implements Processor {

    private final ObjectMapper objectMapper;

    public UpdateRatingProcessor() {
        this.objectMapper = new ObjectMapper();
        this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    @Override
    public void process(Exchange exchange) throws Exception {

        HitsMetadata response = exchange.getIn().getBody(HitsMetadata.class);
        var code = Long.parseLong(exchange.getProperty("document_code").toString());

        if (response != null &amp;&amp; response.hits() != null) {

            var documents = parseToMovies(response);

            var optionalMovie = documents.stream()
                    .filter(document -&gt; code == (document.getSource().getCode())).findAny();

            optionalMovie.ifPresent(document -&gt; {
                document.getSource().setRating(13.0);
                Map&lt;String, Object&gt; updateMap = new HashMap&lt;&gt;();
                updateMap.put("doc", document.getSource());
                exchange.getIn().setHeader("indexId", document.getId());
                exchange.getIn().setBody(updateMap);
            });
        }
    }
<h4>Exclusão de dados</h4><p>Por fim, a rota para exclusão de documentos está configurada. Aqui, vamos excluir um documento usando seu ID. No Elasticsearch, para excluir um documento, precisamos saber o identificador do documento, o índice onde o documento está armazenado e executar uma solicitação de exclusão. No Apache Camel, realizaremos essa operação criando uma nova rota, conforme mostrado abaixo.</p><p>A rota começa no endpoint direct:op-delete, que serve como ponto de entrada. Quando um documento precisa ser excluído, seu identificador <code>(_id)</code> é recebido no corpo da mensagem. A rota então define o cabeçalho indexId com o valor deste identificador usando simples<code>("${body}")</code>, que extrai o _id do corpo da mensagem.</p>public class OperationDeleteRoute extends RouteBuilder {
   private static final Log log = LogFactory.getLog(OperationDeleteRoute.class);

   @Override
   public void configure() {
       from("direct:op-delete")
               .routeId("route-delete")
               .setHeader("indexId", simple("${body}"))
               .to(URI_DELETE_OPERATION)
               .process(exchange -&gt; {
                   var body = exchange.getIn().getBody(String.class);
                   log.info(String.format("Response: %s", body));
               })
               .end();
       ;
   }
}
String URI_DELETE_OPERATION = String
       .format("elasticsearch://elasticsearch?operation=%s&amp;indexName=%s",
               IndexOperationConfig.DELETE_OPERATION,
               INDEX_NAME);
<p>Por fim, a mensagem é direcionada para o endpoint especificado por URI_DELETE_OPERATION, que se conecta ao Elasticsearch para executar a operação de remoção do documento no índice correspondente.
Agora que criamos a rota, podemos criar um contexto Camel <code>(DefaultCamelContext)</code>, que está configurado para incluir o componente Elasticsearch.</p>try (var context = new DefaultCamelContext()) {
   context.addComponent(ESComponent.getName(), ESComponent.getInstance());
   context.addRoutes(new OperationDeleteRoute());
   context.start();
   ProducerTemplate producerTemplate = context.createProducerTemplate();
   producerTemplate.sendBody("direct:op-delete", documentId);
}
<p>Em seguida, a rota de exclusão, definida pela classe <code>OperationDeleteRoute</code> , é adicionada ao contexto. Com o contexto inicializado, um <code>ProducerTemplate</code> é usado para passar o identificador do documento que deve ser excluído para o endpoint <code>direct:op-delete</code> , que aciona a rota de exclusão.</p><h2>Conclusão</h2><p>A integração entre o Apache Camel e o Elasticsearch permite uma ingestão de dados robusta e eficiente, aproveitando a flexibilidade do Camel para definir rotas que podem lidar com diferentes cenários de manipulação de dados, como indexação, atualização e exclusão. Com essa configuração, você pode orquestrar e automatizar processos complexos de forma escalável, garantindo que seus dados sejam gerenciados com eficiência no Elasticsearch. Este exemplo demonstrou como essas ferramentas podem ser usadas em conjunto para criar uma solução eficiente e adaptável para ingestão de dados.</p><h2>Referências</h2><ul><li><p><a href="https://camel.apache.org/manual/">Camelo Apache</a></p></li><li><p><a href="https://camel.apache.org/manual/architecture.html">Arquitetura Apache Camel</a></p></li><li><p><a href="https://camel.apache.org/components/4.4.x/eips/aggregate-eip.html">Apache Camel agregado</a></p></li><li><p><a href="https://camel.apache.org/components/4.4.x/file-component.html">Componente de arquivo</a></p></li><li><p><a href="https://camel.apache.org/components/4.4.x/elasticsearch-component.html">componente Elasticsearch</a></p></li></ul>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elasticsearch-apache-camel-ingest-data</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elasticsearch-apache-camel-ingest-data</guid>
    <category><![CDATA[Dados de indexação]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt05652327efd4d5d1/6a17e6dafbc5f8a588491a8b/bef8145623a8fa80f929f9faa57ce0c460be2d0b-884x458.png" length="0" type="image/png"/>
    <pubDate>Mon, 09 Sep 2024 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>