<?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[Andre Luiz - 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[Andre Luiz - 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/author/andre-luiz</link>
    </image>
    <link>https://www.elastic.co/pt/search-labs/author/andre-luiz</link>
    <atom:link href="https://www.elastic.co/pt/search-labs/rss/author/andre-luiz.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[pt]]></language>
    <lastBuildDate>Tue, 22 Sep 2026 02:58:38 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Mapeamento de embeddings para tipos de campo do Elasticsearch: semantic_text, dense_vector, sparse_vector]]></title>
    <description><![CDATA[Discutindo como e quando usar semantic_text, dense_vector ou sparse_vector, e como eles se relacionam com a geração de embeddings.]]></description>
    <content:encoded><![CDATA[<p>O uso de embeddings para melhorar a relevância e a precisão da recuperação de informações cresceu significativamente ao longo dos anos. Ferramentas como o Elasticsearch evoluíram para dar suporte a esse tipo de dados por meio de tipos de campos especializados, como vetores densos, vetores esparsos e texto semântico. No entanto, para obter bons resultados, é essencial entender como mapear corretamente os embeddings para os tipos de campo disponíveis no Elasticsearch: <code>semantic_text</code>, <code>dense_vector</code> e <code>sparse_vector</code>.</p><p>Neste artigo, discutiremos esses tipos de campos, quando usar cada um deles e como eles se relacionam com as estratégias de geração e uso de embeddings, tanto durante a indexação quanto na consulta.</p><h2>Tipo de vetor denso</h2><p>O tipo de campo <code>dense_vector</code> no Elasticsearch é usado para armazenar vetores densos, que são representações numéricas de dados como texto, imagens e áudio, onde quase todas as dimensões são relevantes. Esses vetores são gerados usando modelos de incorporação fornecidos por plataformas como OpenAI, Cohere ou Hugging Face, e são projetados para capturar o significado semântico geral dos dados, mesmo quando eles não compartilham termos exatos com outros documentos.</p><p>No Elasticsearch, vetores densos podem ter até 4096 dimensões, dependendo do modelo utilizado. Por exemplo, o modelo all-MiniLM-L6-v2 gera vetores com 384 dimensões, enquanto o text-embedding-ada-002 da OpenAI produz vetores com 1536 dimensões.</p><p>O campo <code>dense_vector</code> é geralmente adotado como o tipo padrão para armazenar esse tipo de incorporação quando é necessário maior controle, como usar vetores pré-gerados, aplicar funções de similaridade personalizadas ou integrar com modelos externos.</p><h3>Quando e por que usar o tipo dense_vector?</h3><p>Vetores densos são excelentes para capturar a similaridade semântica entre frases, parágrafos ou documentos inteiros. Funcionam muito bem quando o objetivo é comparar o significado geral dos textos, mesmo que não compartilhem os mesmos termos.</p><p>O campo vetorial denso é ideal quando você já possui um pipeline externo de geração de embeddings usando modelos fornecidos por plataformas como OpenAI, Cohere ou Hugging Face e deseja apenas armazenar e consultar esses vetores manualmente. Este tipo de campo oferece alta compatibilidade com modelos de incorporação e total flexibilidade na geração e consulta, permitindo controlar como os vetores são produzidos, indexados e usados durante a busca.</p><p>Além disso, oferece suporte a diferentes formas de busca semântica, com consultas como k-NN ou script_score para casos em que seja necessário ajustar a lógica de classificação. Essas possibilidades tornam o vetor denso ideal para aplicações como RAG (Retrieval-Augmented Generation), sistemas de recomendação e buscas personalizadas baseadas em similaridade.</p><p>Finalmente, o campo permite personalizar a lógica de relevância, usando funções como <code>cosineSimilarity</code>, <code>dotProduct</code> ou <code>l2norm</code> para adaptar a classificação de acordo com as necessidades do seu caso de uso. </p><p>Vetores densos continuam sendo a melhor opção para quem precisa de flexibilidade, personalização e compatibilidade com casos de uso avançados, como os mencionados acima.</p><h3>Como usar a consulta para o tipo vetor denso?</h3><p>As pesquisas em campos definidos como <strong><code>dense_vector</code></strong> usam a consulta dos k vizinhos mais próximos. Esta consulta é responsável por encontrar documentos cujo vetor denso seja o mais próximo do vetor de consulta. Abaixo, segue um exemplo de como aplicar uma consulta k-NN a um campo vetorial denso:</p>{
  "knn": {
    "field": "my_dense_vector",
    "k": 10,
    "num_candidates": 50,
    "query_vector": [/* vector generated by model */]
  }
}<p>Além da consulta k-NN, caso haja necessidade de personalizar a pontuação do documento, também é possível usar a consulta script_score, combinando-a com funções de comparação vetorial, como <strong>cossenosimilaridade, produto escalar ou norma l2,</strong> para calcular a relevância de forma mais controlada. Veja o exemplo:</p>{
"script_score": {
    "query": { "match_all": {} },
    "script": {
      "source": "cosineSimilarity(params.query_vector,
'my_dense_vector') + 1.0",
      "params": {
        "query_vector": [/* vector */]
      }
    }
  }
}<p>Se você quiser se aprofundar no assunto, recomendo explorar o artigo <a href="https://www.elastic.co/search-labs/blog/vector-search-set-up-elasticsearch">Como configurar a pesquisa vetorial no Elasticsearch.</a></p><p></p><h2>Tipo de vetor esparso</h2><p>O tipo de campo <strong><code>sparse_vector</code></strong> é usado para armazenar vetores esparsos, que são representações numéricas onde a maioria dos valores é zero e apenas alguns termos têm pesos significativos. Esse tipo de vetor é comum em modelos baseados em termos, como o SPLADE ou o ELSER (Elastic Learned Sparse EncodeR).</p><h3>Quando e por que usar vetores esparsos?</h3><p>Vetores esparsos são ideais quando você precisa de uma busca mais precisa em termos lexicais, sem sacrificar a inteligência semântica. Eles representam o texto como pares de token/valor, destacando apenas os termos mais relevantes com pesos associados, o que proporciona clareza, controle e eficiência.</p><p>Esse tipo de campo é especialmente útil quando você gera vetores com base em termos, como nos modelos ELSER ou SPLADE, que atribuem pesos diferentes a cada token com base em sua importância relativa no texto.</p><p>Para as ocasiões em que você deseja controlar a influência de palavras específicas na consulta, os tipos de vetores esparsos permitem ajustar manualmente o peso dos termos para otimizar a classificação dos resultados.</p><p>Entre os principais benefícios estão a transparência na busca, já que é possível entender claramente por que um documento foi considerado relevante, e a eficiência de armazenamento, pois apenas os tokens com valor diferente de zero são salvos, ao contrário dos vetores densos que armazenam todas as dimensões.</p><p>Além disso, vetores esparsos são o complemento ideal em estratégias de busca híbridas, podendo inclusive ser combinados com vetores densos para unir precisão lexical à compreensão semântica.</p><h3>Como usar a consulta para o tipo vetor esparso?</h3><p>A consulta <strong><code>sparse_vector</code></strong> permite pesquisar documentos com base em um vetor de consulta no formato token/valor. Veja um exemplo da consulta abaixo:</p>{
  "query": {
    "sparse_vector": {
      "field": "field_sparse",
      "query_vector": {
        "token1": 0.6,
        "token2": 0.2,
        "token3": 0.9
      }
    }
  }
}<p>Se preferir usar um modelo treinado, é possível utilizar um endpoint de inferência que transforma automaticamente o texto da consulta em um vetor esparso:</p>{
  "query": {
    "sparse_vector": {
      "field": "field_sparse",
      "inference_id": "the inference ID to produce the token/weights",
      "query": "search text"
    }
  }
}<p>Para explorar este tópico mais a fundo, sugiro a leitura de <a href="https://www.elastic.co/search-labs/blog/sparse-vector-embedding">Understanding sparse vector embeddings with trained ML models</a>.</p><h2>Tipo de texto semântico</h2><p>O tipo de campo <strong><code>semantic_text</code></strong> é a maneira mais simples e direta de usar a pesquisa semântica no Elasticsearch. Ele lida automaticamente com a geração de embeddings, tanto no momento da indexação quanto no momento da consulta, por meio de um endpoint de inferência. Isso significa que você não precisa se preocupar em gerar ou armazenar vetores manualmente.</p><h3>Quando e por que usar texto semântico?</h3><p>O campo <code>semantic_text</code> é ideal para quem quer começar com o mínimo de esforço técnico e sem ter que lidar com vetores manualmente. Este campo automatiza etapas como a geração de incorporações e o mapeamento de busca vetorial, tornando a configuração mais rápida e conveniente.</p><p>Você deve considerar usar <code>semantic_text</code> quando valoriza <strong>simplicidade e abstração</strong>, pois isso <strong>elimina a complexidade de configurar manualmente mapeamentos, geração de incorporações e pipelines de ingestão</strong>. Basta selecionar o modelo de inferência e o Elasticsearch cuida do resto.</p><p>As principais vantagens incluem <strong>a geração automática de embeddings,</strong> realizada durante a indexação e a consulta, e <strong>o mapeamento pronto para uso</strong>, que já vem pré-configurado para suportar o modelo de inferência selecionado.</p><p>Além disso, o campo oferece <strong>suporte nativo para a divisão automática de textos longos (fragmentação de texto)</strong>, permitindo que textos extensos sejam divididos em trechos menores, cada um com seu próprio embedding, o que melhora a precisão da busca. Isso aumenta consideravelmente a produtividade, especialmente para equipes que desejam entregar valor rapidamente sem se preocupar com a engenharia subjacente da busca semântica.</p><p>No entanto, embora <code>semantic_text</code> proporcione velocidade e simplicidade, esta abordagem tem algumas limitações. Permite a utilização de modelos padrão de mercado, desde que estejam disponíveis como endpoints de inferência no Elasticsearch. Mas <strong>não suporta incorporações geradas externamente</strong>, como é possível com o campo <code>dense_vector</code> .</p><p>Se você precisar de mais controle sobre como os vetores são gerados, quiser usar seus próprios embeddings ou precisar combinar vários campos para estratégias avançadas, os campos <code>dense_vector</code> e <code>sparse_vector</code> fornecem a flexibilidade necessária para cenários mais personalizados ou específicos do domínio.</p><h3>Como usar a consulta para o tipo de texto semântico</h3><p>Antes de <strong><code>semantic_text</code></strong>, era necessário usar uma consulta diferente dependendo do tipo de incorporação (densa ou esparsa). Uma consulta <code>sparse_vector</code> foi usada para campos esparsos, enquanto campos <code>dense_vector</code> exigiram consultas KNN.</p><p>Com o tipo de texto semântico, a busca é realizada utilizando a <a href="https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-semantic-query">consulta semântica</a>, que gera automaticamente o vetor de consulta e o compara com os embeddings dos documentos indexados. O tipo <strong><code>semantic_text</code></strong> permite definir um ponto de extremidade de inferência para incorporar a consulta, mas se nenhum for especificado, o mesmo ponto de extremidade usado durante a indexação será aplicado à consulta.</p>{
  "query": {
    "semantic": {
      "field": "semantic_text_field",
      "query": "search text"
    }
  }
}<p>Para saber mais, sugiro a leitura do artigo <a href="https://www.elastic.co/search-labs/blog/semantic-search-simplified-semantic-text">Elasticsearch new semantic_text mapping: Simplifying semantic search</a>.</p><h2>Conclusão</h2><p>Ao escolher como mapear embeddings no Elasticsearch, é essencial entender como você deseja gerar os vetores e qual o nível de controle necessário sobre eles. Se você busca simplicidade, o campo de texto semântico permite buscas semânticas automáticas e escaláveis, tornando-o ideal para muitos casos de uso iniciais. Quando é necessário maior controle, desempenho mais preciso ou integração com modelos personalizados, os campos vetoriais densos e esparsos oferecem a flexibilidade necessária.</p><p>O tipo de campo ideal depende do seu caso de uso, da infraestrutura disponível e do nível de maturidade da sua pilha de aprendizado de máquina. Mais importante ainda, a Elastic oferece as ferramentas para construir sistemas de busca modernos e altamente adaptáveis.</p><h2>Referências</h2><ul><li><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/semantic-text.html">Tipo de campo de texto semântico</a></p></li><li><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/sparse-vector.html">Tipo de campo vetorial esparso</a></p></li><li><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/dense-vector.html">Tipo de campo vetorial denso</a></p></li><li><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-semantic-query.html">Consulta semântica</a></p></li><li><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-sparse-vector-query.html">Consulta de vetor esparso</a></p></li><li><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/knn-search.html">pesquisa kNN</a></p></li><li><p><a href="https://www.elastic.co/search-labs/blog/semantic-search-simplified-semantic-text">Novo mapeamento semantic_text do Elasticsearch: Simplificando a busca semântica</a></p></li><li><p><a href="https://www.elastic.co/search-labs/blog/sparse-vector-embedding">Compreendendo incorporações vetoriais esparsas com modelos de aprendizado de máquina treinados</a></p></li></ul>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/mapping-embeddings-to-elasticsearch-field-types</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/mapping-embeddings-to-elasticsearch-field-types</guid>
    <category><![CDATA[Banco de dados vetorial]]></category>
    <category><![CDATA[Mapeamentos]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt72cd3c2601b22886/6a17083b0c4857259901a9dc/f98fdff837db55b466780c0bae672aa6f6c3a966-1200x628.png" length="0" type="image/png"/>
    <pubDate>Tue, 13 May 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Geração de filtros e facetas usando aprendizado de máquina.]]></title>
    <description><![CDATA[Explorando as vantagens e desvantagens de automatizar a criação de filtros e facetas em uma experiência de busca usando modelos de aprendizado de máquina versus a abordagem clássica de codificação fixa.]]></description>
    <content:encoded><![CDATA[<p>Filtros e facetas são mecanismos usados para refinar os resultados da pesquisa, ajudando os usuários a encontrar conteúdo ou produtos relevantes mais rapidamente. Na abordagem clássica, as regras são definidas manualmente. Por exemplo, em um catálogo de filmes, atributos como gênero são predefinidos para uso em filtros e facetas. Por outro lado, com modelos de IA, novos atributos podem ser extraídos automaticamente das características dos filmes, tornando o processo mais dinâmico e personalizado. Neste blog, exploramos as vantagens e desvantagens de cada método, destacando suas aplicações e desafios.</p><h2>Filtros vs facetas</h2><p>Antes de começarmos, vamos definir o que são filtros e facetas. <strong>Os filtros</strong> são atributos predefinidos usados para restringir um conjunto de resultados. Em um mercado online, por exemplo, os filtros estão disponíveis mesmo antes de uma busca ser realizada. O usuário pode selecionar uma categoria, como <strong>"Videogames"</strong>, antes de pesquisar por <strong>"PS5"</strong>, refinando a busca para um subconjunto mais específico em vez de toda a base de dados. Isso aumenta significativamente as chances de se obter resultados mais relevantes.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0a77b38aae238938/6a170b821949f72a52e7aa51/5ed8868fa5017d034e1273e35c884a5430afdf3c-1600x937.png" alt="Filtros" /><p><strong>Os facets</strong> funcionam de forma semelhante aos filtros, mas só ficam disponíveis após a realização da pesquisa. Em outras palavras, a pesquisa retorna resultados e, com base neles, é gerada uma nova lista de opções de refinamento. Por exemplo, ao pesquisar um console PS5, características como <strong>capacidade</strong> de armazenamento, <strong>custo de envio</strong> e <strong>cor</strong> podem ser exibidas para ajudar os usuários a escolher o produto ideal.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt166e356b80d423ef/6a170b840e2e494ca341a10f/c5633fcc5b6fbb916110faf32144d8d43572e33a-1600x937.png" alt="Facetas " /><p>Agora que definimos filtros e facetas, vamos discutir o impacto das abordagens clássicas e baseadas em Aprendizado de Máquina (ML) em sua implementação e uso. Cada método possui vantagens e desafios que influenciam a eficiência da busca.</p><h2>Abordagem clássica de filtros e facetas</h2><p>Nessa abordagem, os filtros e as facetas são definidos manualmente com base em regras predefinidas. Isso significa que os atributos disponíveis para refinar a busca são fixos e planejados antecipadamente, levando em consideração a estrutura do catálogo e as necessidades do usuário.</p><p>Por exemplo, em um marketplace, categorias como "Eletrônicos" ou "Moda" podem ter filtros específicos como marca, formato e faixa de preço. Essas regras são criadas estaticamente, garantindo consistência na experiência de busca, mas exigindo ajustes manuais sempre que novos produtos ou categorias surgirem.</p><p>Embora essa abordagem proporcione previsibilidade e controle sobre os filtros e facetas exibidos, ela pode ser limitada quando surgem novas tendências que exigem refinamento dinâmico.</p><p><strong>Prós:</strong></p><ul><li><p><strong>Previsibilidade e controle:</strong> Como os filtros e as facetas são definidos manualmente, o gerenciamento torna-se mais fácil.</p></li><li><p><strong>Baixa complexidade:</strong> Não há necessidade de treinar modelos.</p></li><li><p><strong>Facilidade de manutenção:</strong> Como as regras são predefinidas, ajustes e correções podem ser feitos rapidamente.</p></li></ul><p><strong>Contras</strong>:</p><ul><li><p><strong>Reindexação necessária para novos filtros:</strong> Sempre que um novo atributo precisar ser usado como filtro, todo o conjunto de dados deverá ser reindexado para garantir que os documentos contenham essa informação.</p></li><li><p><strong>Falta de adaptação dinâmica:</strong> os filtros são estáticos e não se ajustam automaticamente às mudanças no comportamento do usuário.</p></li></ul><h3>Implementação de filtros/facetas – Abordagem clássica</h3><p>Nas <strong>Ferramentas de Desenvolvimento, Kibana</strong>, criaremos uma demonstração de filtros/facetas usando a <strong>abordagem clássica</strong>.</p><p>Primeiro, definimos o mapeamento para estruturar o índice:</p>PUT videogames
{
  "mappings": {
    "properties": {
      "name": { "type": "text" },
      "brand": { "type": "keyword" },
      "storage": { "type": "keyword" },
      "price": { "type": "float" },
      "description": { "type": "text" }
    }
  }
}<p>Os campos <strong>de marca</strong> e <strong>armazenamento</strong> são definidos como <strong>palavras-chave</strong>, permitindo que sejam usados diretamente em agregações (<strong>facetas</strong>). O campo <strong>de preço</strong> é do tipo <strong>float</strong>, permitindo a criação de <strong>intervalos de preço</strong>.</p><p>Na próxima etapa, os dados do produto serão indexados:</p>POST videogames/_bulk
{ "index": { "_id": 1 } }
{ "name": "Play Station 5", "brand": "Sony", "storage": "1TB", "price": 499.99, "description": "Stunning Gaming: Marvel at stunning graphics and experience the features of the new PS5. Breathtaking Immersion: Discover a deeper gaming experience with support for haptic feedback, adaptive triggers, and 3D Audio technology. Slim Design: With the PS5 Digital Edition, gamers get powerful gaming technology in a sleek, compact design. 1TB of Storage: Have your favorite games ready and waiting for you to play with 1TB of built-in SSD storage. Backward Compatibility and Game Boost: The PS5 console can play over 4,000 PS4 games. With Game Boost, you can even enjoy faster, smoother frame rates in some of the best PS4 console games." }
{ "index": { "_id": 2 } }
{ "name": "Xbox Series X", "brand": "Microsoft", "storage": "1TB", "price": 499.99, "description": "Fastest, most powerful Xbox console ever. Play thousands of titles: Every game looks and plays better on Xbox Series X. At the heart of Series X is the Xbox Velocity. Architecture, which combines a custom SSD and built-in software to significantly reduce load times in and out of game. Switch between multiple games in an instant with Quick Resume. Explore new worlds and experience the action like never before with an unparalleled 12 teraflops of graphics processing power. Enjoy 4K gaming at up to 120 frames per second, premium advanced 3D sound, and more. 4K at 120 FPS: requires compatible content and display X version - with disc drive" }
{ "index": { "_id": 3 } }
{ "name": "Nintendo Switch", "brand": "Nintendo", "storage": "512GB", "price": 299.99, "description": "SHARPER, VIBRANT VISUALS. The new 7-inch screen on the Nintendo Switch OLED takes your gaming to the next level: vibrant colors with sharp contrasts for every moment. INTEGRATED GAMEPLAY. Enjoy the console's many multiplayer modes and connect with other players. Online or locally, the fun on the Nintendo Switch is guaranteed. ENJOY IMMERSION FOR LONGER. In addition to delivering an unparalleled experience, thanks to its improved audio, the Nintendo Switch has a rechargeable battery while you play. From 4.5 hours to 9 hours of battery life. INCLUDES SUPER MARIO BROS. WONDER. Transform your world with the phenomenal flowers in this new Mario game, full of amazing adventures, power-ups and new abilities. NINTENDO SWITCH ONLINE SUBSCRIPTION. Access online games, play with friends and enjoy the exclusive benefits of the Nintendo Switch Online subscription." }
{ "index": { "_id": 4 } }
{ "name": "Steam Deck", "brand": "Valve", "storage": "512GB", "price": 399.99, "description": "You can save games, apps, photos and videos without worrying about space. High-Level Performance: The 4-core processor and graphics ensure a dynamic experience and fast responses. High-Definition Images: Smooth transitions and sharp images provide complete immersion in the game. Wireless Connectivity: Wi-Fi technology allows you to play wherever you want, without wires or cables limiting your fun" }
{ "index": { "_id": 5 } }
{ "name": "Nintendo Switch Lite", "brand": "Nintendo", "storage": "512GB", "price": 299.99, "description": "MADE TO BE PORTABLE. Nintendo Switch Lite is designed specifically for portable gaming. The console lets you jump into your favorite games wherever you are. COMPACT AND LIGHTWEIGHT. With its sleek, lightweight design, this console is ready to hit the road wherever you are. COMPATIBLE GAMES. The Nintendo Switch Lite system plays the library of Nintendo Switch games that work in handheld mode. A WORLD OF COLOR TO CHOOSE FROM. Available in a variety of vibrant and unique colors, Nintendo Switch Lite lets you bring even more personality wherever you go." }<p>Agora, vamos recuperar as características clássicas agrupando os resultados por marca, armazenamento e faixa de preço. Na consulta, foi definido o tamanho:0. Nesse cenário, o objetivo é recuperar apenas os resultados da agregação, sem incluir os documentos correspondentes à consulta.</p>POST videogames/_search
{
  "size": 0,
  "aggs": {
    "brands": {
      "terms": { "field": "brand" }
    },
    "storage_sizes": {
      "terms": { "field": "storage" }
    },
    "price_ranges": {
      "range": {
        "field": "price",
        "ranges": [
          { "to": 300 },   
          { "from": 300, "to": 500 },  
          { "from": 500 }  
        ]
      }
    }
  }
}<p>A resposta incluirá contagens para <strong>Marca</strong>, <strong>Armazenamento</strong> e <strong>Preço</strong>, ajudando a criar filtros e segmentações.</p>"aggregations": {
   "brands": {
     "doc_count_error_upper_bound": 0,
     "sum_other_doc_count": 0,
     "buckets": [
       {
         "key": "Microsoft",
         "doc_count": 1
       },
       {
         "key": "Nintendo",
         "doc_count": 1
       },
       {
         "key": "Sony",
         "doc_count": 1
       },
       {
         "key": "Valve",
         "doc_count": 1
       }
     ]
   },
   "storage_sizes": {
     "doc_count_error_upper_bound": 0,
     "sum_other_doc_count": 0,
     "buckets": [
       {
         "key": "1TB",
         "doc_count": 2
       },
       {
         "key": "512GB",
         "doc_count": 2
       }
     ]
   },
   "price_ranges": {
     "buckets": [
       {
         "key": "*-300.0",
         "to": 300,
         "doc_count": 1
       },
       {
         "key": "300.0-500.0",
         "from": 300,
         "to": 500,
         "doc_count": 3
       },
       {
         "key": "500.0-*",
         "from": 500,
         "doc_count": 0
       }
     ]
   }
 }<h2>Abordagem baseada em machine learning/IA para filtros e facetas</h2><p>Nessa abordagem, modelos de Aprendizado de Máquina (ML), incluindo técnicas de Inteligência Artificial (IA), analisam atributos de dados para gerar filtros e facetas relevantes. Em vez de depender de regras predefinidas, o aprendizado de máquina/inteligência artificial aproveita as características dos dados indexados. Isso possibilita a descoberta dinâmica de novas facetas e filtros.</p><p><strong>Prós</strong>:</p><ul><li><p><strong>Atualizações automáticas:</strong> Novos filtros e facetas são gerados automaticamente, sem a necessidade de ajustes manuais.</p></li><li><p><strong>Descoberta de novos atributos:</strong> Pode identificar características de dados <strong>anteriormente não consideradas </strong>como filtros, enriquecendo a experiência de busca.</p></li><li><p><strong>Redução do esforço manual:</strong> a equipe não precisa definir e atualizar constantemente as regras de filtragem, pois a IA aprende com os dados disponíveis.</p></li></ul><p><strong>Contras:</strong></p><ul><li><p><strong>Complexidade de manutenção:</strong> O uso de modelos pode exigir pré-validação para garantir a consistência dos filtros gerados.</p></li><li><p><strong>Requer experiência em aprendizado de máquina e inteligência artificial:</strong> A solução exige profissionais qualificados para ajustar e monitorar o desempenho do modelo.</p></li><li><p><strong>Risco de filtros irrelevantes:</strong> Se o modelo não estiver bem calibrado, poderá gerar facetas que não sejam úteis para os usuários.</p></li><li><p><strong>Custo:</strong> O uso de aprendizado de máquina e inteligência artificial pode exigir serviços de terceiros, aumentando os custos operacionais.</p></li></ul><p>Vale ressaltar que, mesmo com um modelo bem calibrado e um prompt bem elaborado, as facetas geradas ainda devem passar por uma etapa de revisão. Essa validação pode ser manual ou baseada em regras de moderação, garantindo que o conteúdo seja apropriado e seguro. Embora não seja necessariamente uma desvantagem, é importante considerar a qualidade e a adequação dos recursos antes que sejam disponibilizados aos usuários.</p><h3>Implementação de filtros/facetas – abordagem de IA</h3><p>Nesta demonstração, utilizaremos um modelo de IA para analisar automaticamente as características do produto e sugerir atributos relevantes. Com um prompt bem estruturado, extraímos informações do catálogo e as transformamos em filtros e facetas. A seguir, apresentamos cada etapa do processo.</p><p>Inicialmente, usaremos a <strong>API de Inferência</strong> para registrar um endpoint para integração com um serviço de aprendizado de máquina. Abaixo, segue um exemplo de integração com <strong>o serviço da OpenAI</strong>.</p>PUT _inference/completion/generate_filter_ia
{
   "service": "openai",
   "service_settings": {
       "api_key": "your-key",
       "model_id": "gpt-4o-mini"
   }
}<p>Agora, definimos o pipeline para executar o prompt e obter os novos filtros gerados pelo modelo.</p>PUT /_ingest/pipeline/generate_filter_ai
{
   "processors": [
     {
       "script": {
         "source": """ctx.prompt = "You are an expert in data organization for search and product categorization. Your task is to analyze the following product and identify the best dynamic facets that can be used in an e-commerce search experience. Product: " + ctx.name + "description: " + ctx.description + "Instructions: - Analyze the product name and description. - Extract only the dynamic facets (technological features or product characteristics that can be inferred from the description, try to create max 3 facets by characteristics found). Put the values into an array. Using key and value, e.g. dynamic_facets: [{ \"name\": \"Gaming Experience\", \"value\": \"Haptic Feedback\" },{ \"name\": \"Gaming Experience\", \"value\": \"Adaptive Triggers\" } - Return only a JSON."
         """
       }
     },
     {
       "inference": {
         "model_id": "generate_filter_ia",
         "input_output": {
           "input_field": "prompt",
           "output_field": "result"
         }
       }
     },
     {
       "gsub": {
         "field": "result",
         "pattern": "```json",
         "replacement": ""
       }
     },
     {
       "json" : {
         "field" : "result",
         "strict_json_parsing": false,
         "add_to_root" : true
       }
     },
     {
       "remove": {
         "field": "result"
       }
     },
     {
       "remove": {
         "field": "prompt"
       }
     }
   ]
}<p>Executando uma simulação desse pipeline para o produto "PlayStation 5", com a seguinte descrição:</p><p><em>Jogabilidade impressionante: Maravilhe-se com gráficos deslumbrantes e experimente os recursos do novo PS5.</em></p><p><em>Imersão de tirar o fôlego: Descubra uma experiência de jogo mais profunda com suporte para feedback tátil, gatilhos adaptáveis e tecnologia de áudio 3D.</em></p><p><em>Design fino: Com o PS5 Digital Edition, os jogadores têm acesso a uma poderosa tecnologia de jogos em um design elegante e compacto.</em></p><p><em>1 TB de armazenamento: Tenha seus jogos favoritos prontos para jogar com 1 TB de armazenamento SSD integrado.</em></p><p><em>Compatibilidade com versões anteriores e Game Boost: O console PS5 pode rodar mais de 4.000 jogos de PS4. Com o Game Boost, você pode desfrutar de taxas de quadros mais rápidas e suaves até mesmo em alguns dos melhores jogos para PS4.</em></p><p>Vamos observar a saída de comando gerada por esta simulação.</p>{
 "docs": [
   {
     "doc": {
       "_index": "index",
       "_version": "-3",
       "_id": "1",
       "_source": {
         "name": "Play Station 5",
         "result": """```json
{
 "dynamic_facets": [
   { "name": "Storage Capacity", "value": "1TB SSD" },
   { "name": "Graphics Technology", "value": "Stunning Graphics" },
   { "name": "Audio Technology", "value": "3D Audio" }
 ]
}
```""",
         "description": "Stunning Gaming: Marvel at stunning graphics and experience the features of the new PS5. Breathtaking Immersion: Discover a deeper gaming experience with support for haptic feedback, adaptive triggers, and 3D Audio technology. Slim Design: With the PS5 Digital Edition, gamers get powerful gaming technology in a sleek, compact design. 1TB of Storage: Have your favorite games ready and waiting for you to play with 1TB of built-in SSD storage. Backward Compatibility and Game Boost: The PS5 console can play over 4,000 PS4 games. With Game Boost, you can even enjoy faster, smoother frame rates in some of the best PS4 console games.",
         "model_id": "generate_filter_ia",
         "prompt": """You are an expert in data organization for search and product categorization. Your task is to analyze the following product and identify the best dynamic facets that can be used in an e-commerce search experience. Product: Play Station 5description: Stunning Gaming: Marvel at stunning graphics and experience the features of the new PS5. Breathtaking Immersion: Discover a deeper gaming experience with support for haptic feedback, adaptive triggers, and 3D Audio technology. Slim Design: With the PS5 Digital Edition, gamers get powerful gaming technology in a sleek, compact design. 1TB of Storage: Have your favorite games ready and waiting for you to play with 1TB of built-in SSD storage. Backward Compatibility and Game Boost: The PS5 console can play over 4,000 PS4 games. With Game Boost, you can even enjoy faster, smoother frame rates in some of the best PS4 console games.Instructions: - Analyze the product name and description. - Extract only the dynamic facets (technological features or product characteristics that can be inferred from the description, try create max 3 facets by characteristics found). Put the values like arrays. Using key and value, e.g. dynamic_facets: [{ "name": "Gaming Experience", "value": "Haptic Feedback" },{ "name": "Gaming Experience", "value": "Adaptive Triggers" } - Return only a JSON."""
       },
       "_ingest": {
         "timestamp": "2025-03-19T22:14:32.0161803Z"
       }
     }
   }
 ]
}<p>Agora, um novo campo, <strong>dynamic_facets</strong>, será adicionado ao novo índice para armazenar as facetas geradas pela IA.</p>PUT videogames_1
{
 "mappings": {
   "properties": {
     "name": { "type": "text" },
     "brand": { "type": "keyword" },
     "storage": { "type": "keyword" },
     "price": { "type": "float" },
     "description": { "type": "text" },
     "dynamic_facets": { "type": "nested",
     "properties": { "name": { "type": "keyword" },
                     "value": { "type": "keyword" } } }
   }
 }
}<p>Utilizando a <strong>API Reindex</strong>, vamos reindexar o índice <strong>de videogames</strong> para <strong>videogames_1</strong>, aplicando o pipeline <strong>generate_filter_ai</strong> durante o processo. Este pipeline irá gerar automaticamente facetas dinâmicas durante a indexação.</p>POST _reindex?wait_for_completion=false
{
 "source": {
   "index": "videogames"
 },
 "dest": {
   "index": "videogames_1",
   "pipeline": "generate_filter_ai"
 }
}<p>Agora, vamos executar uma pesquisa e obter os novos filtros:</p>GET videogames_1/_search
{
 "size": 0,
 "query": {
   "match": {
     "name": "nintendo"
   }
 },
 "aggs": {
   "dynamic_facets": {
     "nested": {
       "path": "dynamic_facets"
     },
     "aggs": {
       "facets": {
         "terms": {
           "field": "dynamic_facets.name"
         },
         "aggs": {
           "facets": {
             "terms": {
               "field": "dynamic_facets.value"
             }
           }
         }
       }
     }
   }
 }
}<p>Resultados:</p>"aggregations": {
   "dynamic_facets": {
     "doc_count": 3,
     "facets": {
       "doc_count_error_upper_bound": 0,
       "sum_other_doc_count": 0,
       "buckets": [
         {
           "key": "Frame Rate",
           "doc_count": 1,
           "facets": {
             "doc_count_error_upper_bound": 0,
             "sum_other_doc_count": 0,
             "buckets": [
               {
                 "key": "120 FPS",
                 "doc_count": 1
               }
             ]
           }
         },
         {
           "key": "Gaming Resolution",
           "doc_count": 1,
           "facets": {
             "doc_count_error_upper_bound": 0,
             "sum_other_doc_count": 0,
             "buckets": [
               {
                 "key": "4K",
                 "doc_count": 1
               }
             ]
           }
         },
         {
           "key": "Graphics Processing Power",
           "doc_count": 1,
           "facets": {
             "doc_count_error_upper_bound": 0,
             "sum_other_doc_count": 0,
             "buckets": [
               {
                 "key": "12 Teraflops",
                 "doc_count": 1
               }
             ]
           }
         }
       ]
     }
   }
 }<p>Para simbolizar a implementação das facetas, segue abaixo um exemplo simples de interface:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb0d6aa40caf7a91a/6a170b86ab7f0839afdb9eb6/12b6d9d4f4d0985848d92841545fd22b7253ae6d-1600x1288.png" alt="implementação das facetas" /><p>O código da interface do usuário apresentado está <a href="https://gist.github.com/andreluiz1987/06d9ec1b381e942e9def0e969bd811a0">aqui</a>.</p><h2>Conclusão</h2><p>Ambas as abordagens para a criação de filtros e facetas têm seus benefícios e pontos de atenção. A abordagem clássica, baseada em regras manuais, oferece controle e custos mais baixos, mas requer atualizações constantes e não se adapta dinamicamente a novos produtos ou recursos.</p><p>Por outro lado, a abordagem baseada em IA e Aprendizado de Máquina automatiza a extração de facetas, tornando a busca mais flexível e permitindo a descoberta de novos atributos sem intervenção manual. No entanto, essa abordagem pode ser mais complexa de implementar e manter, exigindo calibração para garantir resultados consistentes.</p><p>A escolha entre as abordagens clássicas e as baseadas em IA depende das necessidades e da complexidade do negócio. Para cenários mais simples, onde os atributos dos dados são estáveis e previsíveis, a abordagem clássica pode ser mais eficiente e fácil de manter, evitando custos desnecessários com infraestrutura e modelos de IA. Por outro lado, o uso de aprendizado de máquina/inteligência artificial para extrair facetas pode agregar valor significativo, melhorando a experiência de busca e tornando a filtragem mais inteligente.</p><p>O importante é avaliar se a automação justifica o investimento ou se uma solução mais tradicional já atende às necessidades do negócio de forma eficaz.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/filters-facets-using-ml</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/filters-facets-using-ml</guid>
    <category><![CDATA[Relevância]]></category>
    <category><![CDATA[Pesquisa de aprendizado de máquina]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4084864dcdaa25d3/6a170b880c485781f901aaa9/6f196643d573614fe5124705c7e4db9bfce004b0-1200x628.png" length="0" type="image/png"/>
    <pubDate>Thu, 03 Apr 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Utilizando modelos do Amazon Nova no Elasticsearch]]></title>
    <description><![CDATA[Aprenda a usar os modelos Amazon Nova no Elasticsearch para extrair automaticamente sentimentos, autenticidade, resumos e palavras-chave das avaliações de produtos no Elasticsearch.]]></description>
    <content:encoded><![CDATA[<p>Neste artigo, discutiremos a família de modelos de IA da Amazon, o Amazon Nova, e aprenderemos como usá-lo em conjunto com o Elasticsearch.</p><h2>Sobre a Amazon Nova</h2><p>O Amazon Nova é uma família de modelos de inteligência artificial da Amazon, disponível na plataforma Amazon Bedrock e projetada para oferecer alto desempenho e custo-benefício. Esses modelos operam com entradas de texto, imagem e vídeo, geram saídas textuais e são otimizados para diferentes necessidades de precisão, velocidade e custo.</p><h3>Modelos principais do Amazon Nova</h3><ul><li><p>Amazon Nova Micro: Focado exclusivamente em texto, este é um modelo rápido e econômico, ideal para tradução, raciocínio, preenchimento automático de código e resolução de problemas matemáticos. Sua geração ultrapassa 200 tokens por segundo, tornando-o ideal para aplicações que exigem respostas instantâneas.</p></li><li><p>Amazon Nova Lite: modelo multimodal de baixo custo capaz de processar rapidamente imagens, vídeos e textos. Ele se destaca pela rapidez e precisão, sendo indicado para aplicações interativas e de alto volume onde o custo é um fator relevante.</p></li><li><p>Amazon Nova Pro: A opção mais avançada, que combina alta precisão, velocidade e custo-benefício. Ideal para tarefas complexas como resumo de vídeos, perguntas e respostas, desenvolvimento de software e agentes de IA. Avaliações de especialistas atestam sua excelência na compreensão textual e visual, bem como sua capacidade de seguir instruções e executar fluxos de trabalho automatizados.</p></li></ul><p>Os modelos Amazon Nova são adequados para uma variedade de aplicações, desde a criação de conteúdo e análise de dados até o desenvolvimento de software e a automação de processos com inteligência artificial.</p><p>A seguir, demonstraremos como usar os modelos do Amazon Nova em conjunto com o Elasticsearch para análise automatizada de avaliações de produtos.</p><p>O que faremos:</p><ol><li><p>Crie um endpoint por meio da API de Inferência, integrando o Amazon Bedrock com o Elasticsearch.</p></li><li><p>Crie um pipeline usando o Processador de Inferência, que fará chamadas para o endpoint da API de Inferência.</p></li><li><p>Indexe as avaliações de produtos e gere automaticamente uma análise dessas avaliações usando o pipeline.</p></li><li><p>Analise os resultados da integração.</p></li></ol><h2>Criando um endpoint na API de inferência com Amazon Nova Lite</h2><p>Primeiro, configuramos a API de Inferência para integrar o Amazon Bedrock com o Elasticsearch. Definimos o Amazon Nova Lite, id <strong>amazon.nova-lite-v1:0</strong>, como o modelo a ser utilizado, pois oferece um equilíbrio entre velocidade, precisão e custo.</p><p><strong>Observação:</strong> você precisará de credenciais válidas para usar o Amazon Bedrock. Você pode consultar a documentação para obter as chaves de acesso <a href="https://docs.aws.amazon.com/keyspaces/latest/devguide/create.keypair.html">aqui</a>:</p>PUT _inference/completion/bedrock_completion_amazon_nova-lite
{
   "service": "amazonbedrock",
   "service_settings": {
       "access_key": "#access_key#",
       "secret_key": "#secret_key#",
       "region": "us-east-1",
       "provider": "amazontitan",
       "model": "amazon.nova-lite-v1:0"
   }
}<h2>Criando o pipeline de análise de revisão</h2><p>Agora, criamos um pipeline de processamento que usará o Processador de Inferência para executar uma solicitação de análise de revisão. Este comando enviará os dados da avaliação para o Amazon Nova Lite, que executará as seguintes ações:</p><ul><li><p>Classificação do sentimento (positivo, negativo ou neutro).</p></li><li><p>Resumo da revisão.</p></li><li><p>Geração de palavras-chave.</p></li><li><p>Medição de autenticidade (autêntico | suspeito | genérico).</p></li></ul>PUT /_ingest/pipeline/review_analyzer_ai
{
      "processors": [
      {
        "script": 
            {
            "source": """ctx.prompt = "Analyze the following product review and return a structured JSON. Task: - Summarize the review concisely. - Detect and classify the sentiment as positive, neutral, or negative.- Generate relevant tags (keywords) based on the review content and detected sentiment. - Evaluate the authenticity of the review (authentic, suspicious, or generic). Review: " + ctx.review + " Respond in JSON format with the following fields: \"review_analyze\": {\"sentiment\": \"&lt;positive | neutral | negative&gt;\", \"authenticity\": \"&lt;authentic | suspicious | generic&gt;\",\"summary\": \"&lt;short review summary&gt;\", \"keywords\": [\"&lt;keyword 1&gt;\", \"&lt;keyword 2&gt;\", \"...\"]}}}"
            """
            }
      },
      {
        "inference": {
          "model_id": "bedrock_completion_amazon_nova-lite",
          "input_output": {
            "input_field": "prompt",
            "output_field": "result"
          }
        }
      },
      {
        "gsub": {
          "field": "result",
          "pattern": "```json",
          "replacement": ""
        } 
      },
      {
        "json" : {
          "field" : "result",
          "strict_json_parsing": false,
          "add_to_root" : true
        }
      },
      {
        "remove": {
          "field": "result"
        }
      },
      {
        "remove": {
          "field": "prompt"
        }
      }
    ]
}<h2>Avaliações de indexação</h2><p>Agora, indexamos avaliações de produtos usando a API em lote. O pipeline criado anteriormente será aplicado automaticamente, adicionando a análise gerada pelo modelo Nova aos documentos indexados.</p>POST bulk/
{ "index": { "_index" : "products", "_id": 1, "pipeline":"review_analyzer_ai" } }
{ "product": "Pampers Pants Premium Care Fralda", "review": "Best diaper ever! Great material, lots of cotton, without all that plastic. Doesn't leak! My baby is a boy and every diaper leaked around the waist, this model solved the problem. Even on a small baby it's worth the effort of putting on the short diaper. I put it on my baby at 9 pm and only take it off in the morning, without any leaks." }
{ "index": { "_index" : "products", "_id": 2, "pipeline":"review_analyzer_ai" } }
{ "product": "Portable Electric Body Massager", "review": "It broke in three months for no apparent reason, thank goodness I didn't review it before. I don't recommend buying it because it has a short lifespan." }
{ "index": { "_index" : "products", "_id": 3, "pipeline":"review_analyzer_ai" } }
{ "product": "Havit Fuxi-H3 Black Quad-Mode Wired and Wireless Gaming Headset", "review": "The sound is good for the price, but the connectivity is horrible. You always need to be playing audio, otherwise it loses connection (I work from home, and this is very annoying). Sometimes it loses connection and you have to turn it off and on again to get it back on. The microphone is very sensitive, so it loses connection frequently and you have to turn the headset off and on for the microphone to work again. The flexibility of the stem is useless, because if you move it, the microphone can turn off. Sometimes I need to use Linux and the headset simply doesn't work. It's light and comfortable, the sound is adequate, but the connectivity is terrible." }
{ "index": { "_index" : "products", "_id": 4, "pipeline":"review_analyzer_ai" } }
{ "product": "Air Fryer 4L Oil Free Fryer Mondial", "review": "For those looking for value for money, it's a good option, but the tray (which is underneath the perforated basket) is already peeling a lot. My mother has one just like it and said that hers is even rusting, in other words, the material is MUCH inferior. There's also something that bothers me, because it looks like a microwave, it doesn't fry evenly, it's weaker in the middle and stronger on the sides. Buy at your own risk." }<h2>Consultar e analisar os resultados</h2><p>Por fim, executamos uma consulta para ver como o modelo Amazon Nova Lite analisa e classifica as avaliações. Ao executar o comando GET products/_search, obtemos os documentos já enriquecidos com os campos gerados a partir do conteúdo da avaliação.</p><p>O modelo identifica o sentimento predominante (positivo, neutro ou negativo), gera resumos concisos, extrai palavras-chave relevantes e estima a autenticidade de cada avaliação. Esses campos ajudam a entender a opinião do cliente sem precisar ler o texto completo.</p><p>Para interpretar os resultados, analisamos:</p><ul><li><p>O sentimento indica a percepção geral do consumidor em relação ao produto.</p></li><li><p>O resumo destaca os principais pontos mencionados.</p></li><li><p>Palavras-chave, que podem ser usadas para agrupar avaliações semelhantes ou identificar padrões de feedback.</p></li><li><p>Autenticidade, que indica se a avaliação parece confiável. Isso é útil para curadoria ou moderação.</p></li></ul>   "hits": [
      {
        "_index": "products",
        "_id": "1",
        "_score": 1,
        "_ignored": [
          "review.keyword"
        ],
        "_source": {
          "product": "Pampers Pants Premium Care Fralda",
          "model_id": "bedrock_completion_amazon_nova-lite",
          "review_analyze": {
            "summary": "The reviewer praises the diaper for its great material, high cotton content, and leak-proof design, especially highlighting its effectiveness for their baby.",
            "sentiment": "positive",
            "keywords": [
              "best diaper",
              "great material",
              "cotton",
              "no plastic",
              "leak-proof",
              "baby",
              "effective"
            ],
            "authenticity": "authentic"
          },
          "review": "Best diaper ever! Great material, lots of cotton, without all that plastic. Doesn't leak! My baby is a boy and every diaper leaked around the waist, this model solved the problem. Even on a small baby it's worth the effort of putting on the short diaper. I put it on my baby at 9 pm and only take it off in the morning, without any leaks."
        }
      },
      {
        "_index": "products",
        "_id": "2",
        "_score": 1,
        "_source": {
          "product": "Portable Electric Body Massager",
          "model_id": "bedrock_completion_amazon_nova-lite",
          "review_analyze": {
            "summary": "The product broke in three months for no apparent reason and the reviewer does not recommend it due to its short lifespan.",
            "sentiment": "negative",
            "keywords": [
              "broke",
              "short lifespan",
              "not recommend"
            ],
            "authenticity": "authentic"
          },
          "review": "It broke in three months for no apparent reason, thank goodness I didn't review it before. I don't recommend buying it because it has a short lifespan."
        }
      },
      {
        "_index": "products",
        "_id": "3",
        "_score": 1,
        "_ignored": [
          "review.keyword"
        ],
        "_source": {
          "product": "Havit Fuxi-H3 Black Quad-Mode Wired and Wireless Gaming Headset",
          "model_id": "bedrock_completion_amazon_nova-lite",
          "review_analyze": {
            "summary": "The headset has good sound quality for the price but suffers from poor connectivity, especially when using the microphone or moving the headset. It also has compatibility issues with Linux.",
            "sentiment": "negative",
            "keywords": [
              "sound",
              "connectivity",
              "microphone",
              "compatibility",
              "annoying",
              "turn off and on",
              "Linux",
              "flexible stem",
              "work from home"
            ],
            "authenticity": "authentic"
          },
          "review": "The sound is good for the price, but the connectivity is horrible. You always need to be playing audio, otherwise it loses connection (I work from home, and this is very annoying). Sometimes it loses connection and you have to turn it off and on again to get it back on. The microphone is very sensitive, so it loses connection frequently and you have to turn the headset off and on for the microphone to work again. The flexibility of the stem is useless, because if you move it, the microphone can turn off. Sometimes I need to use Linux and the headset simply doesn't work. It's light and comfortable, the sound is adequate, but the connectivity is terrible."
        }
      },
      {
        "_index": "products",
        "_id": "4",
        "_score": 1,
        "_ignored": [
          "review.keyword"
        ],
        "_source": {
          "product": "Air Fryer 4L Oil Free Fryer Mondial",
          "model_id": "bedrock_completion_amazon_nova-lite",
          "review_analyze": {
            "summary": "The product offers value for money but has issues with peeling, rusting, and uneven frying.",
            "sentiment": "negative",
            "keywords": [
              "value for money",
              "peeling",
              "rusting",
              "uneven frying",
              "weaker in the middle"
            ],
            "authenticity": "authentic"
          },
          "review": "For those looking for value for money, it's a good option, but the tray (which is underneath the perforated basket) is already peeling a lot. My mother has one just like it and said that hers is even rusting, in other words, the material is MUCH inferior. There's also something that bothers me, because it looks like a microwave, it doesn't fry evenly, it's weaker in the middle and stronger on the sides. Buy at your own risk."
        }
      }
    ]<h2>Conclusão</h2><p>A integração entre o Amazon Nova Lite e o Elasticsearch demonstrou como os modelos de linguagem podem transformar avaliações brutas em informações estruturadas e valiosas. Ao processar as avaliações por meio de um pipeline, conseguimos extrair automaticamente e de forma consistente informações sobre sentimento, autenticidade, resumos e palavras-chave.</p><p>Os resultados mostram que o modelo consegue compreender o contexto das avaliações, classificar as opiniões dos usuários e destacar os pontos mais relevantes de cada experiência. Isso cria um conjunto de dados muito mais rico que pode ser aproveitado para melhorar as capacidades de pesquisa.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/amazon-nova-models-elasticsearch</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/amazon-nova-models-elasticsearch</guid>
    <category><![CDATA[AI]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdbbf13eb690294f1/6a17fddd6df73195190a115a/304713c48b568e17d0bb56b19edb28769f7801b3-721x420.jpg" length="0" type="image/jpeg"/>
    <pubDate>Wed, 02 Apr 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Como automatizar a busca e o upload de sinônimos usando nossa API de Sinônimos.]]></title>
    <description><![CDATA[Descubra como os LLMs podem ser usados para identificar e gerar sinônimos automaticamente, permitindo que os termos sejam carregados programaticamente na API de sinônimos do Elasticsearch.]]></description>
    <content:encoded><![CDATA[<p>Melhorar a qualidade dos resultados de pesquisa é essencial para proporcionar uma experiência de usuário eficiente. Uma forma de otimizar as buscas é expandindo automaticamente os termos pesquisados por meio de sinônimos. Isso permite que as consultas sejam interpretadas de forma mais abrangente, abrangendo variações de idioma e, assim, melhorando a correspondência dos resultados.</p><p>Este blog explora como grandes modelos de linguagem (LLMs) podem ser usados para identificar e gerar sinônimos automaticamente, permitindo que esses termos sejam carregados programaticamente na API de sinônimos do Elasticsearch.</p><h2>Quando usar sinônimos?</h2><p>O uso de sinônimos pode ser uma solução mais rápida e econômica em comparação com a busca vetorial. Sua implementação é mais simples, pois não requer conhecimento profundo de embeddings ou um processo complexo de ingestão de vetores.</p><p>Além disso, o consumo de recursos é menor, uma vez que a busca vetorial exige maior capacidade de armazenamento e memória para indexação e recuperação de dados.</p><p>Outro aspecto importante é a regionalização da busca. Com sinônimos, é possível adaptar os termos de acordo com o idioma e os costumes locais. Isso é útil em situações em que os embeddings podem não corresponder a expressões regionais ou termos específicos de cada país. Por exemplo, algumas palavras ou siglas podem ter significados diferentes dependendo da região, mas são naturalmente tratadas como sinônimos pelos usuários locais. No Brasil, isso é bastante comum. "Abacaxi" e "ananás" são a mesma fruta (abacaxi), mas o segundo termo é mais comumente usado em algumas regiões do Nordeste. Da mesma forma, o conhecido "pão francês" no Sudeste pode ser conhecido como "pão careca" no Nordeste.</p><h2>Como usar LLMs para gerar sinônimos?</h2><p>Para obter sinônimos automaticamente, podemos usar Modelos de Aprendizagem Baseados em Lógica (LLMs), que analisam o contexto de um termo e sugerem variações apropriadas. Essa abordagem permite a expansão dinâmica de sinônimos, garantindo uma busca mais ampla e precisa sem depender de um dicionário fixo.</p><p>Nesta demonstração, usaremos um modelo de linguagem natural (LLM) para gerar sinônimos para produtos de comércio eletrônico. Muitas pesquisas retornam poucos ou nenhum resultado devido a variações nos termos pesquisados. Com sinônimos, podemos resolver esse problema. Por exemplo, uma busca por "smartphone" pode abranger diferentes modelos de celulares, garantindo que os usuários encontrem os produtos que procuram.</p><h3>Pré-requisitos</h3><p>Antes de começarmos, precisamos configurar o ambiente e definir as dependências necessárias. Utilizaremos a solução fornecida pela Elastic para <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/run-elasticsearch-locally.html">executar o Elasticsearch e o Kibana localmente em um contêiner Docker</a>. O código será escrito em Python, versão 3.9.6, com as seguintes dependências:</p>pip install openai==1.59.8 elasticsearch==8.15.1<h3>Criando o índice de produtos</h3><p>Inicialmente, criaremos um índice de produtos sem suporte a sinônimos. Isso nos permitirá validar as consultas e compará-las com um índice que inclui sinônimos.</p><p>Para criar o índice, carregamos em massa um conjunto de dados de produtos usando o seguinte comando no Kibana DevTools:</p>POST _bulk
{"index": {"_index": "products", "_id": 10001}}
{"category": "Electronics", "name": "iPhone 14 Pro"}
{"index": {"_index": "products", "_id": 10007}}
{"category": "Electronics", "name": "MacBook Pro 16-inch"}
{"index": {"_index": "products", "_id": 10013}}
{"category": "Electronics", "name": "Samsung Galaxy Tab S8"}
{"index": {"_index": "products", "_id": 10037}}
{"category": "Electronics", "name": "Apple Watch Series 8"}
{"index": {"_index": "products", "_id": 10049}}
{"category": "Electronics", "name": "Kindle Paperwhite"}
{"index": {"_index": "products", "_id": 10067}}
{"category": "Electronics", "name": "Samsung QLED 4K TV"}
{"index": {"_index": "products", "_id": 10073}}
{"category": "Electronics", "name": "HP Spectre x360 Laptop"}
{"index": {"_index": "products", "_id": 10079}}
{"category": "Electronics", "name": "Apple AirPods Pro"}
{"index": {"_index": "products", "_id": 10115}}
{"category": "Electronics", "name": "Amazon Echo Show 10"}
{"index": {"_index": "products", "_id": 10121}}
{"category": "Electronics", "name": "Apple iPad Air"}
{"index": {"_index": "products", "_id": 10127}}
{"category": "Electronics", "name": "Apple AirPods Max"}
{"index": {"_index": "products", "_id": 10151}}
{"category": "Electronics", "name": "Sony WH-1000XM4 Headphones"}
{"index": {"_index": "products", "_id": 10157}}
{"category": "Electronics", "name": "Google Pixel 6 Pro"}
{"index": {"_index": "products", "_id": 10163}}
{"category": "Electronics", "name": "Apple MacBook Air"}
{"index": {"_index": "products", "_id": 10181}}
{"category": "Electronics", "name": "Google Pixelbook Go"}
{"index": {"_index": "products", "_id": 10187}}
{"category": "Electronics", "name": "Sonos Beam Soundbar"}
{"index": {"_index": "products", "_id": 10199}}
{"category": "Electronics", "name": "Apple TV 4K"}
{"index": {"_index": "products", "_id": 10205}}
{"category": "Electronics", "name": "Samsung Galaxy Watch 4"}
{"index": {"_index": "products", "_id": 10211}}
{"category": "Electronics", "name": "Apple MacBook Pro 16-inch"}
{"index": {"_index": "products", "_id": 10223}}
{"category": "Electronics", "name": "Amazon Echo Dot (4th Gen)"}<h3>Gerando sinônimos com LLM</h3><p>Nesta etapa, utilizaremos um modelo de lógica latente (LLM) para gerar sinônimos dinamicamente. Para atingir esse objetivo, integraremos a API da OpenAI, definindo um modelo e um prompt adequados. O LLM receberá a categoria e o nome do produto, garantindo que os sinônimos sejam contextualmente relevantes.</p>import json
import logging

from openai import OpenAI

def call_gpt(prompt, model):
    try:
        logging.info("generate synonyms by llm...")
        response = client.chat.completions.create(
            model=model,
            messages=[{"role": "user", "content": prompt}],
            temperature=0.7,
            max_tokens=1000
        )
        content = response.choices[0].message.content.strip()
        return content
    except Exception as e:
        logging.error(f"Failed to use model: {e}")
        return None

def generate_synonyms(category, products):
   synonyms = {}

   for product in products:
       prompt = f"You are an expert in generating synonyms for products. Based on the category and product name provided, generate synonyms or related terms. Follow these rules:\n"
       prompt += "1. **Format**: The first word should be the main item (part of the product name, excluding the brand), followed by up to 3 synonyms separated by commas.\n"
       prompt += "2. **Exclude the brand**: Do not include the brand name in the synonyms.\n"
       prompt += "3. **Maximum synonyms**: Generate a maximum of 3 synonyms per product.\n\n"
       prompt += f"The category is: **{category}**, and the product is: **{product}**. Return only the synonyms in the requested format, without additional explanations."

       response = call_gpt(prompt, "gpt-4o")
       synonyms[product] = response

   return synonyms<p>A partir do índice de produtos criado, recuperaremos todos os itens da categoria "Eletrônicos" e enviaremos seus nomes para o LLM. O resultado esperado será algo como:</p>{
  "iPhone 14 Pro": ["iPhone", "smartphone", "mobile", "handset"],
  "MacBook Pro 16-inch": ["MacBook", "Laptop", "Notebook", "Ultrabook"],
  "Samsung Galaxy Tab S8": ["Tab", "Tablet", "Slate", "Pad"],
  "Bose QuietComfort 35 Headphones": ["Headphones", "earphones", "earbuds", "headset"]
}<p>Com os sinônimos gerados, podemos registrá-los no Elasticsearch usando a API de Sinônimos.</p><h3>Gerenciando sinônimos com a API de Sinônimos</h3><p>A API de Sinônimos oferece uma maneira eficiente de gerenciar conjuntos de sinônimos diretamente dentro do sistema. Cada conjunto de sinônimos consiste em regras de sinonímia, onde um grupo de palavras é tratado como equivalente nas buscas.</p><p><strong>Exemplo de criação de um conjunto de sinônimos</strong></p>PUT _synonyms/my-synonyms-set
{
  "synonyms_set": [
    {
      "id": "rule-1",
      "synonyms": "hello, hi"
    },
    {
      "synonyms": "bye, goodbye"
    }
  ]
}<p>
Isso cria um conjunto chamado "meu-conjunto-de-sinônimos", onde "olá" e "oi" são tratados como equivalentes, assim como "tchau" e "adeus".</p><h2>Implementação da criação de sinônimos para o catálogo de produtos.</h2><p>A seguir, está o método responsável por construir um conjunto de sinônimos e inseri-lo no Elasticsearch. As regras de sinônimos são geradas com base no mapeamento de sinônimos sugerido pelo LLM. Cada regra possui um ID, correspondente ao nome do produto no formato slug, e a lista de sinônimos calculada pelo LLM.</p>import json
import logging

from elasticsearch import Elasticsearch
from slugify import slugify

es = Elasticsearch(
    "http://localhost:9200",
    api_key="your_api_key"
)

def mount_synonyms(results):
   synonyms_set = [{"id": slugify(product), "synonyms": synonyms} for product, synonyms in
                   results.items()]

   try:
       response = es.synonyms.put_synonym(id="products-synonyms-set",
                                                 synonyms_set=synonyms_set)

       logging.info(json.dumps(response.body, indent=4))
       return response.body
   except Exception as e:
       logging.error(f"Error create synonyms: {str(e)}")
       return None<p>A seguir, está a carga útil da solicitação para criar o conjunto de sinônimos:</p>{
   "synonyms_set":[
      {
         "id": "iphone-14-pro",
         "synonyms": "iPhone, smartphone, mobile, handset"
      },
      {
         "id": "macbook-pro-16-inch",
         "synonyms": "MacBook, Laptop, Notebook, Computer"
      },
      {
         "id": "samsung-galaxy-tab-s8",
         "synonyms": "Tablet, Slate, Pad, Device"
      },
      {
         "id": "garmin-forerunner-945",
         "synonyms": "Forerunner, smartwatch, fitness watch, GPS watch"
      },
      {
         "id": "bose-quietcomfort-35-headphones",
         "synonyms": "Headphones, Earphones, Headset, Cans"
      }
   ]
}<p>Com o conjunto de sinônimos criado no cluster, podemos prosseguir para a próxima etapa, que é a criação de um novo índice com suporte a sinônimos usando o conjunto definido.</p><p>O código Python completo, com os sinônimos gerados pelo LLM e a criação do conjunto de sinônimos definida pela API de Sinônimos, encontra-se abaixo:</p>import json
import logging

from elasticsearch import Elasticsearch
from openai import OpenAI
from slugify import slugify

logging.basicConfig(level=logging.INFO)

client = OpenAI(
   api_key="your-key",
)

es = Elasticsearch(
    "http://localhost:9200",
    api_key="your_api_key"
)


def call_gpt(prompt, model):
   try:
       logging.info("generate synonyms by llm...")
       response = client.chat.completions.create(
           model=model,
           messages=[{"role": "user", "content": prompt}],
           temperature=0.7,
           max_tokens=1000
       )
       content = response.choices[0].message.content.strip()
       return content
   except Exception as e:
       logging.error(f"Failed to use model: {e}")
       return None


def generate_synonyms(category, products):
   synonyms = {}

   for product in products:
       prompt = f"You are an expert in generating synonyms for products. Based on the category and product name provided, generate synonyms or related terms. Follow these rules:\n"
       prompt += "1. **Format**: The first word should be the main item (part of the product name, excluding the brand), followed by up to 3 synonyms separated by commas.\n"
       prompt += "2. **Exclude the brand**: Do not include the brand name in the synonyms.\n"
       prompt += "3. **Maximum synonyms**: Generate a maximum of 3 synonyms per product.\n\n"
       prompt += f"The category is: **{category}**, and the product is: **{product}**. Return only the synonyms in the requested format, without additional explanations."

       response = call_gpt(prompt, "gpt-4o")
       synonyms[product] = response

   return synonyms


def get_products(category):
   query = {
       "size": 50,
       "_source": ["name"],
       "query": {
           "bool": {
               "filter": [
                   {
                       "term": {
                           "category.keyword": category
                       }
                   }
               ]
           }
       }
   }
   response = es.search(index="products", body=query)

   if response["hits"]["total"]["value"] &gt; 0:
       product_names = [hit["_source"]["name"] for hit in response["hits"]["hits"]]
       return product_names
   else:
       return []


def mount_synonyms(results):
   synonyms_set = [{"id": slugify(product), "synonyms": synonyms} for product, synonyms in
                   results.items()]

   try:
       es_client = get_client_es()
       response = es_client.synonyms.put_synonym(id="products-synonyms-set",
                                                 synonyms_set=synonyms_set)

       logging.info(json.dumps(response.body, indent=4))
       return response.body
   except Exception as e:
       logging.error(f"Erro update synonyms: {str(e)}")
       return None


if __name__ == '__main__':
   category = "Electronics"
   products = get_products("Electronics")
   llm_synonyms = generate_synonyms(category, products)
   mount_synonyms(llm_synonyms)<h3>Criando um índice com suporte a sinônimos</h3><p>Um novo índice será criado onde todos os dados do índice <code>products</code> serão reindexados. Este índice usará o <code>synonyms_filter</code>, que aplica o <code>products-synonyms-set</code> criado anteriormente.</p><p>A seguir, o mapeamento de índice configurado para usar sinônimos:</p>PUT products_02
{
  "settings": {
    "analysis": {
      "filter": {
        "synonyms_filter": {
          "type": "synonym",
          "synonyms_set": "products-synonyms-set",
          "updateable": true
        }
      },
      "analyzer": {
        "synonyms_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "synonyms_filter"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "ID": {
        "type": "long"
      },
      "category": {
        "type": "keyword"
      },
      "name": {
        "type": "text",
        "analyzer": "standard",
        "search_analyzer": "synonyms_analyzer"
      }
    }
  }
}<h3>Reindexando o índice <code>products</code></h3><p>Agora, usaremos a <strong>API Reindex</strong> para migrar os dados do índice <code>products</code> para o novo índice <code>products_02</code> , que inclui suporte a sinônimos. O seguinte código foi executado no Kibana DevTools:
</p>POST _reindex
{
  "source": {
    "index": "products"
  },
  "dest": {
    "index": "products_02"
  }
}<p>Após a migração, o índice <code>products_02</code> será preenchido e estará pronto para validar pesquisas usando o conjunto de sinônimos configurado.</p><h3>Validação da pesquisa com sinônimos</h3><p>Vamos comparar os resultados da pesquisa entre os dois índices. Executaremos a mesma consulta em ambos os índices e validaremos se os sinônimos estão sendo usados para recuperar os resultados.</p><h4>Pesquisar no índice <code>products</code> (sem sinônimos)</h4><p>Usaremos o Kibana para realizar buscas e analisar os resultados. No menu Analytics &gt; Discovery, criaremos uma visualização de dados para visualizar os dados dos índices que criamos.</p><p>Dentro do Discovery, clique em Visualização de Dados e defina um nome e um padrão de índice. Para o índice "<strong>produtos</strong>", usaremos o padrão "<strong>produtos</strong> ". Em seguida, repetiremos o processo para criar uma nova visualização de dados para o índice "<strong>products_02</strong>", usando o padrão "<strong>products_02"</strong> .</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte826fd932cfeb9df/6a17fdffec0f8912aa5a6841/3ad4a6891a3905e96532a312932fdf3a8216aec2-1600x599.png" alt="" /><p>Com as visualizações de dados configuradas, podemos retornar a Analytics &gt; Discovery e iniciar as validações.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltba3729c60068e8a0/6a17fe01e9ea87ba2aa9c82a/422c4b2b51abae6580cad25085d1b8a365fc6b9e-1294x850.png" alt="" /><p>Aqui, após selecionar os produtos DataView e pesquisar pelo termo "tablet", não obtemos resultados, embora saibamos que existem produtos como "Kindle Paperwhite" e "Apple iPad Air".</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2c6a383dd4cb0157/6a17fe02577262671d1bce0c/e4ae3a785fdd93f48d7c7d204185ded149126f2c-1600x862.png" alt="" /><h4>Pesquisar no índice <code>products_02</code> (suporta sinônimos)</h4><p>Ao executar a mesma consulta na visualização de dados "<strong>products_synonyms</strong>", que suporta sinônimos, os produtos foram recuperados com sucesso. Isso demonstra que o conjunto de sinônimos configurado está funcionando corretamente, garantindo que diferentes variações dos termos pesquisados retornem os resultados esperados.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt986b4706e2f70014/6a17fe043e9e454edbba16d3/e609749c39e90d5c82fa846af6124679dd62bcb8-1600x526.png" alt="" /><p>Podemos obter o mesmo resultado executando a mesma consulta diretamente no Kibana DevTools. Basta pesquisar o índice products_02 usando a API de pesquisa do Elasticsearch:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltbe829a3c4d7aac60/6a17fe05e8fbce03d73a1bd7/504d0d1f96dcfbceb309063dc0716bcee64ad2f8-1600x870.png" alt="" /><h2>Conclusão</h2><p>A implementação de sinônimos no Elasticsearch melhorou a precisão e a abrangência das buscas no catálogo de produtos. O principal diferencial foi o uso de um <strong>LLM (</strong> Language-Level Model), que gerou sinônimos automaticamente e contextualmente, eliminando a necessidade de listas predefinidas. O modelo analisou nomes e categorias de produtos, garantindo sinônimos relevantes para o comércio eletrônico.</p><p>Além disso, a <strong>API de Sinônimos</strong> simplificou o gerenciamento de dicionários, permitindo que os conjuntos de sinônimos fossem modificados dinamicamente. Com essa abordagem, a busca tornou-se mais flexível e adaptável a diferentes padrões de consulta do usuário.</p><p>Esse processo pode ser continuamente aprimorado com novos dados e ajustes de modelo, garantindo uma experiência de pesquisa cada vez mais eficiente.</p><h2>Referências</h2><p><strong>Executar o Elasticsearch localmente</strong></p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/run-elasticsearch-locally.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/run-elasticsearch-locally.html</a></p><p><strong>API de sinônimos</strong></p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/synonyms-apis.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/synonyms-apis.html</a></p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elasticsearch-synonyms-automate</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elasticsearch-synonyms-automate</guid>
    <category><![CDATA[Relevância]]></category>
    <category><![CDATA[Noções básicas]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0f0247b9bc1d1ccd/6a17fe07ec0f891c745a6845/05a3cfeaa387561d5334ca3f1609035ddfff7481-1200x628.png" length="0" type="image/png"/>
    <pubDate>Thu, 27 Mar 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[Busca facetada: Use IA para aprimorar o escopo e os resultados da busca.]]></title>
    <description><![CDATA[Descubra como usar a pesquisa facetada no Elasticsearch para refinar rapidamente as opções dentro de categorias.]]></description>
    <content:encoded><![CDATA[<p>Neste artigo, exploraremos como a Inteligência Artificial (IA), especificamente utilizando modelos de linguagem avançados como o GPT-4, pode ajudar a criar facetas mais contextuais, tornando-as ainda mais relevantes e úteis para os usuários.</p><p>A busca facetada é uma ferramenta poderosa em plataformas de comércio eletrônico. Isso ajuda a organizar e refinar os resultados da pesquisa com base nas características dos itens exibidos. Embora frequentemente confundidos com filtros, os facets funcionam de maneira diferente. Os filtros são atributos fixos, definidos por informações sempre presentes no índice, como a categoria ou o formato de um produto. As facetas, por outro lado, são dinâmicas e geradas a partir dos resultados retornados pela pesquisa executada.</p><p>Imagine um catálogo de roupas: campos como "categoria" (por exemplo, camisetas, calças) ou "gênero" (por exemplo, masculino, feminino) são filtros que ajudam a refinar os resultados. As facetas, no entanto, refletem características específicas dos produtos que aparecem nos resultados, como cores comuns, tamanhos disponíveis ou materiais. Isso permite uma experiência de busca mais adaptável e contextual.</p><p>Abaixo, você encontrará uma imagem onde interagimos com uma faceta e podemos ver os resultados da pesquisa filtrados por ela.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc4ce8ca7e5b62ad7/6a17f8ba6864a4534bb68979/74d2159706ab7248ebe5efddc74c882f0693db71-600x420.gif" alt="Exemplo de pesquisa facetada" /><h2>Como a IA pode aprimorar a geração de facetas</h2><p>A Inteligência Artificial é frequentemente associada à busca semântica e aos embeddings, mas e quanto às facetas? Como a IA pode ser utilizada para tornar os filtros mais úteis e específicos ao contexto de cada pesquisa?</p><p>Uma possibilidade intrigante é usar IA para criar novas categorizações que vão além das classificações tradicionais do índice. Ao analisar características específicas do conteúdo, essas novas categorias podem fornecer uma contextualização mais rica e precisa, tornando os aspectos mais relevantes e alinhados às necessidades dos usuários. Isso possibilita um refinamento mais significativo dos resultados em comparação com as categorias de documentos originais.</p><h2>Como a IA pode refinar as classificações de filmes para melhores buscas</h2><p>Vamos analisar os seguintes filmes, todos atualmente classificados no gênero Drama:</p><ul><li><p>Réquiem para um Sonho
 Resumo: As utopias induzidas por drogas de quatro pessoas de Coney Island são destruídas quando seus vícios se tornam profundos.</p></li><li><p>Beleza Americana
 Resumo: Um pai suburbano sexualmente frustrado entra em crise de meia-idade após se apaixonar pela melhor amiga de sua filha.</p></li><li><p>Good Will Hunting
 Resumo: Will Hunting, um zelador do MIT, tem um talento especial para matemática, mas precisa da ajuda de um psicólogo para encontrar um rumo na vida.</p></li></ul><p>Essa classificação por gênero não capta as diferenças sutis ou os contextos únicos de cada filme. Ao utilizar inteligência artificial para analisar sinopses e temas centrais, podemos criar novas categorias que reflitam melhor o verdadeiro contexto de cada filme. Por exemplo:</p><ul><li><p>Réquiem para um Sonho - Nova categoria: "Vício e Dependência"</p></li><li><p>Beleza Americana - Nova Categoria: "Crise da Meia-Idade"</p></li><li><p>Gênio Indomável - Nova categoria: "Luta Intelectual"</p></li></ul><p>Essas novas categorias tornam as buscas muito mais precisas, ao mesmo tempo que oferecem aos usuários filtros mais relevantes para refinar seus resultados. Essa abordagem é particularmente eficaz quando as categorias originais são muito genéricas, permitindo que os usuários encontrem exatamente o que procuram com maior facilidade.</p><h2>Criando novas categorias com GPT-4: Exemplo de busca facetada</h2><p>Neste exemplo, mostraremos como um modelo de IA pode ser usado para criar novas categorias de filmes que sejam mais precisas e alinhadas ao contexto de cada obra. Para demonstrar esse processo, utilizaremos o pipeline de simulação da Elastic juntamente com o serviço de inferência da OpenAI. Será criado um pipeline com vários processadores, incluindo o Processador de Scripts, que será responsável por criar o prompt a ser executado no Processador de Inferência, capaz de determinar as novas categorias. Os demais processadores serão utilizados para manipular os dados e os campos auxiliares gerados durante a execução do pipeline. Vale ressaltar que essa lógica também pode ser aplicada a outras ferramentas ou modelos semelhantes.</p><p>Primeiro, precisamos criar o endpoint de inferência, onde definimos o serviço como OpenAI, o token necessário para acessar o serviço e o modelo. Neste exemplo, estou usando gpt-4o-mini. Para obter mais detalhes sobre o serviço de inferência da OpenAI, clique <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/infer-service-openai.html">aqui</a>.</p>PUT _inference/completion/generate_topics_ia
{
    "service": "openai",
    "service_settings": {
        "api_key": "your-token",
        "model_id": "gpt-4o-mini"
    }
}<p>Com o endpoint criado, agora estamos prontos para usá-lo para criar as novas categorias. A seguir, apresentamos um fluxo de trabalho que gerencia todo o processo de manipulação de dados de documentos e geração de prompts. Explicarei detalhadamente a função de cada processador.</p><p>O primeiro processador será responsável por construir o prompt. É muito importante detalhar claramente as instruções para que a IA possa analisar e identificar os tópicos corretamente. Neste pedido, solicito dois tópicos com base na análise do título, da descrição e dos gêneros dos filmes.</p>{
        "script": {
          "source": """
            ctx.prompt = "You are an expert in semantic analysis and audiovisual content categorization. Your task is to generate only subcategories (max 2 topics) that describe specific aspects of movies based on their genres and descriptions. The output should be like: 'n1, n2, ...n'. Here is a movie info to analyze: Title: " + ctx.title  + "Genres: " + ctx.genres  + "Description: " + ctx.description;
          """
        }<p>O próximo pipeline é o pipeline de inferência, que receberá a solicitação e a enviará para o nosso endpoint <strong>generate_topics_ia</strong> . A resposta gerada pelo modelo será armazenada no campo de resultado.</p>{
        "inference": {
          "model_id": "generate_topics_ia",
          "input_output": {
            "input_field": "prompt",
            "output_field": "result"
          }
        }
      }<p>Em seguida, temos 3 processadores usados para manipular a resposta e defini-la no campo de tópicos, além de remover os campos temporários que eu criei.</p><p>Ao executar esse pipeline, obteremos os seguintes resultados:</p>{
  "docs": [
    {
      "doc": {
        "_index": "index",
        "_version": "-3",
        "_id": "1",
        "_source": {
          "description": "While Frodo and Sam edge closer to Mordor with the help of the shifty Gollum, the divided fellowship makes a stand against Sauron's new ally, Saruman, and his hordes of Isengard.",
          "model_id": "generate_topics_ia",
          "title": "The Lord of the Rings: The Fellowship of the Ring",
          "genres": [
            "Action",
            "Adventure",
            "Drama"
          ],
          "topics": [
            "Fantasy",
            "Quest"
          ]
        },
        "_ingest": {
          "timestamp": "2024-11-22T17:51:51.340010257Z"
        }
      }
    },
    {
      "doc": {
        "_index": "index",
        "_version": "-3",
        "_id": "2",
        "_source": {
          "description": "A team of explorers travel through a wormhole in space in an attempt to ensure humanity's survival.",
          "model_id": "generate_topics_ia",
          "title": "Interstellar",
          "genres": [
            "Adventure",
            "Drama",
            "Sci-Fi"
          ],
          "topics": [
            "space exploration",
            "human survival"
          ]
        },
        "_ingest": {
          "timestamp": "2024-11-22T17:51:51.340413173Z"
        }
      }
    },
    {
      "doc": {
        "_index": "index",
        "_version": "-3",
        "_id": "3",
        "_source": {
          "description": "An astronaut becomes stranded on Mars after his team assume him dead, and must rely on his ingenuity to find a way to signal to Earth that he is alive.",
          "model_id": "generate_topics_ia",
          "title": "The Martian",
          "genres": [
            "Adventure",
            "Drama",
            "Sci-Fi"
          ],
          "topics": [
            "survival",
            "ingenuity"
          ]
        },
        "_ingest": {
          "timestamp": "2024-11-22T17:51:51.340427965Z"
        }
      }
    }
  ]
}<p>Note que temos novas categorias que estão mais relacionadas ao contexto dos filmes, embora algumas sejam inicialmente do mesmo gênero.</p><p>Agora podemos usar essas novas categorias e indexá-las juntamente com o documento. Dessa forma, ao gerar as facetas, além da categoria primária, temos subcategorias mais específicas que estão alinhadas com o contexto dos filmes.</p><p>Além disso, é possível vetorizar essas novas categorias e usá-las em buscas vetoriais. Isso significa que as novas categorias não servem apenas como filtros, mas também podem ser usadas para calcular similaridades semânticas com os termos de busca, aumentando ainda mais a relevância dos resultados apresentados.</p><p>Pipeline completo:</p>POST /_ingest/pipeline/_simulate
{
  "pipeline": {
    "processors": [
      {
        "script": {
          "source": """
            ctx.prompt = "You are an expert in semantic analysis and audiovisual content categorization. Your task is to generate only subcategories (max 2 topics) that describe specific aspects of movies based on their genres and descriptions. The output should be like string: 'n1, n2m ...n'. Here is a movies info to analyze: Title: " + ctx.title  + "Genres: " + ctx.genres  + "Description: " + ctx.description;
          """
        }
      },
      {
        "inference": {
          "model_id": "generate_topics_ia",
          "input_output": {
            "input_field": "prompt",
            "output_field": "result"
          }
        }
      },
      {
        "split": {
          "field": "result",
          "target_field": "topics",
          "separator": ", "
        }
      },
      {
        "remove": {
          "field": "result"
        }
      },
      {
        "remove": {
          "field": "prompt"
        }
      }
    ]
  },
  "docs": [
    {
      "_index": "index",
      "_id": "1",
      "_source": {
        "title": "The Lord of the Rings: The Fellowship of the Ring",
        "description": "While Frodo and Sam edge closer to Mordor with the help of the shifty Gollum, the divided fellowship makes a stand against Sauron's new ally, Saruman, and his hordes of Isengard.",
        "genres": [
          "Action",
          "Adventure",
          "Drama"
        ]
      }
    },
    {
      "_index": "index",
      "_id": "2",
      "_source": {
        "title": "Interstellar",
        "description": "A team of explorers travel through a wormhole in space in an attempt to ensure humanity's survival.",
        "genres": [
          "Adventure", "Drama", "Sci-Fi"
        ]
      }
    },
    {
      "_index": "index",
      "_id": "3",
      "_source": {
        "title": "The Martian",
        "description": "An astronaut becomes stranded on Mars after his team assume him dead, and must rely on his ingenuity to find a way to signal to Earth that he is alive.",
        "genres": [
          "Adventure", "Drama", "Sci-Fi"
        ]
      }
    }
  ]
}<h2>Conclusão</h2><p>O uso de IA para aprimorar os filtros pode transformar a experiência de busca, tornando os resultados mais específicos e contextuais. Ao contrário das categorias fixas, que costumam ser amplas, as categorias geradas por IA podem refletir melhor o contexto. Por exemplo, ao reclassificar filmes, podemos capturar o contexto que as categorias primárias não abrangem, fornecendo agrupamentos muito mais relevantes.</p><p>Essas novas categorias podem ser adicionadas ao índice não apenas para aprimorar a filtragem por facetas, mas também para possibilitar buscas vetoriais. O resultado é uma experiência de busca mais eficiente, com filtros mais adequados ao contexto.</p><h2>Referências</h2><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/infer-service-openai.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/infer-service-openai.html</a></p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/simulate-pipeline-api.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/simulate-pipeline-api.html</a></p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/script-processor.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/script-processor.html</a></p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/faceted-search-examples-ai</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/faceted-search-examples-ai</guid>
    <category><![CDATA[AI]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd2838185214162c8/6a17f8bedbb4ff04affb58a5/25c9f9baa2326b5189ce0b1cc6240475781c755d-721x421.jpg" length="0" type="image/jpeg"/>
    <pubDate>Tue, 28 Jan 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 usar a busca híbrida em um catálogo de produtos de e-commerce]]></title>
    <description><![CDATA[Aprenda a usar a busca híbrida para criar um catálogo de produtos de e-commerce, utilizando filtros, promoções, personalização e análise comportamental.]]></description>
    <content:encoded><![CDATA[<p>Neste artigo, demonstraremos como implementar uma busca híbrida que combina os resultados da busca de texto completo com a busca vetorial. Ao unificar essas duas abordagens, a busca híbrida melhora a abrangência dos resultados, aproveitando o melhor de ambas as estratégias de busca.</p><p>Além de integrar a busca híbrida, demonstraremos como adicionar recursos que tornarão sua solução de busca ainda mais robusta. Isso inclui segmentação por facetas e promoções de produtos personalizadas. Além disso, mostraremos como capturar interações do usuário e gerar insights valiosos usando a ferramenta de Análise Comportamental da Elastic.</p><p>Nesta implementação, você verá como construir tanto a interface que permite aos usuários visualizar e interagir com os resultados da pesquisa quanto a API responsável por retornar as informações. Para acessar os repositórios com o código-fonte, os links são fornecidos abaixo:</p><ul><li><p><a href="https://github.com/elastic/elasticsearch-labs/tree/main/supporting-blog-content/hybrid-search-for-an-e-commerce-product-catalogue/product-store-search">https://github.com/elastic/elasticsearch-labs/tree/main/supporting-blog-content/hybrid-search-for-an-e-commerce-product-catalogue/product-store-search</a></p></li><li><p><a href="https://github.com/elastic/elasticsearch-labs/tree/main/supporting-blog-content/hybrid-search-for-an-e-commerce-product-catalogue/app-product-store">https://github.com/elastic/elasticsearch-labs/tree/main/supporting-blog-content/hybrid-search-for-an-e-commerce-product-catalogue/app-product-store</a> </p></li></ul><p>Dividimos este guia em várias etapas, desde a criação do índice até a implementação de recursos avançados, como facetas e personalização de resultados. Ao final, você terá uma solução de busca robusta, pronta para ser usada em um cenário de comércio eletrônico.</p><h2>Configuração do ambiente para pesquisa híbrida de comércio eletrônico</h2><p>Antes de iniciarmos a implementação, precisamos configurar o ambiente. Você pode optar por usar um serviço na Elastic Cloud ou uma solução em contêineres para gerenciar o Elasticsearch. Se você optar pela conteinerização, uma configuração via Docker Compose pode ser encontrada neste repositório: <a href="https://github.com/andreluiz1987/product-store-search/blob/main/docker/docker-compose.yml">docker-compose.yml</a>.</p><h2>Criação de índice e ingestão de catálogo de produtos</h2><p>O índice será criado com base em um catálogo de produtos cosméticos, que inclui campos como nome, descrição, foto, categoria e etiquetas. Os campos usados para pesquisa de texto completo, como "nome" e "descrição", serão mapeados como <code>text</code>, enquanto os campos usados para agregações, como "categoria" e "marca", serão mapeados como <code>keyword</code> para permitir a filtragem facetada.</p><p>O campo "descrição" será usado para a busca vetorial, pois fornece mais contexto sobre os produtos. Este campo será definido como <code>dense_vector,</code> , armazenando a representação vetorial da descrição.</p><p>O mapeamento do índice será o seguinte:</p>{
   "mappings":{
      "properties":{
         "id":{
            "type":"keyword"
         },
         "brand":{
            "type":"text",
            "fields":{
               "keyword":{
                  "type":"keyword"
               }
            }
         },
         "name":{
            "type":"text"
         },
         "price":{
            "type":"float"
         },
         "price_sign":{
            "type":"keyword"
         },
         "currency":{
            "type":"keyword"
         },
         "image_link":{
            "type":"keyword"
         },
         "description":{
            "type":"text"
         },
         "description_embeddings":{
            "type":"dense_vector",
            "dims":384
         },
         "rating":{
            "type":"keyword"
         },
         "category":{
            "type":"keyword"
         },
         "product_type":{
            "type":"keyword"
         },
         "tag_list":{
            "type":"keyword"
         }
      }
   }
}<p>O script para criar o índice pode ser encontrado <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/hybrid-search-for-an-e-commerce-product-catalogue/product-store-search/infra/create_index.py">aqui</a>.</p><h2>Geração de incorporação</h2><p>Para vetorizar as descrições dos produtos, utilizamos o modelo all-MiniLM-L6-v2. Neste caso, a aplicação é responsável por gerar os embeddings antes da indexação. Outra opção seria importar o modelo para o cluster Elasticsearch, mas para este ambiente local, optamos por realizar a vetorização diretamente dentro da aplicação.</p><p>Utilizamos o conjunto de dados de cosméticos disponível no <a href="https://www.kaggle.com/datasets/shivd24coder/cosmetic-brand-products-dataset">Kaggle</a> para preencher o índice e, para melhorar a eficiência da ingestão de dados, usamos o processamento em lote. Durante essa mesma etapa de ingestão, geraremos os embeddings para o campo "description" e os indexaremos no novo campo "description_embeddings".</p><p>Todo o processo de ingestão de dados pode ser acompanhado e executado diretamente através do <strong>Jupyter Notebook</strong> disponível no repositório. O notebook fornece um guia passo a passo sobre como os dados são lidos, processados e indexados no Elasticsearch, permitindo fácil replicação e experimentação.</p><p>Você pode acessar o notebook no seguinte link: <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/hybrid-search-for-an-e-commerce-product-catalogue/product-store-search/ingestion/ingestion.ipynb">Notebook de Ingestão.</a></p><h2>Implementação de busca híbrida</h2><p>Agora, vamos implementar a busca híbrida. Para a pesquisa baseada em palavras-chave, usamos a consulta <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-multi-match-query.html">multi_match</a> , direcionada aos campos "nome", "categoria" e "descrição". Isso garante que os documentos que contenham o termo de pesquisa em qualquer um desses campos sejam recuperados.</p><p>Para a busca vetorial, utilizamos a <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/knn-search.html">consulta KNN</a>. O termo de pesquisa precisa ser vetorizado antes da execução da consulta, e isso é feito usando o método que vetoriza o termo de entrada. Note que o mesmo modelo usado durante a ingestão também é usado para o termo de pesquisa.</p><p>A combinação das duas buscas é realizada utilizando o algoritmo <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/rrf.html">Reciprocal Rank Fusion (RRF) </a> , que mescla os resultados das duas consultas e aumenta a precisão da busca ao reduzir o ruído. O RRF permite que as buscas baseadas em palavras-chave e em vetores funcionem em conjunto, aprimorando a compreensão da consulta do usuário.</p>query = {
   "retriever": {
       "rrf": {
           "retrievers": [
               {
                   "standard": {
                       "query": organic_query['query']
                   }
               },
               {
                   "knn": {
                       "field": "description_embeddings",
                       "query_vector": vector,
                       "k": 5,
                       "num_candidates": 20
                   }
               }
           ],
           "rank_window_size": 20,
           "rank_constant": 5
       }
   },
   "_source": organic_query['_source']
}<h3>Comparação de resultados: pesquisa por palavra-chave vs. pesquisa híbrida</h3><p>Agora, vamos comparar os resultados de uma pesquisa tradicional por palavras-chave com a pesquisa híbrida. Ao pesquisar por "base para pele seca" usando a busca por palavras-chave, obtemos os seguintes resultados:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcb5405df787bc8f5/6a17023e961e697ca1c4cdb4/52e717aa3c9c1fadfadb639f5fb77cf8e47e3b34-1600x1021.png" alt="Comparação de resultados: Busca por palavra-chave vs. busca híbrida" /><ol><li><p><strong>Base Revlon ColorStay para Pele Normal/SecaDescrição</strong>: A Base Revlon ColorStay oferece cobertura de longa duração com uma fórmula leve que não craquela, desbota ou transfere. Com a tecnologia de liberação gradual, esta fórmula sem óleo e com equilíbrio de hidratação foi especialmente desenvolvida para peles normais ou secas, proporcionando hidratação contínua. Características: Maquiagem confortável e com duração de até 24 horas. Cobertura média a total. Disponível em uma variedade de lindas cores.
</p></li><li><p><strong>Base Mousse Dream Smooth da Maybelline</strong>: Por que você vai amar? Esta base cremosa exclusiva proporciona uma pele 100% macia como a de um bebê. Pele com aparência e sensação de hidratação por 14 horas - nunca áspera ou ressecada. Fórmula leve que proporciona cobertura perfeitamente hidratante. Mistura-se perfeitamente e proporciona uma sensação de frescor o dia todo. Sem óleo, sem fragrância, testado por dermatologistas, testado contra alergias, não comedogênico – não obstrui os poros. Seguro. Para peles sensíveis.</p></li></ol><p><strong>Análise</strong>: Ao pesquisar por "base para pele seca", os resultados foram obtidos pela correspondência exata entre as palavras-chave do termo de pesquisa e os títulos e descrições dos produtos. No entanto, essa combinação nem sempre representa a melhor escolha. Por exemplo, <strong>a base Revlon ColorStay para pele normal/seca</strong> é uma boa opção, pois é formulada especificamente para pele seca. Apesar de ser isento de óleo, sua fórmula foi desenvolvida para proporcionar hidratação contínua. Em contrapartida, também recebemos <strong>a base Maybelline Dream Smooth Mousse</strong>, que, embora seja livre de óleo e mencione hidratação, geralmente é mais recomendada para peles oleosas ou mistas, já que os produtos sem óleo tendem a se concentrar no controle da oleosidade em vez de fornecer a hidratação extra necessária para peles secas. Isso evidencia a limitação das buscas baseadas em palavras-chave, que podem retornar produtos que não atendem completamente às necessidades específicas de pessoas com pele seca.</p><p>Agora, ao realizar a mesma pesquisa usando a abordagem híbrida:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt412e38b327cf6a4f/6a17024066c4f94c52f8beb9/13b562a5120619355ba0861976102e208964a49f-1600x1021.png" alt="Realizando buscas usando a abordagem híbrida" /><ol><li><p><strong>Base Cremosa CoverGirl Outlast Stay Luminous Natural (820): Descrição</strong>: A Base CoverGirl Outlast Stay Luminous é perfeita para obter um acabamento luminoso e um brilho sutil. É livre de óleo, com uma fórmula não oleosa que proporciona à sua pele uma luminosidade natural que dura o dia todo! Esta base de longa duração hidrata a pele enquanto proporciona uma cobertura impecável.

<strong>Análise: </strong>Este produto é uma excelente opção, pois prioriza a hidratação, que é fundamental para usuários com pele seca. Os termos "hidrata a pele" e "acabamento luminoso" estão alinhados com a intenção do usuário de encontrar uma base para pele seca. A busca vetorial provavelmente compreendeu o conceito de hidratação e o relacionou à necessidade de uma base que trate a pele seca.
</p></li><li><p><strong>Base Revlon ColorStay para Pele Normal/Seca: Descrição:</strong> A base Revlon ColorStay oferece cobertura de longa duração com uma fórmula leve que não craquela, desbota ou transfere. Com a tecnologia de liberação gradual, esta fórmula sem óleo e com equilíbrio de hidratação foi especialmente desenvolvida para peles normais ou secas, proporcionando hidratação contínua.

<strong>Análise: </strong>Este produto aborda diretamente as necessidades de usuários com pele seca, mencionando explicitamente que sua fórmula é indicada para pele normal ou seca. A "fórmula de equilíbrio de umidade" e a hidratação contínua são ideais para quem busca uma base que atenda às necessidades da pele seca. A busca vetorial recuperou com sucesso esse resultado, não apenas pela correspondência de palavras-chave, mas também pelo foco na hidratação e pela menção específica de pele seca como público-alvo.
</p></li><li><p><strong>Descrição da Base Sérum: </strong>As bases sérum são fórmulas leves com cobertura média, disponíveis em uma ampla gama de 21 tons. Essas bases oferecem cobertura moderada com aparência natural e uma sensação de sérum muito leve. Possuem viscosidade muito baixa e são dispensados com a bomba fornecida ou com o conta-gotas de vidro opcional, disponível para compra separadamente, caso seja de preferência.

<strong>Análise:</strong> Neste caso, a descrição enfatiza uma base sérum leve com toque natural, o que está de acordo com as necessidades de pessoas com pele seca, que geralmente buscam produtos suaves, hidratantes e que proporcionem um acabamento sem efeito craquelado. A busca vetorial provavelmente captou o contexto mais amplo de cobertura leve e natural e a textura semelhante a um sérum, que está associada à retenção de umidade e a uma aplicação confortável, tornando-a relevante para pele seca, mesmo que o termo "pele seca" não seja mencionado explicitamente.</p></li></ol><h2>Implementação de facetas</h2><p>Os filtros são essenciais para refinar e filtrar os resultados da pesquisa de forma eficiente, proporcionando aos usuários uma navegação mais direcionada, especialmente em cenários com grande variedade de produtos, como no comércio eletrônico. Elas permitem que os usuários ajustem os resultados com base em atributos como categoria, marca ou preço, tornando a busca mais precisa. Para implementar este recurso, usamos <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html">agregações de termos</a> nos campos <code>category</code> e <code>brand</code> , que foram definidos como <code>keyword</code> durante o estágio de criação do índice.</p>    query = build_query(term, categories, product_types, brands)
    query["aggs"] = {
        "product_types": {"terms": {"field": "product_type"}},
        "categories": {"terms": {"field": "category"}},
        "brands": {"terms": {"field": "brand.keyword"}}
    }<p>O código completo da implementação pode ser encontrado <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/hybrid-search-for-an-e-commerce-product-catalogue/product-store-search/api/api.py#L144">aqui</a>.</p><p>Veja abaixo os resultados da busca por "base para pele seca":</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt31080652a60d8600/6a1702416234e0af7ddb18e7/e8907af359c021eaa38ec7a6a53f10c325ee8ade-1146x1248.png" alt="Resultados da pesquisa por &quot;base para pele seca&quot;" /><h2>Personalizando resultados: consultas fixadas</h2><p>Em alguns casos, pode ser benéfico promover determinados produtos nos resultados da pesquisa. Para isso, utilizamos <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-pinned-query.html"><strong>Consultas Fixadas</strong></a>, que permitem que produtos específicos apareçam no topo dos resultados. A seguir, realizaremos uma busca pelo termo "Fundação" sem promover nenhum produto:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt31e75c815262993e/6a170243509168ae42e1b95d/9396c4ed358e7a68eed47f17dd6915d0bad492aa-1600x1157.png" alt="Pesquise o termo &quot;Fundação&quot; sem promover nenhum produto." /><p>Em nosso exemplo, podemos promover produtos que tenham a etiqueta "Sem Glúten". Ao utilizarmos os IDs dos produtos, garantimos que eles sejam priorizados nos resultados da pesquisa. Especificamente, promoveremos os seguintes produtos: <strong>Base Sérum</strong> (ID: 1043), <strong>Base de Alta Cobertura</strong> (ID: 1042) e <strong>Pó Translúcido Realista</strong> (ID: 1039).</p>{
   "query":{
      "pinned":{
         "ids":[
            "1043",
            "1042",
            "1039"
         ],
         "organic":{
            "bool":{
               "must":[
                  {
                     "multi_match":{
                        "query":"foundation",
                        "fields":[
                           "name",
                           "category",
                           "description"
                        ]
                     }
                  }
               ]
            }
         }
      }
   }
}<p>Utilizamos IDs de produto específicos para garantir que eles sejam priorizados nos resultados da consulta. A estrutura da consulta inclui uma lista de IDs de produtos que devem ser "fixados" no topo (neste caso, os IDs 1043, 1042 e 1039), enquanto os resultados restantes seguem o fluxo orgânico da pesquisa, usando uma combinação de condições como a consulta de texto nos campos "nome", "categoria" e "descrição". Dessa forma, é possível promover itens de maneira controlada, garantindo sua visibilidade, enquanto o restante da busca permanece baseado na relevância usual.</p><p>Abaixo, você pode ver o resultado da execução da consulta com os produtos promovidos:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt53a6d5cbef227f16/6a1702458b73cb68f0189ef3/8c1a547bfe31360c405eae0891c666635051a51b-1600x1039.png" alt="Resultado da execução da consulta com os produtos promovidos" /><p>O código completo da consulta pode ser encontrado <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/hybrid-search-for-an-e-commerce-product-catalogue/product-store-search/api/api.py#L112">aqui</a>.</p><h2>Analisando o comportamento de busca com análise comportamental.</h2><p>Até o momento, já adicionamos funcionalidades para melhorar a relevância dos resultados de busca e facilitar a descoberta de produtos. Agora, vamos finalizar nossa solução de busca incluindo um recurso que nos ajudará a analisar o comportamento de busca do usuário, identificando padrões como consultas com ou sem resultados e cliques nos resultados da busca. Para isso, usaremos o recurso <strong>de Análise Comportamental</strong> fornecido pela Elastic. Com ele, em apenas alguns passos, podemos monitorar e analisar o comportamento de busca do usuário, obtendo informações valiosas para otimizar a experiência de busca.</p><h3>Criando a coleta de dados de análise comportamental</h3><p>Nossa primeira ação será criar uma coleção, que será responsável por receber todos os eventos de análise comportamental. Para criar a coleção, acesse a interface do Kibana em <strong>Pesquisa &gt; Análise Comportamental</strong>. No exemplo abaixo, criamos a coleção chamada <code>tracking-search</code>.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9b4cb5480ab0bfef/6a1702474a531b189936a7e7/c05e533212a3690c5ea9f2d5226cbcdc901c482a-1600x1009.png" alt="Análise comportamental - como nomear sua coleção" /><h3>Integrar a análise comportamental à interface.</h3><p>Nosso aplicativo <a href="https://github.com/elastic/elasticsearch-labs/tree/main/supporting-blog-content/hybrid-search-for-an-e-commerce-product-catalogue/app-product-store">front-end</a> foi desenvolvido em JavaScript e, para integrar o Behavioral Analytics, seguiremos os passos descritos na documentação oficial da Elastic para instalar o <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/behavioral-analytics-start.html#behavioral-analytics-start-ui-integration-js-client"><strong>Behavioral Analytics JavaScript Tracker</strong></a>.</p><h3>Implementando o rastreador JavaScript</h3><p>Agora, vamos importar o cliente rastreador para nosso aplicativo e usar os métodos <code>trackPageView</code>, <code>trackSearch</code> e <code>trackSearchClick</code> para capturar as interações do usuário.</p><p><strong>Aviso</strong>: Embora utilizemos uma ferramenta para coletar dados de interação do usuário, é essencial garantir a conformidade com <strong>o GDPR</strong>. Isso significa informar claramente os usuários sobre quais dados estão sendo coletados, como serão usados e fornecer a opção de desativar o rastreamento. Além disso, devemos implementar medidas de segurança robustas para proteger as informações coletadas e respeitar os direitos do usuário, como o acesso e a exclusão de dados, garantindo que todas as etapas estejam em conformidade com os princípios do GDPR.
</p><p><strong>Etapa 1: Criando a instância do rastreador</strong></p><p>Primeiro, criaremos a instância do rastreador que monitorará as interações. Nessa configuração, definimos o endpoint de destino, o nome da coleção e a chave da API:</p>createTracker({
  endpoint: "https://endpoint:443",
  collectionName: "tracking-search",
  apiKey: "api-key"
});<p><strong>Etapa 2: Capturando visualizações de página</strong></p><p>Para rastrear visualizações de página, podemos configurar o evento <code>trackPageView</code> :</p>    trackPageView({
      page: {
        title: "home-page"
      },
    });<p>Para obter mais detalhes sobre o evento <code>trackPageView</code> , você pode consultar esta <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/behavioral-analytics-event-reference.html#behavioral-analytics-event-reference-pageview-fields">documentação</a>.</p><p><strong>Etapa 3: Capturar consultas de pesquisa</strong></p><p>Para monitorar as ações de busca dos usuários, utilizaremos o método <code>trackSearch</code> :</p>      trackSearch({
        search: {
          query: searchTerm,
          results: {
            items: documents,
            total_results: response.data.length,
          },
        },
      });<p>Aqui estamos coletando o termo de pesquisa e os resultados da pesquisa.</p><p><strong>Etapa 4: Rastreamento de cliques nos resultados da pesquisa</strong></p><p>Finalmente, para capturar cliques nos resultados da pesquisa, usaremos o método <code>trackSearchClick</code> :</p>trackSearchClick({
      document: { id: product.id, index: "products-catalog"},
      search: {
        query: searchTerm,
        page: {
          current: 1,
          size: products.length,
        },
        results: {
          items: documents,
          total_results: products.length,
        },
        search_application: "app-product-store"
      },
    });<p>Coletamos informações sobre o ID do documento clicado, bem como o termo de pesquisa e os resultados da pesquisa.</p><h3>Analisando os dados no Kibana</h3><p>Agora que os eventos de interação do usuário estão sendo capturados, podemos obter dados valiosos sobre as ações de busca. O Kibana utiliza a ferramenta de Análise Comportamental para visualizar e analisar esses dados comportamentais. Para visualizar os resultados, basta navegar até <strong>Pesquisa &gt; Análise Comportamental &gt; Minha Coleção</strong>, onde será exibida uma visão geral dos eventos capturados.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdab4f4507c5a4732/6a17024860084b34ca3c4411/e219c4af2e01b0ccc1b9079459a07832835abc75-1600x1155.png" alt="Analisando os dados no Kibana" /><p>Nesta visão geral, obtemos uma perspectiva ampla dos eventos registrados para cada ação integrada à nossa interface. A partir dessas informações, podemos obter insights valiosos sobre o comportamento de busca do usuário. No entanto, se você deseja criar painéis personalizados com métricas mais relevantes para o seu cenário específico, o Kibana oferece ferramentas poderosas para a criação de painéis, permitindo que você crie diversas visualizações de suas métricas.</p><p>Abaixo, criei algumas visualizações e gráficos para monitorar, por exemplo, os termos mais pesquisados ao longo do tempo, as consultas que não retornaram resultados, uma nuvem de palavras destacando os termos mais pesquisados e, finalmente, uma visualização geográfica para identificar a origem do acesso à pesquisa.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt04ced4406436f942/6a17024a5091685116e1b961/84a2c39dab77a3f9366c258a3a45d2cbc7df125e-1600x689.png" alt="Visualizações e gráficos para monitorar" /><h2>Conclusão</h2><p>Neste artigo, implementamos uma solução de busca híbrida que combina busca por palavras-chave e busca vetorial, fornecendo resultados mais precisos e relevantes para os usuários. Exploramos também como usar recursos adicionais, como filtros e personalização de resultados com Consultas Fixadas, para criar uma experiência de busca mais completa e eficiente.</p><p>Além disso, integramos <strong>o Behavioral Analytics</strong> da Elastic para capturar e analisar o comportamento do usuário durante suas interações com o mecanismo de busca. Ao usar métodos como <code>trackPageView</code>, <code>trackSearch</code> e <code>trackSearchClick</code>, conseguimos monitorar consultas de pesquisa, cliques em resultados de pesquisa e visualizações de página, gerando informações valiosas sobre o comportamento de pesquisa.</p><h2>Referências</h2><p>Conjunto de dados</p><p><a href="https://www.kaggle.com/datasets/shivd24coder/cosmetic-brand-products-dataset">https://www.kaggle.com/datasets/shivd24coder/cosmetic-brand-products-dataset</a></p><p>Transformador</p><p><a href="https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2">https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2</a></p><p>Fusão de Classificação Recíproca</p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/rrf.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/rrf.html</a></p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/retriever.html#rrf-retriever">https://www.elastic.co/guide/en/elasticsearch/reference/current/retriever.html#rrf-retriever</a></p><p>Consulta Knn</p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/knn-search.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/knn-search.html</a></p><p>Consulta fixada</p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-pinned-query.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-pinned-query.html</a></p><p>APIs de análise comportamental</p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/behavioral-analytics-apis.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/behavioral-analytics-apis.html</a></p><p>https://www.elastic.co/guide/en/elasticsearch/reference/current/behavioral-analytics-overview.html</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/hybrid-search-ecommerce</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/hybrid-search-ecommerce</guid>
    <category><![CDATA[Banco de dados vetorial]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt63c711d1bf9b2501/6a17024c66c4f9c2b7f8bebd/05578fc595a12f6b1ebf88a10a2a31e9971b545e-1200x628.png" length="0" type="image/png"/>
    <pubDate>Tue, 12 Nov 2024 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Implementação de busca semântica: Construindo uma busca de receitas com Elasticsearch]]></title>
    <description><![CDATA[Implementação da busca semântica no contexto de sites de comércio eletrônico.]]></description>
    <content:encoded><![CDATA[<h2>Introdução</h2><p>Muitos sites de comércio eletrônico estão interessados em aprimorar a experiência de busca de receitas. A busca semântica, quando aplicada corretamente, permite que os clientes encontrem rapidamente os ingredientes necessários com base em consultas mais naturais, como "algo para o Dia dos Namorados" ou "refeições de Ação de Graças".</p><p>Neste artigo, demonstraremos como usar o Elasticsearch para implementar uma busca semântica que suporte esse tipo de consulta. Vamos configurar um índice para armazenar o catálogo de ingredientes e produtos de um supermercado e demonstrar como esse índice pode ser usado para melhorar as buscas por receitas. Ao longo do artigo, explicaremos como criar essa estrutura de dados e aplicar técnicas de processamento de linguagem natural para fornecer resultados relevantes e alinhados à intenção do cliente.</p><p>Todo o código apresentado neste artigo foi desenvolvido em Python e está disponível no <a href="https://github.com/elastic/elasticsearch-labs/tree/main/supporting-blog-content/building-a-recipe-search-with-elasticsearch">GitHub</a>. Você pode acessar o repositório para revisar o código-fonte, fazer ajustes conforme necessário e implementar as soluções diretamente em seu ambiente de desenvolvimento.</p><h2>Iniciando a implementação da busca semântica</h2><p>Para começar a implementar a busca semântica, primeiro precisamos definir o modelo de linguagem natural. A Elastic oferece seu próprio modelo, <a href="https://www.elastic.co/guide/en/machine-learning/8.15/ml-nlp-elser.html"><strong>o ELSER</strong></a>, mas também oferece suporte para a integração de modelos de PNL de diversos fornecedores, como o Hugging Face. Essa flexibilidade permite que você escolha a opção que melhor se adapta às suas necessidades.</p><p>Neste artigo, utilizaremos <strong>o ELSER</strong>, que reduz a complexidade de implantação e gerenciamento de modelos de PNL (Processamento de Linguagem Natural). Além disso, o Elastic oferece o recurso <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/semantic-search-semantic-text.html"><strong>semantic_text</strong></a> , que simplifica bastante o processo. Com o <strong>semantic_text</strong>, todo o processo de geração de embeddings torna-se simples e automatizado. Basta definir um ponto de inferência e especificar o campo que receberá os embeddings no seu mapeamento de índice. Durante a indexação de documentos, os elementos incorporados serão gerados e associados automaticamente ao campo especificado.</p><h3>Etapas de configuração</h3><p>A seguir estão os passos para criar um índice com suporte para pesquisa semântica. Seguindo estas instruções, você terá um índice configurado e pronto para buscas semânticas:</p><ol><li><p><strong>Crie o </strong><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/infer-service-elser.html"><strong>ponto de inferência</strong></a>.</p></li><li><p><a href="https://github.com/andreluiz1987/semantic-search-market/blob/main/infra.py"><strong>Crie o índice</strong></a>, definindo o campo de descrição como semantic_text para que ele possa receber os embeddings.</p></li><li><p><a href="https://github.com/andreluiz1987/semantic-search-market/blob/main/ingestion.py"><strong>Indexe os dados</strong></a> no índice do catálogo de produtos, que armazenará um catálogo de produtos. Este catálogo foi obtido a partir de um conjunto de dados disponível <a href="https://www.kaggle.com/datasets/bhavikjikadara/grocery-store-dataset?select=GroceryDataset.csv">aqui</a>.</p></li></ol><h2>Aplicação da busca semântica em supermercados</h2><p>Agora que temos o índice preenchido com dados de produtos de supermercado, estamos testando e validando consultas para melhorar os resultados da pesquisa usando a busca semântica. Nosso objetivo é proporcionar uma experiência de busca mais inteligente, que compreenda o contexto e a intenção do usuário, oferecendo resultados mais relevantes e precisos.</p><h3>Desafios resolvidos pela busca semântica</h3><p>Com base no catálogo de produtos, vamos explorar como a busca semântica pode transformar a experiência de busca em supermercados, abordando problemas de vocabulário e contexto que a busca lexical tradicional costuma ter dificuldades em resolver.</p><h4><strong>1. Interpretação das intenções culinárias</strong></h4><p><strong>Problema 01</strong>: Um cliente pode pesquisar por "frutos do mar para grelhar", mas um sistema de busca lexical pode não entender completamente a intenção por trás da consulta. Pode ser que o sistema não consiga identificar todos os frutos do mar adequados para grelhar, retornando apenas aqueles que contenham exatamente os termos "frutos do mar" ou "grelhar" no título do produto.</p><p>Primeiramente, realizaremos uma busca lexical e analisaremos os resultados. Em seguida, faremos o mesmo com uma busca semântica, comparando os resultados para o mesmo termo de busca.</p><p><strong>Consulta de pesquisa lexical</strong></p> response = client.search(
        index="grocery-catalog",
        size=5,
        source_excludes="description_embedding",
        query={
            "multi_match": {
                "query": "seafood for grilling",
                "fields": [
                    "name",
                    "description"]
            }
        }
    )<p><strong>Resultados:</strong></p><p>Tipo de pesquisa</p><p>Nome</p><p>Pontuação</p><p>Lexical</p><p>Caranguejo-das-neves Bairdi do Alasca, peixe do noroeste</p><p>10,453125</p><p>Lexical</p><p>Molho Gourmet Original do Sr. Yoshida</p><p>7,2289705</p><p>Lexical</p><p>Pacote Variado de Frutos do Mar Premium - 20 unidades</p><p>7.1924105</p><p>Lexical</p><p>Pargo-vermelho americano - Inteiro, com cabeça, limpo</p><p>6,998647</p><p>Lexical</p><p>Garras e patas de lagosta, capturadas de forma sustentável na natureza.</p><p>6,438654</p><p>A busca lexical retornou alguns frutos do mar adequados para grelhar, como o pargo-vermelho americano e o caranguejo-das-neves-do-Alasca Bairdi da Northwest Fish. No entanto, a busca lexical retornou produtos menos relevantes no topo da lista, como o molho Mr. Yoshida, que não é um produto à base de frutos do mar, mas sim um molho para carne, sugerindo que o algoritmo lexical teve dificuldades em compreender totalmente o contexto de "para grelhar".</p><p><strong>Solução de busca semântica</strong></p><p>Usamos uma consulta que combina o termo "frutos do mar" com contextos de preparo como "grelhar" para retornar uma lista abrangente de opções, como filés de peixe, camarão e vieiras, que são ideais para grelhar — mesmo que as palavras "grelhar" ou "frutos do mar" não apareçam diretamente no nome do produto. Isso garante que os resultados da pesquisa estejam mais alinhados com a intenção do cliente.</p><p><strong>Pesquisa semântica de consulta:</strong></p>es_client.search(
   index="grocery-catalog-elser",
   size=size,
   source_excludes="description_embedding",
   query={
       "semantic": {
           "field": "description_embedding",
           "query": "seafood for grilling"

       }
   })<p>Tipo de pesquisa</p><p>Nome</p><p>Pontuação</p><p>Semântica</p><p>Robalo inteiro, limpo e com cabeça.</p><p>16.175909</p><p>Semântica</p><p>Bacalhau-negro do Alasca (peixe-sable)</p><p>15,855331</p><p>Semântica</p><p>Pargo-vermelho americano - Inteiro, com cabeça</p><p>15,454779</p><p>Semântica</p><p>Caranguejo-das-neves Bairdi do Alasca, peixe do noroeste</p><p>15,855331</p><p>Semântica</p><p>Pargo-vermelho americano - Inteiro, com cabeça</p><p>15,3892355</p><p>A busca semântica não apenas retornou produtos diretamente relacionados ao termo "frutos do mar", mas também compreendeu o contexto de "grelhar", apresentando peixes inteiros e filés adequados para grelhar. O ponto crucial aqui é a precisão dos resultados, que incluíram opções de peixes inteiros, como o robalo e o bacalhau negro do Alasca, ambos comumente usados para grelhar.</p><p><strong>Problema 02 </strong>: Muitos clientes procuram soluções rápidas e fáceis para o jantar depois de um longo dia de trabalho, usando termos como "refeições fáceis para a semana". A busca lexical tradicional pode não capturar completamente o conceito de refeições rápidas, muitas vezes focando apenas em produtos que incluem a palavra "fácil" em seu nome.</p><p>Assim como fizemos no problema anterior, começaremos realizando uma busca lexical. Em seguida, aplicaremos uma solução utilizando busca semântica.</p><p><strong>Consulta de pesquisa lexical</strong></p> response = client.search(
        index="grocery-catalog",
        size=5,   
        source_excludes="description_embedding",
        query={
            "multi_match": {
                "query": "easy weeknight meals",
                "fields": [
                    "name",
                    "description"]
            }
        }
    )<p><strong>Resultados:</strong></p><p>Tipo de pesquisa</p><p>Nome</p><p>Pontuação</p><p>Lexical</p><p>Etiquetas adesivas Avery Easy Peel para endereços, pacote com 4200 unidades</p><p>8.017723</p><p>Lexical</p><p>Refeições portáteis/de emergência com aquecimento automático Omeals 32</p><p>6,592727</p><p>Lexical</p><p>Poke de Atum Albacora em Cubos da Coastal Seafood</p><p>5,836883</p><p>Lexical</p><p>Espuma Hefty Super Weight de 340 g (12 oz)</p><p>5,8116536</p><p>Lexical</p><p>Guardanapos Vanity Fair Everyday, 2 camadas, pacote com 110 unidades</p><p>5,752989</p><p>A busca lexical retornou resultados muito menos relevantes, incluindo itens completamente não relacionados a refeições, como Etiquetas de Endereço Avery Easy Peel e Guardanapos Vanity Fair Everyday. Esses produtos não atendem à necessidade do usuário por refeições rápidas. Embora a busca lexical tenha retornado um produto útil (Omeals Self Heating Emergency Meals), outros resultados, como guardanapos e etiquetas, só correspondiam às palavras "fácil" ou "noite de semana" em suas descrições, sem realmente abordar a intenção do usuário de encontrar uma solução rápida para refeições.</p><p><strong>Solução de busca semântica</strong></p><p>Implementamos uma consulta que entende a intenção por trás de refeições rápidas e fáceis. Associa produtos que podem ser preparados rapidamente, como carnes pré-cozidas, massas congeladas ou kits de refeição, mesmo que não incluam explicitamente a palavra "fácil" no nome. Essa abordagem garante que os clientes encontrem as opções mais adequadas para jantares rápidos durante a semana, atendendo à necessidade de praticidade.</p><p><strong>Pesquisa semântica de consulta</strong></p>es_client.search(
   index="grocery-catalog-elser",
   size=size,
   source_excludes="description_embedding",
   query={
       "semantic": {
           "field": "description_embedding",
           "query": "easy weeknight meals"

       }
   })<p><strong>Resultados:</strong></p><p>Tipo de pesquisa</p><p>Nome</p><p>Pontuação</p><p>Semântica</p><p>Refeições portáteis/de emergência com aquecimento automático Omeals 32</p><p>14.610006</p><p>Semântica</p><p>Nissin, Cup Noodles, Camarão, 70g</p><p>13,751424</p><p>Semântica</p><p>Mistura para Waffles e Panquecas Namaste Sem Glúten</p><p>13,73376</p><p>Semântica</p><p>Batatas Idaho, Batatas Hashbrown Douradas Grelhadas</p><p>12,549422</p><p>Semântica</p><p>Nissin, Cup Noodles, Frango, 24 unidades</p><p>12.034527</p><p>A busca semântica retornou produtos claramente relacionados a refeições rápidas e práticas, como macarrão instantâneo (Cup Noodles), batatas pré-cozidas e misturas para panquecas, que são opções típicas para jantares fáceis durante a semana. Isso demonstra que a busca semântica consegue captar o conceito por trás da frase "refeições fáceis para noites de semana", identificando a intenção do usuário de encontrar refeições rápidas e práticas. Curiosamente, produtos de outras categorias, como "refrigerantes", também podem ser incluídos quando relevantes no contexto (por exemplo, bebidas para acompanhar as refeições).</p><h4><strong>2. Termos regionais e variações de vocabulário</strong></h4><p><strong>Problema</strong>: Um cliente pode pesquisar por "refrigerante", enquanto outro cliente pode usar "refrigerante" para o mesmo produto. A busca lexical tradicional não reconhece que ambos os termos se referem ao mesmo item.</p><p><strong>Consulta de pesquisa lexical</strong></p> response = client.search(
        index="grocery-catalog",
        size=5,
        source_excludes="description_embedding",
        query={
            "multi_match": {
                "query": "refreshing pop drink low sugar",
                "fields": [
                    "name",
                    "description"]
            }
        }
    )<p><strong>Resultados:</strong></p><p>Tipo de pesquisa</p><p>Nome</p><p>Pontuação</p><p>Lexical</p><p>Prime Hydration+ Sticks - Mistura para Bebida Eletrolítica</p><p>14,492869</p><p>Lexical</p><p>Capri Sun, 100% Suco, Pacote Variado</p><p>12.340851</p><p>Lexical</p><p>Bebida energética Joyburst, Frosé Rosé, 12</p><p>11,839179</p><p>Lexical</p><p>Pop-Tarts da Kellogg's, com cobertura de açúcar mascavo e canela.</p><p>9,97788</p><p>Lexical</p><p>Kind Mini Bars, Pacote Variado, 0,7</p><p>9,336912</p><p>A busca lexical concentra-se em correspondências exatas de palavras. Embora tenha retornado produtos como Prime Hydration e Capri Sun, a correspondência direta com o termo "pop" também levou a resultados irrelevantes, como Pop-Tarts da Kellogg's, que é um lanche e não uma bebida. Isso demonstra como a busca lexical pode ser menos eficaz quando um termo possui múltiplos significados ou pode ser ambíguo.</p><p><strong>Solução de busca semântica</strong></p><p>Em consultas semânticas, podemos superar o problema das variações de vocabulário que a busca lexical não consegue resolver. Ao expandir os termos de pesquisa, conseguimos obter resultados baseados no significado contextual, fornecendo respostas mais relevantes e abrangentes.</p><p><strong>Consulta:</strong></p>es_client.search(
   index="grocery-catalog-elser",
   size=size,
   source_excludes="description_embedding",
   query={
       "semantic": {
           "field": "description_embedding",
           "query": "refreshing pop drink low sugar"

       }
   })<p><strong>Resultados:</strong></p><p>Tipo de pesquisa</p><p>Nome</p><p>Pontuação</p><p>Semântica</p><p>Refrigerante Prebiótico Olipop 355ml (12 oz) - Variedade</p><p>14,776867</p><p>Semântica</p><p>Bai Antioxidante Cocofusion, Pacote Variado, 18</p><p>14,663253</p><p>Semântica</p><p>Bebida energética Monster, Zero Ultra, 24</p><p>14,486348</p><p>Semântica</p><p>Joyburst Energy Variedade, 355 ml</p><p>14.007214</p><p>Semântica</p><p>Bebida energética Joyburst, Frosé Rosé, 12</p><p>13,641038</p><p>A busca semântica retorna produtos que correspondem diretamente ao conceito de "refrigerante" como sinônimo de "soda" (como Olipop Prebiotics Soda), mesmo que o termo exato "refrigerante" não esteja presente no nome do produto. A busca compreendeu a intenção do usuário — uma bebida refrescante e com baixo teor de açúcar — e conseguiu retornar produtos relevantes, incluindo opções como refrigerantes prebióticos (Olipop) e bebidas energéticas sem açúcar (Monster Energy Drink).</p><h2>Conclusão</h2><p>A implementação da busca semântica no contexto de supermercados provou ser altamente eficaz na compreensão de consultas complexas como "frutos do mar para grelhar" e "refeições fáceis para a semana". Essa abordagem nos permitiu interpretar a intenção do usuário com mais precisão, retornando produtos altamente relevantes.</p><p>Ao utilizar o Elasticsearch e simplificar o processo com o ELSER, conseguimos aplicar a busca semântica de forma rápida e eficiente, melhorando significativamente os resultados da busca e proporcionando uma experiência de compra mais ágil e direcionada. Isso não apenas otimizou o processo de busca, mas também aumentou a relevância dos resultados oferecidos aos clientes.</p><h2>Referências</h2><p>Modelo ELSER:</p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/put-inference-api.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/put-inference-api.html</a></p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/infer-service-elser.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/infer-service-elser.html</a></p><p></p><p>Texto semântico:</p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/semantic-text.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/semantic-text.html</a></p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/semantic-search.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/semantic-search.html</a></p><p></p><p>Conjunto de dados:</p><p><a href="https://www.kaggle.com/datasets/bhavikjikadara/grocery-store-dataset?select=GroceryDataset.csv">https://www.kaggle.com/datasets/bhavikjikadara/grocery-store-dataset?select=GroceryDataset.csv</a></p><p></p><p>Busca semântica:</p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/semantic-search.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/semantic-search.html</a></p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/semantic-search-semantic-text.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/semantic-search-semantic-text.html</a></p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/semantic-search-elasticsearch-ecommerce</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/semantic-search-elasticsearch-ecommerce</guid>
    <category><![CDATA[Noções básicas]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5c545fc80b6d79d6/6a170214839dfad776dcfd6f/d968e646240cd3ef7c79b5124d562a5f951d812b-1440x840.png" length="0" type="image/png"/>
    <pubDate>Thu, 07 Nov 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>