<?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/es/search-labs/author/andre-luiz</link>
    </image>
    <link>https://www.elastic.co/es/search-labs/author/andre-luiz</link>
    <atom:link href="https://www.elastic.co/es/search-labs/rss/author/andre-luiz.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[es]]></language>
    <lastBuildDate>Mon, 28 Sep 2026 05:13:02 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Mapear incrustaciones a tipos de campos de Elasticsearch: semantic_text, dense_vector, sparse_vector]]></title>
    <description><![CDATA[Discutir cómo y cuándo usar semantic_text, dense_vector o sparse_vector, y cómo se relacionan con la generación de incrustaciones.]]></description>
    <content:encoded><![CDATA[<p>El uso de incrustaciones para mejorar la relevancia y precisión de la recuperación de información creció significativamente a lo largo de los años. Herramientas como Elasticsearch evolucionaron para soportar este tipo de datos mediante tipos de campos especializados como vectores densos, vectores dispersos y texto semántico. Sin embargo, para lograr buenos resultados, es esencial entender cómo mapear correctamente las incrustaciones a los tipos de campos disponibles de Elasticsearch: <code>semantic_text</code>, <code>dense_vector</code>y <code>sparse_vector</code>.</p><p>En este artículo, discutiremos estos tipos de campos, cuándo usar cada uno y cómo se relacionan con la generación y las estrategias de uso de incrustaciones, tanto durante la indexación como durante la consulta.</p><h2>Tipo vectorial denso</h2><p>El tipo de campo <code>dense_vector</code> en Elasticsearch se emplea para almacenar vectores densos, que son representaciones numéricas de datos como texto, imágenes y audio, donde casi todas las dimensiones son relevantes. Estos vectores se generan empleando modelos de incrustación proporcionados por plataformas como OpenAI, Cohere o Hugging Face, y están diseñados para captar el significado semántico general de los datos, incluso cuando no comparten términos exactos con otros documentos.</p><p>En Elasticsearch, los vectores densos pueden tener hasta 4096 dimensiones dependiendo del modelo empleado. Por ejemplo, el modelo totalmente MiniLM-L6-v2 genera vectores con 384 dimensiones, mientras que el text-embedding-ada-002 de OpenAI produce vectores con 1536 dimensiones.</p><p>El campo <code>dense_vector</code> se adopta comúnmente como el tipo predeterminado para almacenar este tipo de incrustación cuando se necesita mayor control, como usando vectores pregenerados, aplicando funciones de similitud personalizadas o integrando con modelos externos.</p><h3>¿Cuándo y por qué usar dense_vector tipo?</h3><p>Los vectores densos son excelentes para capturar similitudes semánticas entre oraciones, párrafos o documentos completos. Funcionan muy bien cuando el objetivo es comparar el significado general de los textos, aunque no compartan los mismos términos.</p><p>El campo vectorial denso es ideal cuando ya tienes una pipeline externa de generación de embedding usando modelos proporcionados por plataformas como OpenAI, Cohere o Hugging Face y solo quieres almacenar y consultar estos vectores manualmente. Este tipo de campo ofrece alta compatibilidad con modelos de incrustación y total flexibilidad en la generación y consulta, permitiéndote controlar cómo se producen, indexan y emplean los vectores durante la búsqueda.</p><p>Además, soporta diferentes formas de búsqueda semántica, con consultas como k-NN o script_score para casos en los que sea necesario ajustar la lógica de clasificación. Estas posibilidades hacen que el vector denso sea ideal para aplicaciones como RAG (Generación Aumentada por Recuperación), sistemas de recomendación y búsquedas personalizadas basadas en similitudes.</p><p>Por último, el campo te permite personalizar la lógica de relevancia, usando funciones como <code>cosineSimilarity</code>, <code>dotProduct</code> o <code>l2norm</code> para adaptar la clasificación según las necesidades de tu caso de uso. </p><p>Los vectores densos siguen siendo la mejor opción para quienes necesitan flexibilidad, personalización y compatibilidad con casos de uso avanzados como los mencionados anteriormente.</p><h3>¿Cómo usar la consulta para el tipo de vector denso?</h3><p>Las búsquedas en campos definidos como <strong><code>dense_vector</code></strong> emplean la consulta k-vecinos más cercanos. Esta consulta es responsable de encontrar documentos cuyo vector denso está más cercano al vector de consulta. A continuación se muestra un ejemplo de cómo aplicar una consulta k-NN a un campo vectorial denso:</p>{
  "knn": {
    "field": "my_dense_vector",
    "k": 10,
    "num_candidates": 50,
    "query_vector": [/* vector generated by model */]
  }
}<p>Además de la consulta k-NN, si es necesario personalizar el puntaje del documento, también es posible usar la consulta script_score, combinándola con funciones de comparación vectorial como <strong>cosenoSimilitud, Producto PuntoPunto o l2norm</strong> para calcular la relevancia de forma más controlada. Mira el ejemplo:</p>{
"script_score": {
    "query": { "match_all": {} },
    "script": {
      "source": "cosineSimilarity(params.query_vector,
'my_dense_vector') + 1.0",
      "params": {
        "query_vector": [/* vector */]
      }
    }
  }
}<p>Si quieres profundizar más, te recomiendo explorar el artículo <a href="https://www.elastic.co/search-labs/blog/vector-search-set-up-elasticsearch">Cómo configurar la búsqueda vectorial en Elasticsearch.</a></p><p></p><h2>Tipo vectorial disperso</h2><p>El tipo de campo <strong><code>sparse_vector</code></strong> se emplea para almacenar vectores dispersos, que son representaciones numéricas donde la mayoría de los valores son cero y solo unos pocos términos tienen pesos significativos. Este tipo de vector es común en modelos basados en términos como SPLADE o ELSER (Elastic Learned Sparse EncodeR).</p><h3>¿Cuándo y por qué usar tipo vectorial disperso?</h3><p>Los vectores dispersos son ideales cuando se necesita una búsqueda más precisa en términos léxicos, sin sacrificar la inteligencia semántica. Representan el texto como pares token/valor, resaltando solo los términos más relevantes con pesos asociados, lo que proporciona claridad, control y eficiencia.</p><p>Este tipo de campo es especialmente útil cuando se generan vectores basados en términos, como en los modelos ELSER o SPLADE, que asignan diferentes pesos a cada token según su importancia relativa en el texto.</p><p>Para las ocasiones en las que quieres controlar la influencia de palabras específicas en la consulta, los tipos vectoriales dispersos te permiten ajustar manualmente el peso de los términos para optimizar el orden de los resultados.</p><p>Entre los principales beneficios están la transparencia en la búsqueda, ya que es posible entender claramente por qué un documento se consideraba relevante, y la eficiencia de almacenamiento, ya que solo se almacenan los tokens con valor distinto de cero, a diferencia de los vectores densos que almacenan todas las dimensiones.</p><p>Además, los vectores dispersos son el complemento ideal en estrategias de búsqueda híbrida, e incluso pueden combinar con vectores densos para combinar precisión léxica con comprensión semántica.</p><h3>¿Cómo usar la consulta para el tipo de vector disperso?</h3><p>La consulta <strong><code>sparse_vector</code></strong> te permite buscar documentos basándote en un vector de consulta en formato token/valor. Consulta un ejemplo de la consulta a continuación:</p>{
  "query": {
    "sparse_vector": {
      "field": "field_sparse",
      "query_vector": {
        "token1": 0.6,
        "token2": 0.2,
        "token3": 0.9
      }
    }
  }
}<p>Si prefieres usar un modelo capacitado, es posible emplear un punto final de inferencia que transforme automáticamente el texto de consulta en un vector disperso:</p>{
  "query": {
    "sparse_vector": {
      "field": "field_sparse",
      "inference_id": "the inference ID to produce the token/weights",
      "query": "search text"
    }
  }
}<p>Para profundizar en este tema, sugiero leer <a href="https://www.elastic.co/search-labs/blog/sparse-vector-embedding">Understanding sparse vector embeddings with trained ML</a> models.</p><h2>Tipo de texto semántico</h2><p>El tipo de campo <strong><code>semantic_text</code></strong> es la forma más sencilla y directa de usar la búsqueda semántica en Elasticsearch. Gestiona automáticamente la generación de incrustaciones, tanto en tiempo de indexación como en tiempo de consulta, a través de un punto final de inferencia. Esto significa que no tienes que preocuparte por generar o almacenar vectores manualmente.</p><h3>¿Cuándo y por qué usar texto semántico?</h3><p>El campo <code>semantic_text</code> es ideal para quienes quieren empezar con el mínimo esfuerzo técnico y sin tener que manejar vectores manualmente. Este campo automatiza pasos como la generación de incrustaciones y el mapeo de búsqueda vectorial, haciendo que la configuración sea más rápida y cómoda.</p><p>Deberías considerar usar <code>semantic_text</code> cuando valoras la <strong>simplicidad y la abstracción</strong>, ya que <strong>elimina la complejidad de configurar manualmente mapeos, generación de incrustaciones y pipelines de ingestión</strong>. Solo tienes que seleccionar el modelo de inferencia, y Elasticsearch se encarga del resto.</p><p>Los principales beneficios incluyen <strong>la generación automática de incrustaciones,</strong> realizada tanto durante la indexación como durante la consulta, y <strong>el mapeo listo para usar</strong>, que viene preconfigurado para soportar el modelo de inferencia seleccionado.</p><p>Además, el campo <strong>ofrece soporte nativo para la división automática de textos largos (fragmentación de texto),</strong> permitiendo dividir textos grandes en pasajes más pequeños, cada uno con su propia incrustación, lo que mejora la precisión en la búsqueda. Esto aumenta enormemente la productividad, especialmente para equipos que quieren ofrecer valor rápidamente sin tener que lidiar con la ingeniería subyacente de la búsqueda semántica.</p><p>Sin embargo, aunque <code>semantic_text</code> proporciona rapidez y simplicidad, este enfoque tiene algunas limitaciones. Permite el uso de modelos estándar de mercado, siempre que estén disponibles como puntos finales de inferencia en Elasticsearch. Pero <strong>no soporta incrustaciones generadas externamente</strong>, como es posible con el campo <code>dense_vector</code> .</p><p>Si necesitas más control sobre cómo se generan los vectores, quieres usar tus propios embeddings o necesitas combinar varios campos para estrategias avanzadas, los campos <code>dense_vector</code> y <code>sparse_vector</code> ofrecen la flexibilidad necesaria para escenarios más personalizados o específicos de dominio.</p><h3>Cómo usar la consulta para el tipo de texto semántico</h3><p>Antes de <strong><code>semantic_text</code></strong>, era necesario usar una consulta diferente según el tipo de incrustación (densa o dispersa). Se empleaba una consulta <code>sparse_vector</code> para campos dispersos, mientras que <code>dense_vector</code> campos requerían consultas KNN.</p><p>Con el tipo de texto semántico, la búsqueda se realiza usando la <a href="https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-semantic-query">consulta semántica</a>, que genera automáticamente el vector de consulta y lo compara con las incrustaciones de los documentos indexados. El tipo <strong><code>semantic_text</code></strong> permite definir un extremo de inferencia para incrustar la consulta, pero si no se especifica ninguno, se aplicará el mismo punto final que se usa durante la indexación a la consulta.</p>{
  "query": {
    "semantic": {
      "field": "semantic_text_field",
      "query": "search text"
    }
  }
}<p>Para saber más, te sugiero leer el artículo <a href="https://www.elastic.co/search-labs/blog/semantic-search-simplified-semantic-text">Elasticsearch nueva semantic_text mapeo: Simplificando la búsqueda semántica</a>.</p><h2>Conclusión</h2><p>Al elegir cómo mapear incrustaciones en Elasticsearch, es esencial entender cómo quieres generar los vectores y qué nivel de control necesitas sobre ellos. Si buscas simplicidad, el campo de texto semántico permite una búsqueda semántica automática y escalable, lo que lo hace ideal para muchos casos de uso iniciales. Cuando se requiere más control, un rendimiento ajustado o integración con modelos personalizados, los campos vectoriales densos y dispersos proporcionan la flexibilidad necesaria.</p><p>El tipo de campo ideal depende de tu caso de uso, la infraestructura disponible y la madurez de tu pila de aprendizaje automático. Lo más importante es que Elastic ofrece las herramientas para construir sistemas de búsqueda modernos y altamente adaptables.</p><h2>Referencias</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 vectorial disperso</a></p></li><li><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/dense-vector.html">Tipo de campo vectorial 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 vectorial dispersa</a></p></li><li><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/knn-search.html">Búsqueda kNN</a></p></li><li><p><a href="https://www.elastic.co/search-labs/blog/semantic-search-simplified-semantic-text">Mapeado de nuevas semantic_text de Elasticsearch: Simplificación de la búsqueda semántica</a></p></li><li><p><a href="https://www.elastic.co/search-labs/blog/sparse-vector-embedding">Comprendiendo las incrustaciones de vectores dispersos con modelos de aprendizaje automático capacitados</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[Base de datos vectorial]]></category>
    <category><![CDATA[Mapeos]]></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[Generación de filtros y facetas usando ML]]></title>
    <description><![CDATA[Explorando los pros y contras de automatizar la creación de filtros y facetas en una experiencia de búsqueda usando modelos de aprendizaje automático frente al enfoque tradicional codificado de forma dura.]]></description>
    <content:encoded><![CDATA[<p>Los filtros y facetas son mecanismos empleados para refinar los resultados de búsqueda, ayudando a los usuarios a encontrar contenido o productos relevantes más rápidamente. En el enfoque tradicional, las reglas se definen manualmente. Por ejemplo, en un catálogo de películas, atributos como el género están predefinidos para su uso en filtros y facetas. Por otro lado, con los modelos de IA, se pueden extraer automáticamente nuevos atributos de las características de las películas, haciendo el proceso más dinámico y personalizado. En este blog, exploramos los pros y los contras de cada método, destacando sus aplicaciones y desafíos.</p><h2>Filtros vs facetas</h2><p>Antes de empezar, definamos qué son los filtros y las facetas. <strong>Los filtros</strong> son atributos predefinidos que se emplean para restringir un conjunto de resultados. En un mercado, por ejemplo, los filtros están disponibles incluso antes de que se realice una búsqueda. El usuario puede seleccionar una categoría, como <strong>"Juegos de video",</strong> antes de buscar <strong>"PS5",</strong> refinando la búsqueda a un subconjunto más específico en lugar de a toda la base de datos. Esto aumenta significativamente las posibilidades de obtener resultados más relevantes.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0a77b38aae238938/6a170b821949f72a52e7aa51/5ed8868fa5017d034e1273e35c884a5430afdf3c-1600x937.png" alt="Filtros" /><p><strong>Las facetas</strong> funcionan de forma similar a los filtros, pero solo están disponibles luego de realizar la búsqueda. En otras palabras, la búsqueda devuelve resultados y, a partir de ellos, se genera una nueva lista de opciones de refinamiento. Por ejemplo, al buscar una consola PS5, pueden mostrar aspectos como <strong>la capacidad</strong> de almacenamiento, <strong>el costo de envío</strong> y <strong>el color</strong> para ayudar a los usuarios a elegir el producto ideal.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt166e356b80d423ef/6a170b840e2e494ca341a10f/c5633fcc5b6fbb916110faf32144d8d43572e33a-1600x937.png" alt="Facetas " /><p>Ahora que definimos filtros y facetas, hablemos del impacto de los enfoques tradicionales y basados en Aprendizaje Automático (ML) en su implementación y uso. Cada método tiene beneficios y desafíos que influyen en la eficiencia de búsqueda.</p><h2>Enfoque tradicional de filtros y facetas</h2><p>En este enfoque, los filtros y facetas se definen manualmente basar en reglas predefinidas. Esto significa que los atributos disponibles para perfeccionar la búsqueda están fijos y planeados con antelación, teniendo en cuenta la estructura del catálogo y las necesidades del usuario.</p><p>Por ejemplo, en un mercado, categorías como "Electrónica" o "Moda" pueden tener filtros específicos como marca, formato y rango de precio. Estas reglas se crean de forma estática, garantizando la coherencia en la experiencia de búsqueda pero requiriendo ajustes manuales cada vez que surgen nuevos productos o categorías.</p><p>Aunque este enfoque proporciona previsibilidad y control sobre los filtros y facetas mostrados, puede ver limitado cuando surgen nuevas tendencias que exigen refinamiento dinámico.</p><p><strong>Pros:</strong></p><ul><li><p><strong>Previsibilidad y control:</strong> Como los filtros y facetas se definen manualmente, la gestión se vuelve más sencilla.</p></li><li><p><strong>Baja complejidad:</strong> No hace falta capacitar modelos.</p></li><li><p><strong>Facilidad de mantenimiento:</strong> Como las reglas están predefinidas, se pueden hacer ajustes y correcciones rápidamente.</p></li></ul><p><strong>Contras</strong>:</p><ul><li><p><strong>Reindexación necesaria para nuevos filtros:</strong> Cada vez que un nuevo atributo necesita usar como filtro, todo el conjunto de datos debe reindexar para cerciorar que los documentos contengan esta información.</p></li><li><p><strong>Falta de adaptación dinámica:</strong> Los filtros son estáticos y no se ajustan automáticamente a los cambios en el comportamiento del usuario.</p></li></ul><h3>Implementación de filtros/facetas – Enfoque tradicional</h3><p>En <strong>Dev Tools, Kibana</strong>, crearemos una demostración de filtros/facetas usando el <strong>enfoque tradicional</strong>.</p><p>Primero, definimos la asignación para estructurar el índice:</p>PUT videogames
{
  "mappings": {
    "properties": {
      "name": { "type": "text" },
      "brand": { "type": "keyword" },
      "storage": { "type": "keyword" },
      "price": { "type": "float" },
      "description": { "type": "text" }
    }
  }
}<p>Los campos <strong>de marca</strong> y <strong>almacenamiento</strong> se establecen como <strong>palabra clave</strong>, lo que permite usarlos directamente en agregaciones (<strong>facetas</strong>). El campo <strong>de precios</strong> es de tipo <strong>float</strong>, lo que permite la creación de <strong>rangos de precio</strong>.</p><p>En el siguiente paso, los datos del producto se indexarán:</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>Ahora, recuperemos los aspectos tradicionales agrupando los resultados por marca, almacenamiento y rango de precio. En la consulta, se definió size:0. En este escenario, el objetivo es recuperar solo los resultados de la agregación sin incluir los documentos correspondientes a la 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>La respuesta incluirá recuentos para <strong>Marca</strong>, <strong>Almacenamiento</strong> y <strong>Precio</strong>, ayudando a crear filtros y facetas.</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>Machine learning y enfoque basado en IA para filtros y facetas</h2><p>En este enfoque, los modelos de Aprendizaje Automático (ML), incluidas las técnicas de Inteligencia Artificial (IA), analizan atributos de datos para generar filtros y facetas relevantes. En lugar de depender de reglas predefinidas, ML/IA aprovecha características de datos indexados. Esto permite el descubrimiento dinámico de nuevas facetas y filtros.</p><p><strong>Beneficios</strong>:</p><ul><li><p><strong>Actualizaciones automáticas:</strong> Se generan automáticamente nuevos filtros y facetas, sin necesidad de ajustes manuales.</p></li><li><p><strong>Descubrimiento de nuevos atributos:</strong> Puede identificar características de datos <strong>previamente no consideradas </strong>como filtros, enriqueciendo la experiencia de búsqueda.</p></li><li><p><strong>Reducción del esfuerzo manual:</strong> El equipo no necesita definir y actualizar constantemente las reglas de filtrado mientras la IA aprende de los datos disponibles.</p></li></ul><p><strong>Contras:</strong></p><ul><li><p><strong>Complejidad del mantenimiento:</strong> El uso de modelos puede requerir una pre-validación para cerciorar la consistencia de los filtros generados.</p></li><li><p><strong>Requiere conocimientos en ML e IA:</strong> La solución requiere profesionales cualificados para afinar y monitorizar el rendimiento del modelo.</p></li><li><p><strong>Riesgo de filtros irrelevantes:</strong> Si el modelo no está bien calibrado, puede generar facetas que no son útiles para los usuarios.</p></li><li><p><strong>Costar:</strong> El uso de aprendizaje automático e inteligencia artificial puede requerir servicios de terceros, aumentando los costos operativos.</p></li></ul><p>Cabe destacar que, incluso con un modelo bien calibrado y un prompt bien elaborado, los aspectos generados deberían pasar por un paso de revisión. Esta validación puede ser manual o basar en normas de moderación, cerciorando que el contenido sea adecuado y seguro. Aunque no necesariamente supone un inconveniente, es importante cerciorar la calidad e idoneidad de los aspectos antes de que estén disponibles para los usuarios.</p><h3>Implementación de filtros/facetas – enfoque de IA</h3><p>En esta demostración, emplearemos un modelo de IA para analizar automáticamente las características del producto y sugerir atributos relevantes. Con un prompt bien estructurado, extraemos información del catálogo y la transformamos en filtros y facetas. A continuación, presentamos cada paso del proceso.</p><p>Inicialmente, emplearemos la <strong>API de Inferencia</strong> para registrar un endpoint para su integración con un servicio de ML. A continuación se muestra un ejemplo de integración con <strong>el servicio de OpenAI</strong>.</p>PUT _inference/completion/generate_filter_ia
{
   "service": "openai",
   "service_settings": {
       "api_key": "your-key",
       "model_id": "gpt-4o-mini"
   }
}<p>Ahora, definimos la tubería para ejecutar el prompt y obtener los nuevos filtros generados por el 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>Ejecutando una simulación de esta tubería para el producto "PlayStation 5", con la siguiente descripción:</p><p><em>Juegos impresionantes: Maravíllate con unos gráficos impresionantes y disfruta de las características de la nueva PS5.</em></p><p><em>Inmersión impresionante: Descubre una experiencia de juego más profunda con soporte para retroalimentación háptica, disparadores adaptativos y tecnología de audio 3D.</em></p><p><em>Diseño Slim: Con la Edición Digital PS5, los jugadores cuentan con una tecnología de juego poderoso en un diseño elegante y compacto.</em></p><p><em>1TB de almacenamiento: Ten tus juegos favoritos listos y esperando para jugar con 1TB de almacenamiento SSD integrado.</em></p><p><em>Retrocompatibilidad y mejora del juego: La consola PS5 puede reproducir más de 4.000 juegos de PS4. Con Game Boost, incluso puedes disfrutar de tasas de fotogramas más rápidas y fluidas en algunos de los mejores juegos de consola de PS4.</em></p><p>Observemos la salida de prompt generada por esta simulación.</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>Ahora se agregará un nuevo campo, <strong>dynamic_facets</strong>, al nuevo índice para almacenar las facetas generadas por la 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>Usando la <strong>API Reindex</strong>, reindexaremos el índice <strong>de juegos de video</strong> a <strong>videogames_1</strong>, aplicando la <strong>generate_filter_ai</strong> pipeline durante el proceso. Esta tubería generará automáticamente facetas dinámicas durante la indexación.</p>POST _reindex?wait_for_completion=false
{
 "source": {
   "index": "videogames"
 },
 "dest": {
   "index": "videogames_1",
   "pipeline": "generate_filter_ai"
 }
}<p>Ahora, haremos una búsqueda y obtendremos los nuevos 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 la implementación de las facetas, a continuación se muestra una interfaz sencilla:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb0d6aa40caf7a91a/6a170b86ab7f0839afdb9eb6/12b6d9d4f4d0985848d92841545fd22b7253ae6d-1600x1288.png" alt="Implementación de las facetas" /><p>El código de la interfaz que se presenta <a href="https://gist.github.com/andreluiz1987/06d9ec1b381e942e9def0e969bd811a0">está aquí</a>.</p><h2>Conclusión</h2><p>Ambos enfoques para crear filtros y facetas tienen sus beneficios y puntos de preocupación. El enfoque tradicional, basado en reglas manuales, ofrece control y costos más bajos, pero requiere actualizaciones constantes y no se adapta dinámicamente a nuevos productos o funcionalidades.</p><p>Por otro lado, el enfoque basado en IA y Aprendizaje Automático automatiza la extracción de facetas, haciendo la búsqueda más flexible y permitiendo el descubrimiento de nuevos atributos sin intervención manual. Sin embargo, este enfoque puede ser más complejo de implementar y mantener, requiriendo calibración para garantizar resultados consistentes.</p><p>La elección entre los enfoques tradicionales y basados en IA depende de las necesidades y la complejidad del negocio. Para escenarios más simples, donde los atributos de los datos son estables y previsibles, el enfoque tradicional puede ser más eficiente y fácil de mantener, evitando costos innecesarios con infraestructuras y modelos de IA. Por otro lado, el uso de ML/IA para extraer facetas puede aportar un valor significativo, mejorando la experiencia de búsqueda y haciendo que el filtrado sea más inteligente.</p><p>Lo importante es evaluar si la automatización justifica la inversión o si una solución más tradicional ya satisface eficazmente las necesidades del negocio.</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[Relevancia]]></category>
    <category><![CDATA[Investigación en ML]]></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[Uso de modelos Amazon Nova en Elasticsearch]]></title>
    <description><![CDATA[Aprende a usar los modelos Amazon Nova en Elasticsearch para extraer automáticamente el sentimiento, la autenticidad, los resúmenes y las palabras clave de las reseñas de productos en Elasticsearch.]]></description>
    <content:encoded><![CDATA[<p>En este artículo, hablaremos sobre la familia de modelos de IA de Amazon, Amazon Nova, y aprenderemos a emplearla junto con Elasticsearch.</p><h2>Acerca de Amazon Nova</h2><p>Amazon Nova es una familia de modelos de inteligencia artificial de Amazon, disponibles en Amazon Bedrock y diseñados para ofrecer alto rendimiento y eficiencia en costos. Estos modelos funcionan con entradas de texto, imagen y video, generan salidas textuales y están optimizados para diferentes necesidades de precisión, velocidad y costo.</p><h3>Modelos principales de Amazon Nova</h3><ul><li><p>Amazon Nova Micro: Centrado exclusivamente en texto, es un modelo rápido y rentable, ideal para traducción, razonamiento, completación de código y resolución de problemas matemáticos. Su generación supera los 200 tokens por segundo, lo que la hace ideal para aplicaciones que requieren respuestas instantáneas.</p></li><li><p>Amazon Nova Lite: un modelo multimodal de bajo costo capaz de procesar rápidamente imágenes, vídeos y texto. Destaca por su velocidad y precisión, siendo adecuado para aplicaciones interactivas y de gran volumen donde el costo es un factor relevante.</p></li><li><p>Amazon Nova Pro: La opción más avanzada, que combina alta precisión, velocidad y eficiencia de costos. Ideal para tareas complejas como resumen en video, preguntas frecuentes, desarrollo de software y agentes de IA. Las reseñas de expertos atestiguan su excelencia en comprensión textual y visual, así como su capacidad para seguir instrucciones y ejecutar flujos de trabajo automatizados.</p></li></ul><p>Los modelos Amazon Nova son adecuados para una variedad de aplicaciones, desde la creación de contenido y análisis de datos hasta el desarrollo de software y la automatización de procesos impulsada por IA.</p><p>A continuación, demostraremos cómo emplear los modelos Amazon Nova junto con Elasticsearch para un análisis automatizado de reseñas de productos.</p><p>Lo que haremos:</p><ol><li><p>Crea un endpoint mediante Inference API, integrando Amazon Bedrock con Elasticsearch.</p></li><li><p>Crea una tubería usando el Procesador de Inferencia, que hará llamadas al endpoint de la API de Inferencia.</p></li><li><p>Indexa las reseñas de productos y genera automáticamente un análisis de las reseñas usando la canalización.</p></li><li><p>Analiza los resultados de la integración.</p></li></ol><h2>Creando un endpoint en la API de inferencia con Amazon Nova Lite</h2><p>Primero, configuramos la API de Inference para integrar Amazon Bedrock con Elasticsearch. Definimos Amazon Nova Lite, id <strong>amazon.nova-lite-v1:0</strong>, como modelo a usar, ya que ofrece un equilibrio entre velocidad, precisión y costo.</p><p><strong>Nota:</strong> Necesitarás credenciales válidas para usar Amazon Bedrock. Puedes consultar la documentación para obtener claves <a href="https://docs.aws.amazon.com/keyspaces/latest/devguide/create.keypair.html">de acceso aquí</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>Creación de la cadena de análisis de revisiones</h2><p>Ahora, creamos una cadena de procesamiento que empleará el Procesador de Inferencia para ejecutar una indicación de análisis de revisión. Este prompt enviará los datos de la reseña a Amazon Nova Lite, que realizará:</p><ul><li><p>Clasificación de sentimiento (positivo, negativo o neutral).</p></li><li><p>Resumen de la reseña.</p></li><li><p>Generación de palabras clave.</p></li><li><p>Medición de autenticidad (auténtica | sospechosa | genérica).</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>Reseñas de indexación</h2><p>Ahora, indexamos las reseñas de productos usando la API Bulk. La tubería creada anteriormente se aplicará automáticamente, agregando el análisis generado por el modelo Nova a los 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>Consulta y análisis de los resultados</h2><p>Finalmente, realizamos una consulta para ver cómo el modelo Amazon Nova Lite analiza y clasifica las reseñas. Al ejecutar productos/_search GET, obtenemos los documentos ya enriquecidos con los campos generados a partir del contenido de la revisión.</p><p>El modelo identifica el sentimiento predominante (positivo, neutral o negativo), genera resúmenes concisos, extrae palabras clave relevantes y estima la autenticidad de cada revisión. Estos campos ayudan a entender la opinión del cliente sin necesidad de leer el texto completo.</p><p>Para interpretar los resultados, analizamos:</p><ul><li><p>Sentimiento, que indica la percepción general que el consumidor tiene del producto.</p></li><li><p>El resumen, que destaca los puntos principales mencionados.</p></li><li><p>Palabras clave, que pueden usar para agrupar opiniones similares o identificar patrones de retroalimentación.</p></li><li><p>Autenticidad, que indica si la reseña parece fiable. Esto es útil para la curación o la moderación.</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>Reflexiones finales</h2><p>La integración entre Amazon Nova Lite y Elasticsearch demostró cómo los modelos de lenguaje pueden transformar las reseñas en bruto en información estructurada y valiosa. Al procesar las reseñas a través de una canalización, pudimos extraer el sentimiento, la autenticidad, los resúmenes y las palabras clave de forma automática y consistente.</p><p>Los resultados muestran que el modelo puede comprender el contexto de las reseñas, clasificar las opiniones de los usuarios y destacar los puntos más relevantes de cada experiencia. Esto crea un conjunto de datos mucho más rico que puede aprovechar para mejorar las capacidades de búsqueda.</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[Cómo automatizar sinónimos y subir usando nuestra API de Sinónimos]]></title>
    <description><![CDATA[Descubre cómo los LLMs pueden usar para identificar y generar sinónimos automáticamente, permitiendo que los términos se carguen programáticamente en la API de sinónimos de Elasticsearch.]]></description>
    <content:encoded><![CDATA[<p>Mejorar la calidad de los resultados de búsqueda es esencial para ofrecer una experiencia de usuario eficiente. Una forma de optimizar las búsquedas es expandiendo automáticamente los términos consultados mediante sinónimos. Esto permite interpretar las consultas de forma más amplia, cubriendo variaciones lingüísticas y así mejorando la coincidencia de resultados.</p><p>Este blog explora cómo los grandes modelos de lenguaje (LLMs) pueden usar para identificar y generar sinónimos automáticamente, permitiendo que estos términos se carguen programáticamente en la API de sinónimos de Elasticsearch.</p><h2>¿Cuándo usar sinónimos?</h2><p>El uso de sinónimos puede ser una solución más rápida y rentable en comparación con la búsqueda vectorial. Su implementación es más sencilla ya que no requiere un conocimiento profundo de embeddings ni un proceso complejo de ingestión vectorial.</p><p>Además, el consumo de recursos es menor, ya que la búsqueda vectorial exige mayor capacidad de almacenamiento y memoria para incrustar, indexar y recuperar.</p><p>Otro aspecto importante es la regionalización de la búsqueda. Con los sinónimos, es posible adaptar términos según el idioma y las costumbres locales. Esto es útil en situaciones donde las incrustaciones pueden no coincidir con expresiones regionales o términos específicos de cada país. Por ejemplo, algunas palabras o siglas pueden tener significados diferentes según la región, pero los usuarios locales los tratan naturalmente como sinónimos. En Brasil, esto es bastante común. "Abacaxi" y "ananás" son la misma fruta (piña), pero el segundo término se usa más comúnmente en algunas regiones del noreste. De manera similar, el conocido "pão francês" en el sudeste puede ser conocido como "pão careca" en el noreste.</p><h2>¿Cómo usar los LLMs para generar sinónimos?</h2><p>Para obtener sinónimos automáticamente, podemos usar LLMs, que analizan el contexto de un término y sugieren variaciones apropiadas. Este enfoque permite expandir dinámicamente los sinónimos, cerciorando una búsqueda más amplia y precisa sin depender de un diccionario fijo.</p><p>En esta demostración, emplearemos un LLM para generar sinónimos de productos de comercio electrónico. Muchas búsquedas demuestran pocos o ningún resultado debido a las variaciones en los términos consultados. Con sinónimos, podemos resolver este problema. Por ejemplo, una búsqueda de "smartphone" puede abarcar diferentes modelos de teléfonos móviles, cerciorando que los usuarios encuentren los productos que buscan.</p><h3>Prerrequisitos</h3><p>Antes de empezar, necesitamos configurar el entorno y definir las dependencias necesarias. Emplearemos la solución proporcionada por Elastic para <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/run-elasticsearch-locally.html">ejecutar Elasticsearch y Kibana localmente en Docker</a>. El código estará escrito en Python, v3.9.6, con las siguientes dependencias:</p>pip install openai==1.59.8 elasticsearch==8.15.1<h3>Creación del índice de productos</h3><p>Inicialmente, crearemos un índice de productos sin soporte de sinónimos. Esto nos permitirá validar consultas y luego compararlas con un índice que incluya sinónimos.</p><p>Para crear el índice, cargamos en masa un conjunto de datos de producto usando el siguiente comando en 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>Generación de sinónimos con LLM</h3><p>En este paso, emplearemos un LLM para generar sinónimos dinámicamente. Para lograrlo, integraremos la API de OpenAI, definiendo un modelo y un prompt apropiados. El LLM recibirá la categoría y el nombre del producto, cerciorando que los sinónimos sean relevantes en el contexto.</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 del índice de productos creados, recuperaremos todos los artículos de la categoría "Electrónica" y enviaremos sus nombres al LLM. La salida esperada será algo así:</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>Con los sinónimos generados, podemos registrarlos en Elasticsearch usando la API de Sinónimos.</p><h3>Gestión de sinónimos con la API de Sinónimos</h3><p>La API de Sinónimos proporciona una forma eficiente de gestionar conjuntos de sinónimos directamente dentro del sistema. Cada conjunto de sinónimos consiste en reglas de sinónimos, donde un grupo de palabras se considera equivalente en las búsquedas.</p><p><strong>Ejemplo de creación de un conjunto de sinónimos</strong></p>PUT _synonyms/my-synonyms-set
{
  "synonyms_set": [
    {
      "id": "rule-1",
      "synonyms": "hello, hi"
    },
    {
      "synonyms": "bye, goodbye"
    }
  ]
}<p>
Esto crea un conjunto llamado "mis-sinónimos-conjunto", donde "hola" y "hola" se tratan como equivalentes, así como "adiós" y "adiós".</p><h2>Implementación de la creación de sinónimos para el catálogo de productos</h2><p>A continuación se muestra el método responsable de construir un conjunto de sinónimos e insertarlo en Elasticsearch. Las reglas de sinónimos se generan a partir del mapeo de sinónimos sugerido por el LLM. Cada regla tiene un ID, correspondiente al nombre del producto en formato slug, y a la lista de sinónimos calculada por el 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 continuación se muestra la carga útil de la solicitud para crear el 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>Con el conjunto de sinónimos creado en el clúster, podemos pasar al siguiente paso, que es crear un nuevo índice con soporte de sinónimos usando el conjunto definido.</p><p>El código completo en Python con los sinónimos generados por LLM y la creación de conjuntos de sinónimos definida por la API de Sinónimos es el siguiente:</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>Creación de un índice con soporte de sinónimos</h3><p>Se creará un nuevo índice donde todos los datos del índice de <code>products</code> serán reindexados. Este índice usará la <code>synonyms_filter</code>, que aplica la <code>products-synonyms-set</code> creada anteriormente.</p><p>A continuación se muestra el mapeo de índices 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 el índice de <code>products</code></h3><p>Ahora, usaremos la <strong>API Reindex</strong> para migrar los datos del índice de <code>products</code> al nuevo índice de <code>products_02</code> , que incluye soporte para sinónimos. El siguiente código se ejecutó en Kibana DevTools:
</p>POST _reindex
{
  "source": {
    "index": "products"
  },
  "dest": {
    "index": "products_02"
  }
}<p>Tras la migración, el índice de <code>products_02</code> estará llenado y listo para validar búsquedas usando el conjunto de sinónimos configurado.</p><h3>Validación de la búsqueda con sinónimos</h3><p>Comparemos los resultados de búsqueda entre los dos índices. Ejecutaremos la misma consulta en ambos índices y validaremos si los sinónimos se están empleando para obtener resultados.</p><h4>Buscar en el índice de <code>products</code> (sin sinónimos)</h4><p>Emplearemos a Kibana para realizar búsquedas y analizar los resultados. En el menú de Analítica &gt; Descubrimiento, crearemos una Vista de Datos para visualizar los datos de los índices que creamos.</p><p>Dentro de Discovery, haz clic en Vista de datos y define un nombre y un patrón de índice. Para el índice de "<strong>productos</strong>", usaremos el patrón de "<strong>productos</strong>". Luego, repetiremos el proceso para crear una nueva Vista de Datos para el índice "<strong>products_02</strong>", usando el patrón "<strong>products_02".</strong></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte826fd932cfeb9df/6a17fdffec0f8912aa5a6841/3ad4a6891a3905e96532a312932fdf3a8216aec2-1600x599.png" alt="" /><p>Con las Vistas de Datos configuradas, podemos volver a Analytics &gt; Discovery y comenzar las validaciones.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltba3729c60068e8a0/6a17fe01e9ea87ba2aa9c82a/422c4b2b51abae6580cad25085d1b8a365fc6b9e-1294x850.png" alt="" /><p>Aquí, tras seleccionar productos DataView y buscar el término "tablet", no obtenemos resultados, aunque sabemos que existen productos como "Kindle Paperwhite" y "Apple iPad Air".</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2c6a383dd4cb0157/6a17fe02577262671d1bce0c/e4ae3a785fdd93f48d7c7d204185ded149126f2c-1600x862.png" alt="" /><h4>Buscar en el índice de <code>products_02</code> (sinónimos de soporte)</h4><p>Al realizar la misma consulta en la Vista de Datos "<strong>products_synonyms</strong>", que soporta sinónimos, los productos se recuperaron con éxito. Esto demuestra que el conjunto de sinónimos configurado funciona correctamente, cerciorando que diferentes variaciones de los términos buscados devuelvan los resultados esperados.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt986b4706e2f70014/6a17fe043e9e454edbba16d3/e609749c39e90d5c82fa846af6124679dd62bcb8-1600x526.png" alt="" /><p>Podemos lograr el mismo resultado ejecutando la misma consulta directamente en Kibana DevTools. Simplemente busca en el índice de products_02 usando la API de búsqueda de Elasticsearch:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltbe829a3c4d7aac60/6a17fe05e8fbce03d73a1bd7/504d0d1f96dcfbceb309063dc0716bcee64ad2f8-1600x870.png" alt="" /><h2>Conclusión</h2><p>La implementación de sinónimos en Elasticsearch mejoró la precisión y cobertura de las búsquedas en catálogos de productos. El diferenciador clave era el uso de un <strong>LLM</strong>, que generaba sinónimos automáticamente y contextualmente, eliminando la necesidad de listas predefinidas. El modelo analizó nombres y categorías de productos, cerciorando sinónimos relevantes para el comercio electrónico.</p><p>Además, la <strong>API de Sinónimos</strong> simplificó la gestión de diccionarios, permitiendo modificar dinámicamente los conjuntos de sinónimos. Con este enfoque, la búsqueda se volvió más flexible y adaptable a diferentes patrones de consulta de usuario.</p><p>Este proceso puede mejorar continuamente con nuevos datos y ajustes de modelos, cerciorando una experiencia de investigación cada vez más eficiente.</p><h2>Referencias</h2><p><strong>Ejecuta 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>Sinónimos API</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[Relevancia]]></category>
    <category><![CDATA[Conceptos básicos]]></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[Cómo ingerir datos a través de Airbyte en Elasticsearch]]></title>
    <description><![CDATA[Usar Airbyte para ingir datos en Elasticsearch. Cubriremos los requisitos previos, la configuración de Airbyte y la integración paso a paso.]]></description>
    <content:encoded><![CDATA[<p>Airbyte es una herramienta de integración de datos que permite mover información de diversas fuentes a diferentes destinos de forma automatizada y escalable. Te permite extraer datos de APIs, bases de datos y otros sistemas y cargarlos en plataformas como Elasticsearch, que ofrece búsqueda avanzada y análisis eficiente.</p><p>En este artículo, explicaremos cómo configurar Airbyte para que insienta datos en Elasticsearch, cubriendo conceptos clave, requisitos previos y la integración paso a paso.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt99eabff95c587c00/6a17e300e8fbce2d303a18a9/ea7af907dfd4c0b7e8673164467ee236623282d2-1360x802.png" alt="Configura Airbyte para que ingira datos en Elasticsearch" /><h2>Conceptos fundamentales de Airbyte</h2><p>Airbyte tiene varios conceptos esenciales para su uso. A continuación, destacamos los principales:</p><ul><li><p>Fuentes: Define el origen de los datos que se extraerá.</p></li><li><p>Destinos: Define dónde se enviarán y almacenarán los datos.</p></li><li><p>Conexiones: Configura la relación entre la fuente y el destino, incluyendo la frecuencia de sincronización.</p></li></ul><h2>Integración de Airbyte con Elasticsearch</h2><p>En esta demostración, realizaremos una integración en la que los datos almacenados en un cubo S3 serán migrados a un índice Elasticsearch. Mostraremos cómo configurar el código fuente (S3) y el destino (Elasticsearch) en Airbyte.</p><h3>Prerrequisitos</h3><p>Para seguir a esta demostración, deben cumplir los siguientes requisitos:</p><ol><li><p>Crea un cubo en AWS, donde se almacenarán los archivos JSON que contienen los datos.</p></li><li><p><a href="https://docs.airbyte.com/using-airbyte/getting-started/oss-quickstart">Instala Airbyte localmente</a> usando Docker.</p></li><li><p>Crea un clúster de Elasticsearch en Elastic Cloud para almacenar los datos ingeridos.</p></li></ol><p>A continuación, detallaremos cada uno de estos pasos.</p><h4>Instalación de Airbyte</h4><p>Airbyte puede ejecutar localmente usando Docker o en la nube, donde existen costos asociados al uso. Para esta demostración, usaremos la versión local con Docker.</p><p>La instalación puede tardar unos minutos. Tras seguir las instrucciones de instalación, Airbyte estará disponible en: http://localhost:8000.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0f9149be887b5500/6a17e302abe0f2b1c6dfe956/66147b5121413ad9baecb10c6886288e917f7c09-1600x1102.png" alt="Instalación de Airbyte" /><p></p><p>Luego de iniciar sesión, podemos empezar a configurar la integración.</p><h4>Creación del cubo</h4><p>En este paso, necesitarás una cuenta de AWS para crear un bucket S3. Además, es esencial establecer las licencias correctas creando una política y un usuario IAM para permitir el acceso al cubo.</p><p>En el bucket, subiremos archivos JSON que contengan diferentes registros de log, que luego serán migrados a Elasticsearch. Los registros de archivos contienen este contenido:</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>A continuación están los archivos cargados en el cubo:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltbf769c5e9bdb5dfe/6a17e3043e9e45a360ba13f7/f3e7f5889002e3a804121a880d97f1d93044e2f7-1600x680.png" alt="Archivos cargados en el cubo en Airbyte" /><h4>Configuración de la nube elástica</h4><p>Para facilitar la demostración, usaremos Elastic Cloud. Si aún no tienes cuenta, puedes crear una cuenta de prueba gratis aquí: <a href="https://cloud.elastic.co/registration">Elastic Cloud Registration</a>.</p><p>Luego de configurar el despliegue en Elastic Cloud, necesitarás obtener:</p><ul><li><p>La URL del servidor Elasticsearch.</p></li><li><p>Un usuario para acceder a Elasticsearch.</p></li></ul><p>Para obtener la URL, ve a Despliegues &gt; Mi despliegue, en la aplicación, busca Elasticsearch y haz clic en 'Copiar el punto final'.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltddfaaf863168e2bb/6a17e305faa913e29793c7e4/2e38c0bfb2cea83d9ef90dba0e673559fe358199-1368x1056.png" alt="Configuración de la nube elástica" /><p>Para crear el usuario, sigue los pasos a continuación:</p><ol><li><p>Accede a Kibana &gt; Stack Management &gt; usuarios.</p></li><li><p>Crea un nuevo usuario con el rol de superusuario.</p></li><li><p>Diligencia el espacio para crear al usuario.</p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltca15b0d3084f4c67/6a17e3073e9e4507e2ba13fb/54d098805087a2d60772475cbb31784083a38c25-1600x1026.png" alt="Creación de usuarios en Elastic Cloud" /><p>Ahora que lo tenemos todo listo, podemos empezar a configurar los conectores en Airbyte.</p><h3>Configuración del conector fuente</h3><p>En este paso, crearemos el conector fuente para S3. Para ello, accederemos a la interfaz de Airbyte y seleccionaremos la opción Fuente en el menú. Luego, buscaremos el conector S3. A continuación, detallamos los pasos necesarios para configurar el conector:</p><ol><li><p>Accede a Airbyte y ve al menú de Fuentes.</p></li><li><p>Busca y selecciona el conector S3.</p></li><li><p>Configura los siguientes parámetros:</p><ol><li><p>Nombre de la fuente: Define un nombre para la fuente de datos.</p></li><li><p>Método de entrega: Seleccionar Réplica de Registros (recomendado para datos estructurados).</p></li><li><p>Formato de datos: Elige formato JSON.</p></li><li><p>Nombre del flujo: Define el nombre del índice en Elasticsearch.</p></li><li><p>Nombre del cubo: Introduce el nombre del cubo en AWS.</p></li><li><p>Clave de acceso de AWS y clave secreta de AWS: Introduce las credenciales de acceso.</p></li></ol></li></ol><p>Haz clic en Configurar código fuente y espera la validación.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdca1fb8d8f5d034f/6a17e30963baff75bc741bb2/f83566ab5ebad07ad9fd61dc20353ca5a95c8c92-1600x1099.png" alt="Esperar la validación para la ingestión de datos de Airbyte y Elasticsearch" /><h3>Conector de destino de configuración</h3><p>En este paso, configuraremos el conector de destino, que será Elasticsearch. Para ello, accederemos al menú y seleccionaremos la opción Destino. Luego, buscaremos Elasticsearch y haremos clic en el resultado que devolvemos. Ahora, procederemos con la configuración de esta conexión:</p><ol><li><p>Accede a Airbyte y ve al menú de Destinos.</p></li><li><p>Busca y selecciona el conector Elasticsearch.</p></li><li><p>Configura los siguientes parámetros:</p><ol><li><p>Método de autenticación: Elige nombre de usuario/contraseña.</p></li><li><p>Nombre de usuario y contraseña: Emplea las credenciales creadas en Kibana.</p></li><li><p>Endpoint del servidor: Pega la URL copiada de Elastic Cloud.</p></li></ol></li></ol><p>Haz clic en <strong>Configurar destino</strong> y espera la validación.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt72056179d048e027/6a17e30b033c8d5d9d6bb115/f9246b54cc77e0589c0bf658ffc274fd28f766d5-1600x941.png" alt="Crear un destino en Elastic Cloud para la ingesta de datos de Airbyte" /><h3>Creación de la conexión de origen y destino</h3><p>Una vez creada la Fuente y el Destino, se creará la conexión entre ellos, completando así la creación de la integración. </p><p>A continuación se muestran las instrucciones para crear la conexión:</p><p>1. En el menú, ve a Conexiones y haz clic en Crear Primera Conexión.</p><p>2. En la siguiente pantalla, podrás seleccionar una Fuente existente o crear una nueva. Como ya tenemos una Fuente creada, seleccionaremos la Fuente S3.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc7f1e01215a7a328/6a17e30c63baff53d7741bb6/14937ccb2686bbde7cb99ffe7e13f7f4e35d7a31-1600x393.png" alt="Selecciona una fuente existente o crea una nueva en Airbyte" /><p>3. El siguiente paso será seleccionar el destino. Como ya creamos el conector Elasticsearch, se seleccionará para finalizar la configuración.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltece5c720f28eee00/6a17e30d505ac3dc68ad8aa3/d10962bc175f9ce0b2745ea913d739d3c40ba3b6-1600x431.png" alt="Selecciona el destino en Airbyte" /><p>En el siguiente paso, será necesario definir el Modo de Sincronización y qué esquema se empleará. Como solo se creó el esquema de registro, será la única opción disponible para la selección.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7cbcccad9cfd5a8d/6a17e30f414c64d32d9450e9/d5d3a2e20038d17ef701822fe7ccc38d6e175c50-1600x805.png" alt="Define el modo de sincronización en Airbyte" /><p>4. Pasaremos al paso Configurar Conexión. Aquí podemos definir el nombre de la conexión y la frecuencia de ejecución de la integración. La frecuencia puede configurar de tres maneras:</p><ul><li><p><strong>Cron</strong>: Ejecuta las sincronizaciones basar en la expresión cron definida por el usuario (por ejemplo, 0 0 15 * * ?, a las 15:00 todos los días);</p></li><li><p><strong>Programado</strong>: Ejecuta las sincronizaciones en el intervalo de tiempo especificado (por ejemplo, cada 24 horas, cada 2 horas);</p></li><li><p><strong>Manual</strong>: Ejecuta las sincronizaciones manualmente.</p></li></ul><p>Para esta demostración, seleccionaremos la opción Manual.</p><p>Finalmente, al hacer clic en <strong>Configurar conexión</strong>, se establecerá la conexión entre la Fuente y el Destino.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4f5fc0e51035b733/6a17e311af47b67ac8cddeff/1a0470f6dff341cb90e6ecfd8ae87a7d2243cbf4-1600x626.png" alt="Haciendo clic en Configurar conexión en Airbyte" /><h3>Sincronización de datos de S3 a Elasticsearch</h3><p>Cuando vuelves a la pantalla de Conexiones, puedes ver la conexión que se creó. Para ejecutar el proceso, simplemente haz clic en Sincronizar. A partir de ese momento, comenzará la migración de datos de S3 a Elasticsearch.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9b0ad7a7446f9d58/6a17e3121d1b83b4c593e3c3/c1ce54b129eafb2533b638e4df2b96f3a266ad62-1600x347.png" alt="Sincronización de datos de S3 con Elasticsearch en Airbyte" /><p>Si todo va bien, obtendrás el estado sincronizado.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt857cdad5bd7fe03f/6a17e313be608646e00046b9/6fe9d5826787066bd8bf0f5e17905df9f8d698e6-1600x361.png" alt="Estado sincronizado de S3 a Elasticsearch en Airbyte" /><h3>Visualización de datos en Kibana</h3><p>Ahora, iremos a Kibana para analizar los datos y comprobar si están indexados correctamente. En la sección Kibana Discovery crearemos una Vista de Datos llamada logs. Con esto, podremos explorar los datos que solo existen en el índice de registros, que se creó tras la sincronización.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1bc137f7c04e50ee/6a17e3151480094f2eb486cf/6b6909647ac3187d0fee477cfd732741314f82cf-1600x566.png" alt="Visualización de datos en Kibana: Airbyte y Elastic" /><p>Ahora podemos visualizar los datos indexados y realizar análisis sobre ellos. De este modo, validamos todo el flujo de migración usando Airbyte, donde cargamos los datos presentes en el bucket e los indexamos en Elasticsearch.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd8c0a36a83ee4bb1/6a17e317b1e1135ea679f20e/ca8e9b3d7f7112291af58acf514f4573b44037e8-1600x806.png" alt="Airbyte y Elastic: visualiza los datos indexados y realiza análisis sobre ellos en Kibana" /><h2>Conclusión: Integración de Airbyte y Elasticsearch</h2><p>Airbyte demostró ser una herramienta eficiente para la integración de datos, permitiéndonos conectar varias fuentes y destinos de forma automatizada. En este tutorial, demostramos cómo ingirir datos de un cubo S3 a un índice de Elasticsearch, destacando los pasos principales del proceso.</p><p>Este enfoque facilita la ingestión de grandes volúmenes de datos y permite análisis dentro de Elasticsearch, como búsquedas complejas, agregaciones y visualizaciones de datos.</p><h2>Referencias</h2><p><strong>Inicio rápido de 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>Conceptos 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[Datos de índice]]></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[Cómo ingerir datos en Elasticsearch a través de LlamaIndex]]></title>
    <description><![CDATA[Un paso a paso sobre cómo ingerir datos y buscar usando RAG con LlamaIndex.]]></description>
    <content:encoded><![CDATA[<p>En este artículo, implementaremos un motor de búsqueda para las preguntas frecuentes empleando LlamaIndex para indexar los datos. Elasticsearch servirá como nuestra base de datos vectorial, permitiendo la búsqueda vectorial, mientras que RAG (Generación Aumentada por Recuperación) enriquecerá el contexto, proporcionando respuestas más precisas.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte5895fbc057ffc1b/6a17f4cf3e9e45288bba15ef/7ac65a686bdd76c145e903f5c3110c62875a525f-972x501.png" alt="LlamaIndex y Elasticsearch: Ingestiendo documentos y construyendo búsqueda de preguntas frecuentes" /><h2>¿Qué es LlamaIndex?</h2><p>LlamaIndex es un marco que facilita la creación de agentes y flujos de trabajo impulsados por Grandes Modelos de Lenguaje (LLMs) para interactuar con datos específicos o privados. Permite la integración de datos de diversas fuentes (APIs, PDFs, bases de datos) con LLMs, facilitando tareas como investigación, extracción de información y generación de respuestas contextualizadas.</p><p><strong>Conceptos clave:</strong></p><ul><li><p>Agentes: Asistentes inteligentes que emplean LLMs para realizar tareas, desde respuestas simples hasta acciones complejas.</p></li><li><p>Flujos de trabajo: Procesos de varios pasos que combinan agentes, conectores de datos y herramientas para tareas avanzadas.</p></li><li><p>Aumento de contexto: Una técnica que enriquece el LLM con datos externos, superando sus limitaciones de entrenamiento.</p></li></ul><p><strong>Integración de LlamaIndex</strong> <strong>con Elasticsearch:</strong></p><p>Elasticsearch puede usar de varias formas con LlamaIndex:</p><ul><li><p>Fuente de datos: Emplea el Elasticsearch Reader para extraer documentos.</p></li><li><p>Modelo de incrustaciones: Codificar datos en vectores para búsquedas semánticas.</p></li><li><p>Almacenamiento vectorial: Emplea Elasticsearch como repositorio para buscar documentos vectorizados.</p></li><li><p>Almacenamiento avanzado: Configurar estructuras como resúmenes de documentos o grafos de conocimiento.</p></li></ul><h2>Uso de LlamaIndex y Elasticsearch para crear una búsqueda de preguntas frecuentes </h2><h3>Preparación de datos</h3><p>Usaremos como ejemplo las <a href="https://www.elastic.co/guide/en/cloud/current/ec-faq-getting-started.html">preguntas frecuentes de Elasticsearch Service</a> . Cada pregunta se extraía de la web y se almacenaba en un archivo de texto individual. Puedes usar cualquier método para organizar los datos; En este ejemplo, elegimos almacenar los archivos localmente.</p><p>Archivo de ejemplo:</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>Luego de almacenar todas las preguntas, el directorio se verá así:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt43467eb9c5579103/6a17f4d02f4a5cc60bfa8a62/1f367d57f2e650334671a2c03156ef4412c0c615-962x704.png" alt="" /><h3>Instalación de dependencias</h3><p>Implementaremos la ingestión y búsqueda usando el lenguaje Python, la versión que usé fue la 3.9. Como requisito previo, será necesario instalar las siguientes dependencias:</p>llama-index-vector-stores-elasticsearch
llama-index
openai<p>Elasticsearch y Kibana se crearán con Docker, configurados mediante docker-compose.yml para ejecutar la versión 8.16.2. Esto facilita la creación del entorno 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>Ingesta de documentos usando LlamaIndex</h3><p>Los documentos se indexarán en Elasticsearch usando LlamaIndex. Primero, cargamos los archivos con <strong>SimpleDirectoryReader</strong>, que permite cargar archivos desde un directorio local. Luego de cargar los documentos, los indexaremos usando el <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>Los Vector Stores en LlamaIndex son responsables de almacenar y gestionar las incrustaciones de documentos. LlamaIndex soporta diferentes tipos de Vector Stores, y en este caso, usaremos Elasticsearch. En el StorageContext, configuramos la instancia de Elasticsearch. Dado que el contexto es local, no se requerían parámetros adicionales. Para configuraciones en otros entornos, consulte la documentación para comprobar los parámetros necesarios: <a href="https://docs.llamaindex.ai/en/stable/examples/vector_stores/ElasticsearchIndexDemo/#configuring-elasticsearchstore">ElasticsearchStore Configuration</a>.</p><p>Por defecto, LlamaIndex emplea el modelo <strong>OpenAI text-embedding-ada-002</strong> para generar embeddings. Sin embargo, en este ejemplo, usaremos el modelo <strong>text-embedding-3-small</strong> . Es importante señalar que se requerirá una clave API de OpenAI para usar el modelo.</p><p>A continuación se muestra el código completo para la ingestión 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>Tras la ejecución, los documentos se indexarán en el índice <strong>de preguntas frecuentes</strong> como se muestra a continuación:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt391ae1bfc1daefbf/6a17f4d22f4a5c9887fa8a66/d59b85ed1f57bf80e84d6cb0d6d722a2d12ae4c0-1600x745.png" alt="" /><h3>Búsqueda con RAG</h3><p>Para realizar búsquedas, configuramos el cliente <strong>ElasticsearchStore</strong> , configurando los campos <strong>index_name</strong> y <strong>es_url</strong> con la URL de Elasticsearch. En <strong>retrieval_strategy</strong>, definimos la <strong>AsyncDenseVectorStrategy</strong> para búsquedas vectoriales. También están disponibles otras estrategias, como <strong>AsyncBM25Strategy</strong> (búsqueda por palabras clave) y <strong>AsyncSparseVectorStrategy</strong> (vectores dispersos). Se pueden encontrar más detalles en la <a href="https://docs.llamaindex.ai/en/stable/api_reference/storage/vector_store/elasticsearch/">documentación oficial</a>.</p>es = ElasticsearchStore(
   index_name="faq",
   es_url="http://localhost:9200",
   retrieval_strategy=AsyncDenseVectorStrategy(
   )
)<p>A continuación, se creará un objeto <strong>VectorStoreIndex</strong> , donde configuramos el <strong>vector_store</strong> usando el objeto ElasticsearchStore. Con el método <strong>as_retriever</strong> , realizamos la búsqueda de los documentos más relevantes para una consulta, estableciendo el número de resultados devueltos a 5 mediante el <strong>parámetro 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>El siguiente paso es RAG. Los resultados de la búsqueda vectorial se incorporan en un prompt formateado para el LLM, permitiendo una respuesta contextualizada basada en la información recuperada.</p><p>En la PromptPlantilla, definimos el formato del prompt, que incluye:</p><ul><li><p>Contexto ({context_str}): documentos recuperados por el recuperador.</p></li><li><p>Consulta ({query_str}): la pregunta del usuario.</p></li><li><p>Instrucciones: pautas para que el modelo responda según el contexto, sin depender de conocimientos externos.</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>Finalmente, el LLM procesa el prompt y devuelve una respuesta precisa y contextual.</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>El código completo se encuentra a continuación:</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>Ahora podemos realizar nuestra búsqueda, por ejemplo, "¿Los servicios de Elastic son gratis?" y obtener una respuesta contextualizada basada en los datos de las preguntas frecuentes en sí.</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 generar esta respuesta, se emplearon los siguientes 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>Conclusión</h2><p>Empleando LlamaIndex, demostramos cómo crear un sistema eficiente de búsqueda de preguntas frecuentes con soporte para Elasticsearch como base de datos vectorial. Los documentos se ingieren e indexan mediante incrustaciones, lo que permite búsquedas vectoriales. A través de una PromptPlantilla, los resultados de la búsqueda se incorporan al contexto y se envían al LLM, que genera respuestas precisas y contextualizadas basadas en los documentos recuperados.</p><p>Este flujo de trabajo integra la recuperación de información con la generación contextualizada de respuestas para ofrecer resultados precisos y relevantes.</p><h2>Referencias</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[Datos de índice]]></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[Búsqueda facetada: Emplea la IA para mejorar el alcance y los resultados de la búsqueda]]></title>
    <description><![CDATA[Explora cómo usar la búsqueda por facetas en Elasticsearch para reducir rápidamente las opciones dentro de las categorías.]]></description>
    <content:encoded><![CDATA[<p>En este artículo, exploraremos cómo la Inteligencia Artificial (IA), específicamente empleando modelos de lenguaje avanzados como GPT-4, puede ayudar a crear facetas más contextuales, haciéndolas aún más relevantes y útiles para los usuarios.</p><p>La búsqueda por facetas es una herramienta poderosa en las plataformas de comercio electrónico. Ayuda a organizar y refinar los resultados de búsqueda en función de las características de los elementos mostrados. Aunque a menudo se confunden con filtros, los aspectos funcionan de forma diferente. Los filtros son atributos fijos, definidos por la información siempre presente en el índice, como la categoría o formato de un producto. Las facetas, en cambio, son dinámicas y se generan a partir de los resultados devueltos por la búsqueda ejecutada.</p><p>Imagina un catálogo de ropa: campos como "categoría" (por ejemplo, camisetas, pantalones) o "género" (por ejemplo, hombre, mujer) son filtros que ayudan a reducir los resultados. Sin embargo, los aspectos reflejan características específicas de los productos que aparecen en los resultados, como colores comunes, tamaños disponibles o materiales. Esto permite una experiencia de búsqueda más adaptable y contextual.</p><p>A continuación hay una imagen donde interactuamos con una faceta y podemos ver los resultados de búsqueda filtrados por ella.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc4ce8ca7e5b62ad7/6a17f8ba6864a4534bb68979/74d2159706ab7248ebe5efddc74c882f0693db71-600x420.gif" alt="Ejemplo de búsqueda facetada" /><h2>Cómo la IA puede mejorar la generación de facetas</h2><p>La inteligencia artificial suele asociar con la búsqueda semántica y las incrustaciones, pero ¿qué pasa con los aspectos? ¿Cómo se puede aprovechar la IA para que los aspectos sean más útiles y específicos del contexto para cada búsqueda?</p><p>Una posibilidad intrigante es emplear la IA para crear nuevas categorizaciones que vayan más allá de las clasificaciones tradicionales del índice. Al analizar características específicas del contenido, estas nuevas categorías pueden proporcionar una contextualización más rica y precisa, haciendo que los aspectos sean más relevantes y alineados con las necesidades de los usuarios. Esto permite un refinamiento más significativo de los resultados en comparación con las categorías originales de documentos.</p><h2>Cómo la IA puede refinar las clasificaciones de películas para obtener mejores búsquedas</h2><p>Analicemos las siguientes películas, todas actualmente clasificadas dentro del género Drama:</p><ul><li><p>Réquiem por un sueño
Resumen: Las utopías inducidas por las drogas de cuatro personas de Coney Island se rompen cuando sus adicciones son profundas.</p></li><li><p>Belleza americana
Currículum: Un padre suburbano sexualmente frustrado sufre una crisis de la mediana edad tras enamorar de la mejor colega de su hija.</p></li><li><p>Búsqueda de Buena Voluntad
Currículum: Will Hunting, conserje en el M.I.T., tiene un don para las matemáticas, pero necesita ayuda de un psicólogo para encontrar un rumbo en su vida.</p></li></ul><p>Esta clasificación de género no capta las diferencias sutiles ni los contextos únicos de cada película. Aprovechando la IA para analizar resumen y temas centrales, podemos crear nuevas categorías que reflejen mejor el contexto real de cada película. Por ejemplo:</p><ul><li><p>Réquiem por un sueño - Nueva categoría: "Adicción y dependencia"</p></li><li><p>American Beauty - Nueva categoría: "Crisis de la mediana edad"</p></li><li><p>Búsqueda de Buena Voluntad - Nueva categoría: "Lucha Intelectual"</p></li></ul><p>Estas nuevas categorías hacen que las búsquedas sean mucho más precisas y ofrecen a los usuarios filtros más significativos para refinar sus resultados. Este enfoque es especialmente efectivo cuando las categorías originales son demasiado genéricas, permitiendo a los usuarios encontrar exactamente lo que buscan con mayor facilidad.</p><h2>Creación de nuevas categorías con GPT-4: Ejemplo de búsqueda facetada</h2><p>En este ejemplo, mostraremos cómo un modelo de IA puede emplear para crear nuevas categorías de películas que sean más precisas y alineadas con el contexto de cada obra. Para demostrar este proceso, emplearemos la cadena de simulación Elastic junto con el servicio de inferencia OpenAI. Se creará una tubería con varios procesadores, incluido el Script Processor, que será responsable de crear el prompt que se ejecutará en el Inference Processor, capaz de determinar las nuevas categorías. Los otros procesadores se emplearán para manipular los datos y los campos auxiliares generados durante la ejecución de la pipeline. Cabe mencionar que esta lógica también puede aplicar con otras herramientas o modelos similares.</p><p>Primero, necesitamos crear el endpoint de inferencia, donde definimos el servicio como OpenAI, el token necesario para acceder al servicio y el modelo. En este ejemplo, estoy usando gpt-4o-mini. Para más detalles sobre el servicio de inferencia OpenAI haz <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/infer-service-openai.html">clic aquí</a>.</p>PUT _inference/completion/generate_topics_ia
{
    "service": "openai",
    "service_settings": {
        "api_key": "your-token",
        "model_id": "gpt-4o-mini"
    }
}<p>Con el endpoint creado, ya estamos listos para usarlo y crear las nuevas categorías. A continuación se muestra una pipeline que gestiona todo el proceso de manipulación de datos documentales y generación de prompts. Voy a explicar la función de cada procesador en detalle.</p><p>El primer procesador será responsable de construir el prompt. Es muy importante detallar claramente las instrucciones para que la IA pueda analizar e identificar correctamente los temas. En este prompt, aplicar 2 temas basándome en el análisis del título, la descripción y los géneros de las películas.</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>La siguiente tubería es la de inferencia, recibirá el prompt y lo enviará a nuestro <strong>punto final generate_topics_ia</strong> . La respuesta generada por el modelo se almacenará en el campo de resultados.</p>{
        "inference": {
          "model_id": "generate_topics_ia",
          "input_output": {
            "input_field": "prompt",
            "output_field": "result"
          }
        }
      }<p>A continuación, tenemos 3 procesadores que manipulan la respuesta y la configuran en el campo de temas, además de eliminar campos temporales que creé.</p><p>Al ejecutar esta canalización, veremos los resultados a continuación:</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>Cabe destacar que tenemos nuevas categorías más relacionadas con el contexto de las películas, aunque algunas son inicialmente del mismo género.</p><p>Ahora podemos usar estas nuevas categorías e indexarlas junto con el documento. De este modo, al generar las facetas, además de la categoría principal, tenemos subcategorías más específicas alineadas con el contexto de las películas.</p><p>Además, es posible vectorizar estas nuevas categorías y usarlas en búsquedas vectoriales. Esto significa que las nuevas categorías no solo sirven como filtros, sino que también pueden usar para calcular similitudes semánticas con los términos de búsqueda, aumentando aún más la relevancia de los resultados presentados.</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>Conclusión</h2><p>Emplear IA para mejorar aspectos puede transformar la experiencia de búsqueda al hacer que los resultados sean más específicos y contextuales. A diferencia de las categorías fijas, que suelen ser amplias, las categorías generadas por IA pueden reflejar mejor el contexto. Por ejemplo, al reclasificar películas, podemos captar el contexto que las categorías principales no mencionan, proporcionando agrupaciones mucho más relevantes.</p><p>Estas nuevas categorías pueden agregar al índice no solo para mejorar el facetado, sino también para habilitar búsquedas vectoriales. El resultado es una experiencia de búsqueda más eficiente, con filtros más alineados con el contexto.</p><h2>Referencias</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[Cómo ingestar datos en Elasticsearch a través de Apache Airflow]]></title>
    <description><![CDATA[Aprende cómo ingerir datos en Elasticsearch a través de Apache Airflow.]]></description>
    <content:encoded><![CDATA[<h2>¿Qué es el Apache Airflow?</h2><p>Apache Airflow es una plataforma diseñada para crear, programar y monitorizar flujos de trabajo. Se emplea para orquestar procesos ETL, pipelines de datos y otros flujos de trabajo complejos, ofreciendo flexibilidad y escalabilidad. Su interfaz visual y capacidades de monitorización en tiempo real hacen que la gestión de tuberías sea más accesible y eficiente, permitiéndote seguir el progreso y los resultados de tus ejecuciones. A continuación se presentan sus cuatro pilares principales:</p><ul><li><p><strong>Dinámico: </strong>Las canalizaciones están definidas en Python, lo que permite una generación dinámica y flexible de flujos de trabajo.</p></li><li><p><strong>Extensible:</strong> Airflow puede integrar con una variedad de entornos, crear operadores personalizados y ejecutar código específico según sea necesario.</p></li><li><p><strong>Elegante:</strong> Los pipelines se escriben de manera limpia y explícita.</p></li><li><p><strong>Escalable:</strong> Su arquitectura modular emplea una cola de mensajes para orquestar un número arbitrario de trabajadores.</p></li></ul><p>En la práctica, el flujo de aire puede emplear en escenarios como:</p><ul><li><p><strong>Importación de datos: </strong>Orquestar la ingestión diaria de datos en una base de datos como Elasticsearch.</p></li><li><p><strong>Monitorización de registros:</strong> Gestionar la recopilación y procesamiento de archivos de registro, que luego se analizan en Elasticsearch para identificar errores o anomalías.</p></li><li><p><strong>Integración de múltiples fuentes de datos:</strong> Combina información de diferentes sistemas (APIs, bases de datos, archivos) en una sola capa en Elasticsearch, simplificando la búsqueda y la elaboración de reportes.</p></li></ul><h2>Comprendiendo los DAG (Grafos Acíclicos Dirigidos) en el flujo de aire</h2><p>En Airflow, los flujos de trabajo se representan mediante DAGs (Grafos Acíclicos Dirigidos). Un DAG es una estructura que define la secuencia en la que se ejecutarán las tareas. Las principales características de los DAG son:</p><ul><li><p><strong>Composición por tareas independientes:</strong> Cada tarea representa una unidad de trabajo y está diseñada para ejecutar de forma independiente.</p></li><li><p><strong>Secuenciación: </strong>La secuencia en la que se ejecutan las tareas está definida explícitamente en el DAG.</p></li><li><p><strong>Reusabilidad:</strong> Los DAG están diseñados para ejecutar repetidamente, facilitando la automatización de procesos.</p></li></ul><h2>Componentes de flujo de aire</h2><p>El ecosistema Airflow está compuesto por varios componentes que trabajan juntos para orquestar tareas:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt25a23489b8725b3e/6a17dfcfe8fbceba103a1846/bacd83aff625026d62f023e0434baa5782a2761a-1046x628.png" alt="Componentes principales del flujo de aire" /><ul><li><p><strong>Programador:</strong> Responsable de programar los DAGs y enviar tareas para su ejecución por parte de los trabajadores.</p></li><li><p><strong>Ejecutor:</strong> Gestiona la ejecución de las tareas, delegándolas a los trabajadores.</p></li><li><p><strong>Servidor sitio web:</strong> Proporciona una interfaz gráfica para interactuar con DAGs y tareas.</p></li><li><p><strong>Carpeta Dags:</strong> Carpeta donde almacenamos los DAGs escritos en Python.</p></li><li><p><strong>Metadatos:</strong> Base de datos que sirve como repositorio para la herramienta, empleada por el planificador y el ejecutor para almacenar el estado de ejecución.</p></li></ul><h2>Apache Airflow y Elasticsearch</h2><p>Demostraremos el uso de Apache Airflow y Elasticsearch para orquestar tareas e indexar resultados en Elasticsearch. El objetivo de esta demostración es crear una cadena de tareas para actualizar registros en un índice de Elasticsearch. Este índice contiene una base de datos de películas, donde los usuarios pueden valorar y asignar valoraciones. Imaginando un escenario con cientos de audiencias diarias, es necesario mantener actualizado el registro de audiencias. Para ello, se desarrollará un DAG que se ejecutará diariamente, responsable de recuperar las nuevas calificaciones consolidadas y actualizar los registros en el índice.</p><p>En el flujo del DAG, tendremos una tarea para obtener las valoraciones, seguida de otra tarea para validar los resultados. Si los datos no existen, el DAG será dirigido a una tarea de fallo. De lo contrario, los datos se indexarán en Elasticsearch. El objetivo es actualizar el campo de calificación de las películas en un índice recuperando las calificaciones mediante un método con el mecanismo responsable de calcular los puntajes.</p><h2>Usando Apache Airflow y Elasticsearch con Docker</h2><p>Para crear un entorno contenedorizado, usaremos Apache Airflow con Docker. Sigue las instrucciones de la <a href="https://airflow.apache.org/docs/apache-airflow/stable/howto/docker-compose/index.html">guía "Running Airflow en Docker"</a> para configurar Airflow de forma práctica.</p><p>En cuanto a Elasticsearch, usaré un clúster en Elastic Cloud, pero si prefieres, también puedes configurar Elasticsearch con Docker. Ya se creó un índice que contiene un catálogo de películas, con los datos de las películas indexados. El campo de 'calificación' de estas películas se actualizará.</p><h2>Creación del DAG</h2><p>Tras instalarla mediante Docker, se creará una estructura de carpetas, incluyendo la carpeta dags, donde debemos colocar nuestros archivos DAG para que Airflow los reconozca.</p><p>Antes de eso, debemos cerciorarnos de que las dependencias necesarias estén instaladas. Estas son las dependencias de este proyecto:</p>pip install apache-airflow apache-airflow-providers-elasticsearch<p>Crearemos el archivo <code>update_ratings_movies.py</code> y empezaremos a programar las tareas.</p><p>Ahora, importemos las bibliotecas necesarias:</p>from airflow import DAG
from airflow.operators.python import PythonOperator, BranchPythonOperator
from airflow.providers.elasticsearch.hooks.elasticsearch import ElasticsearchPythonHook<p>Emplearemos <a href="https://airflow.apache.org/docs/apache-airflow-providers-elasticsearch/stable/hooks/elasticsearch_python_hook.html"><strong>el ElasticsearchPythonHook</strong></a>, un componente que simplifica la integración entre Airflow y un clúster de Elasticsearch al abstraer la conexión y el uso de APIs externas.</p><p>A continuación, definimos el DAG, especificando sus argumentos principales:</p><ul><li><p><strong><code>dag_id</code></strong>: el nombre del DAG.</p></li><li><p><strong><code>start_date</code></strong>: cuando empezará el DAG.</p></li><li><p><strong><code>schedule</code></strong>: define la periodicidad (diaria en nuestro caso).</p></li><li><p><strong><code>doc_md</code></strong>: documentación que se importará y mostrará en la interfaz Airflow.</p></li></ul><h2>Definición de las tareas</h2><p>Ahora, definamos las tareas del DAG. La primera tarea será la de recuperar los datos de valoración de la película. Usaremos el <strong>PythonOperator</strong> con la <code>task_id</code> configurada en <code>'get_movie_ratings'</code>. El parámetro <code>python_callable</code> llamará a la función responsable de obtener las valoraciones.</p>get_ratings_operator = PythonOperator(
   task_id='get_movie_ratings',
   python_callable=get_movie_ratings_task
)<p>A continuación, necesitamos validar si los resultados son válidos. Para esto, usaremos un condicional con <strong>un operador BranchPython</strong>. La <code>task_id</code> será <code>'validate_result'</code>, y la <code>python_callable</code> llamará a la función de validación. El parámetro <code>op_args</code> se empleará para pasar el resultado de la tarea anterior, <code>'get_movie_ratings'</code>, a la función de validación.</p>validate_result = BranchPythonOperator(
   task_id='validate_result',
   python_callable=validate_result,
   op_args=["{{ task_instance.xcom_pull(task_ids='get_movie_ratings') }}"]
)<p>Si la validación tiene éxito, tomaremos los datos de la tarea <code>'get_movie_ratings'</code> e los indexaremos en Elasticsearch. Para lograrlo, crearemos una nueva tarea, <code>'index_movie_ratings'</code>, que empleará el <strong>PythonOperator</strong>. El parámetro <code>op_args</code> pasará los resultados de la tarea <code>'get_movie_ratings'</code> a la función de indexación.</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>Si la validación indica un fallo, el DAG procederá a una tarea de notificación de fallo. En este ejemplo, simplemente imprimimos un mensaje, pero en un escenario real podríamos configurar alertas para notificar sobre los fallos.</p>failed_get_rating_operator = PythonOperator(
   task_id='failed_get_rating_operator',
   python_callable=lambda: print('Ratings were False, skipping indexing.')
)<p>Finalmente, definimos las dependencias de las tareas, cerciorándonos de que se ejecuten en el orden correcto:</p>get_ratings_operator &gt;&gt; validate_result &gt;&gt; [index_ratings_operator, failed_get_rating_operator]<p>Ahora sigue el código completo de nuestro 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>Visualización de la ejecución del DAG</h2><p>En la interfaz Apache Airflow, podemos visualizar la ejecución de los DAGs. Simplemente ve a la pestaña "DAGs" y localiza el DAG que creaste.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9c5de210a5a264ad/6a17dfd00b0bed0290dd34cf/905b9191c4e3191e8b5608174d4c555370bf25eb-1600x760.png" alt="Visualiza la ejecución de los DAGs en la interfaz Apache Airflow con Elasticsearch" /><p>A continuación, podemos visualizar las ejecuciones de las tareas y sus respectivos estados. Al seleccionar una ejecución para una fecha específica, podemos acceder a los registros de cada tarea. Ten en cuenta que en la tarea <strong><code>index_movie_ratings</code></strong> podemos ver los resultados de indexación en el índice y que se completó con éxito.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0beddf311a808d24/6a17dfd2033c8d76de6bb0ba/73c3f738d27500cf153377bedf1aa2b67a94a8c8-1600x648.png" alt="visualiza las ejecuciones de las tareas y sus estados en Apache Airflow con Elasticsearch" /><p>En las otras pestañas, es posible acceder a información adicional sobre las tareas y el DAG, ayudando en el análisis y resolución de posibles problemas.</p><h2>Conclusión</h2><p>En este artículo, demostramos cómo integrar Apache Airflow con Elasticsearch para crear una solución de ingestión de datos. Mostramos cómo configurar el DAG, definir las tareas responsables de recuperar, validar e indexar datos de video, así como monitorizar y visualizar la ejecución de estas tareas en la interfaz Airflow.</p><p>Este enfoque puede adaptar fácilmente a diferentes tipos de datos y flujos de trabajo, haciendo de Airflow una herramienta útil para orquestar pipelines de datos en diversos escenarios.</p><h2>Referencias</h2><p>Apache AirFlow</p><p><a href="https://airflow.apache.org/">https://airflow.apache.org/</a></p><p>Instalar Apache Airflow con 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>Elasticsearch Python Hook</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[Datos de índice]]></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[Cómo ingerir datos en Elasticsearch a través de Kafka]]></title>
    <description><![CDATA[Una guía paso a paso para integrar Apache Kafka con Elasticsearch para una ingestión, indexación y visualización eficiente de datos usando Python, Docker Compose y Kafka Connect.]]></description>
    <content:encoded><![CDATA[<p>En este artículo, mostramos cómo integrar Apache Kafka con Elasticsearch para la ingestión e indexación de datos. Proporcionaremos una visión general de Kafka, su concepto de productores y consumidores, y crearemos un índice de registros donde los mensajes serán recibidos e indexados a través de Apache Kafka. El proyecto está implementado en Python y el código está disponible en <a href="https://github.com/elastic/elasticsearch-labs/tree/main/supporting-blog-content/elasticsearch-through-apache-kafka">GitHub</a>.</p><h3><strong>Prerrequisitos</strong></h3><ul><li><p>Docker y Docker Compose: Cerciórate de tener Docker y Docker Compose instalados en tu máquina.</p></li><li><p>Python 3.x: Para ejecutar los scripts de productor y consumidor.</p></li></ul><h3><strong>Introducción a Apache Kafka</strong></h3><p>Apache Kafka es una plataforma de streaming distribuida que permite una alta escalabilidad y disponibilidad, así como tolerancia a fallos. En Kafka, la gestión de datos se realiza a través de los componentes principales:</p><ul><li><p><strong>Intermediario</strong>: responsable de almacenar y distribuir mensajes entre productores y consumidores.</p></li><li><p><strong>Zookeeper</strong>: gestiona y coordina los corredores Kafka, controlando el estado del clúster, los líderes de partición y la información del consumidor.</p></li><li><p><strong>Temas</strong>: canales donde se publican y almacenan datos para su consumo.</p></li><li><p><strong>Consumidores y productores</strong>: mientras los productores envían datos a los temas, los consumidores recuperan esos datos.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4aae32304d7417f6/6a17f7be577262b47c1bcdac/89a37243baec48bbdfa85e3298fc91082322ed4e-1600x868.png" alt="Diagram Apache Kafka" /><p>Estos componentes trabajan juntos para formar el ecosistema Kafka, proporcionando un marco robusto para el flujo de datos.</p><h3><strong>Estructura del proyecto</strong></h3><p>Para entender el proceso de ingesta de datos, lo dividimos en etapas:</p><ul><li><p><strong>Aprovisionamiento de infraestructura</strong>: configurar el entorno Docker para soportar Kafka, Elasticsearch y Kibana.</p></li><li><p><strong>Creación de productores</strong>: implementando el Productor Kafka, que envía datos al tema de registros.</p></li><li><p><strong>Creación de Consumidores</strong>: desarrollar el Consumidor Kafka para leer e indexar mensajes en Elasticsearch.</p></li><li><p><strong>Validación de ingestión</strong>: verificar y validar los datos enviados y consumidos.</p></li></ul><h3><strong>Configuración de infraestructura con Docker Compose</strong></h3><p>Empleamos Docker Compose para configurar y gestionar los servicios necesarios. A continuación, encontrarás el código Docker Compose que configura cada servicio necesario para la integración de Apache Kafka, Elasticsearch y Kibana, cerciorando un proceso de ingestión de datos.</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>Puedes acceder al archivo directamente desde el repositorio <a href="https://github.com/andreluiz1987/elasticsearch-labs/tree/supporting-blog/elasticsearch-apache-kafka/supporting-blog-content/elasticsearch-through-apache-kafka">de GitHub</a> de Elasticsearch Labs.</p><h3><strong>Envío de datos con el productor Kafka</strong></h3><p>El productor es responsable de enviar mensajes al tema de los logs. Al enviar mensajes en lotes, aumenta la eficiencia del uso de la red, permitiendo optimizaciones con los ajustes de <code>batch_size</code> y <code>linger_ms</code> , que controlan la cantidad y latencia de los lotes, respectivamente. La <code>acks='all'</code> de configuración garantiza que los mensajes se almacenen de forma duradera, lo cual es esencial para los datos de registro 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>Al iniciar el productor, los mensajes se envían en lotes sobre el tema, como se muestra a continuación:</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 indexación de datos con el Kafka Consumer</strong></h3><p>El consumidor está diseñado para procesar mensajes de forma eficiente, consumiendo lotes del tema de logs e indexándolos en Elasticsearch. Con <code>auto_offset_reset='latest'</code>, se cerciora que el consumidor empiece a procesar los mensajes más recientes, ignorando los antiguos, y <code>max_poll_records=10</code> limita el lote a 10 mensajes. Con <code>fetch_max_wait_ms=2000</code>, el consumidor espera hasta 2 segundos para acumular suficientes mensajes antes de procesar el lote.</p><p>En su bucle principal, el consumidor consume mensajes de registro, procesa e indexa cada lote en Elasticsearch, cerciorando la ingestión continua de datos.</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>Visualización de datos en Kibana</strong></h3><p>Con Kibana, podemos explorar y validar los datos ingeridos de Kafka e indexados en Elasticsearch. Accediendo <strong>a Dev Tools</strong> en Kibana, puedes ver los mensajes indexados y confirmar que los datos son los esperados. Por ejemplo, si nuestro productor Kafka enviara 5 lotes de 10 mensajes cada uno, deberíamos ver un total de 50 registros en el índice.</p><p>Para verificar los datos, puedes usar la siguiente consulta en la sección <strong>de Herramientas de desarrollo</strong> :</p>GET /logs/_search
{
  "query": {
    "match_all": {}
  }
}<p>Respuesta:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc15fb278fe6f984e/6a17f7c0b1e1131ac279f404/f44f95fc27bba50991412d5c7e7728519b9bdec4-688x1024.png" alt="Respuesta verifica los datos - Kafka &amp; Elasticsearch​" /><p>Además, Kibana ofrece la capacidad de crear visualizaciones y paneles que pueden ayudar a que el análisis sea más intuitivo e interactivo. A continuación, podéis ver algunos ejemplos de los paneles y visualizaciones que creamos, que ilustran los datos en varios formatos, mejorando nuestra comprensión de la información procesada.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltabc2856c9feedc47/6a17f7c13e9e4522bfba1651/a18e0ebb543e929136d4786651bc6cee32fa69bc-1600x470.png" alt="Visualización de Kibana - Kafka &amp; Elasticsearch​" /><h3><strong>Ingesta de datos con Kafka Connect</strong></h3><p>Kafka Connect es un servicio diseñado para facilitar la integración entre fuentes de datos y destinos (sumideros), como bases de datos o sistemas de archivos. Opera con conectores predefinidos que gestionan el movimiento de datos automáticamente. En nuestro caso, Elasticsearch funciona como el sumidero de datos.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt53e3acaf62e7dbed/6a17f7c3577262c5151bcdb0/52a6982c864fdc04cb7a8a5fb02e67dca0ba8226-1600x819.png" alt="Ingesta de datos con Kafka Connect" /><p>Con Kafka Connect, podemos simplificar el proceso de ingesta de datos, eliminando la necesidad de implementar manualmente el flujo de trabajo de ingestión de datos en Elasticsearch. Con el conector adecuado, Kafka Connect permite que los datos enviados a un tema Kafka se indexen directamente en Elasticsearch con una configuración mínima y sin necesidad de codificación adicional.</p><h4><strong>Trabajando con Kafka Connect</strong></h4><p>Para implementar Kafka Connect, agregaremos el<a href="https://github.com/andreluiz1987/es-apache-kafka/blob/main/docker-compose.yml#L31"> servicio kafka-connect </a>a nuestra configuración de Docker Compose. Una parte clave de esta configuración es la instalación del conector Elasticsearch, que gestionará la indexación de datos.</p><p>Tras configurar el servicio y crear el contenedor Kafka Connect, será necesario un archivo de configuración para el conector Elasticsearch. Este archivo define parámetros esenciales como:</p><ul><li><p><code>connection.url</code>: URL de conexión para Elasticsearch.</p></li><li><p><code>topics</code>: El tema de Kafka que el conector monitorizará (en este caso, "logs").</p></li><li><p><code>type.name</code>: Tipo de documento en Elasticsearch (normalmente _doc).</p></li><li><p><code>value.converter</code>: Convierte los mensajes Kafka a formato JSON.</p></li><li><p><code>value.converter.schemas.enable</code>: Especifica si el esquema debe incluir.</p></li><li><p><code>schema.ignore</code> y <code>key.ignore</code>: Ajustes para ignorar esquemas y claves de Kafka durante la indexación.</p></li></ul><p>A continuación se muestra el comando <code>curl</code> para crear el conector Elasticsearch en 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>Con esta configuración, Kafka Connect comenzará automáticamente a ingerir los datos enviados al tema de "logs" e indexarlos en Elasticsearch. Este enfoque permite la ingesta e indexación de datos totalmente automatizada sin necesidad de codificación adicional, simplificando así todo el proceso de integración.</p><h3><strong>Conclusión</strong></h3><p>Integrar Kafka y Elasticsearch crea una poderosa cadena de procesamiento y análisis de datos en tiempo real. Esta guía proporciona un enfoque fundamental para construir una arquitectura robusta de ingestión de datos, con visualización y análisis fluidos en Kibana, lista para adaptar a requisitos más complejos en el futuro.</p><p>Además, usar Kafka Connect hace que la integración entre Kafka y Elasticsearch sea aún más ágil, eliminando la necesidad de código adicional para procesar e indexar datos. Kafka Connect permite que los datos enviados a un tema específico se indexen automáticamente en Elasticsearch con una configuración 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[Datos de índice]]></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[Cómo usar la búsqueda híbrida para un catálogo de productos de comercio electrónico]]></title>
    <description><![CDATA[Aprende a usar la búsqueda híbrida para crear un catálogo de productos de comercio electrónico, empleando facetados, promociones, personalización y análisis de comportamiento.]]></description>
    <content:encoded><![CDATA[<p>En este artículo, demostraremos cómo implementar una búsqueda híbrida que combine los resultados de la búsqueda en texto completo con la búsqueda vectorial. Al unificar estos dos enfoques, la búsqueda híbrida mejora la amplitud de resultados, aprovechando lo mejor de ambas estrategias de búsqueda.</p><p>Además de integrar la búsqueda híbrida, demostraremos cómo agregar funciones que hagan que tu solución de búsqueda sea aún más robusta. Estas incluyen facetados y promociones personalizadas de productos. Además, te mostraremos cómo capturar las interacciones del usuario y generar información valiosa empleando la herramienta de Análisis de Comportamiento de Elastic.</p><p>En esta implementación, verás cómo construir tanto la interfaz que permite a los usuarios ver e interactuar con los resultados de búsqueda como la API responsable de devolver la información. Para acceder a los repositorios con el código fuente, los enlaces se proporcionan a continuación:</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 esta guía en varios pasos, desde la creación del índice hasta la implementación de funciones avanzadas como el facetado y la personalización de resultados. Al final, tendrás una solución de búsqueda robusta lista para usar en un escenario de comercio electrónico.</p><h2>Configuración de entornos para búsqueda híbrida de comercio electrónico</h2><p>Antes de comenzar la implementación, necesitamos configurar el entorno. Puedes elegir usar un servicio en Elastic Cloud o una solución contenedora para gestionar Elasticsearch. Si eliges contenerización, en este repositorio puedes encontrar una configuración mediante Docker Compose: <a href="https://github.com/andreluiz1987/product-store-search/blob/main/docker/docker-compose.yml">docker-compose.yml</a>.</p><h2>Creación de índices e ingesta de catálogos de productos</h2><p>El índice se creará a partir de un catálogo de productos cosméticos, que incluye campos como nombre, descripción, foto, categoría y etiquetas. Los campos usados para la búsqueda en texto completo, como "nombre" y "descripción", se mapearán como <code>text</code>, mientras que los campos usados para agregaciones, como "categoría" y "marca", se mapearán como <code>keyword</code> para permitir el facetado.</p><p>El campo "descripción" se empleará para la búsqueda vectorial, ya que proporciona más contexto sobre los productos. Este campo se definirá como <code>dense_vector,</code> almacenar la representación vectorial de la descripción.</p><p>El mapeo del índice será el siguiente:</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>El script para crear el índice se puede encontrar <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">aquí</a>.</p><h2>Generación de incrustación</h2><p>Para vectorizar las descripciones de productos, empleamos el modelo all-MiniLM-L6-v2. En este caso, la aplicación es responsable de generar las incrustaciones antes de indexar. Otra opción sería importar el modelo al clúster de Elasticsearch, pero para este entorno local, elegimos realizar la vectorización directamente dentro de la aplicación.</p><p>Empleamos el conjunto de datos cosméticos disponible en <a href="https://www.kaggle.com/datasets/shivd24coder/cosmetic-brand-products-dataset">Kaggle</a> para poblar el índice y, para mejorar la eficiencia de la ingesta de datos, empleamos procesamiento por lotes. Durante esta misma etapa de ingestión, generaremos las incrustaciones para el campo "descripción" e indexarémolas en el nuevo campo "description_embeddings".</p><p>El proceso completo de ingesta de datos puede seguir y ejecutar directamente a través del <strong>Jupyter Notebook</strong> disponible en el repositorio. El cuaderno ofrece una guía paso a paso sobre cómo se leen, procesan e indexan los datos en Elasticsearch, permitiendo una fácil replicación y experimentación.</p><p>Puedes acceder al cuaderno en el siguiente enlace: <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">Cuaderno de Ingestión.</a></p><h2>Implementación de búsqueda híbrida</h2><p>Ahora, implementemos la búsqueda híbrida. Para la búsqueda basada en palabras clave, usamos la <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-multi-match-query.html">consulta multi_match</a> , dirigida a los campos "nombre", "categoría" y "descripción". Esto garantiza que se recuperen los documentos que contienen el término de búsqueda en cualquiera de estos campos.</p><p>Para la búsqueda vectorial, usamos la <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/knn-search.html">consulta KNN</a>. El término de búsqueda debe vectorizarse antes de ejecutar la consulta, y esto se hace usando el método que vectoriza el término de entrada. Ten en cuenta que el mismo modelo usado durante la ingestión también se emplea para el término de búsqueda.</p><p>La combinación de ambas búsquedas se realiza mediante el algoritmo <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/rrf.html">de Fusión de Rango Recíproco (RRF), </a>que fusiona los resultados de ambas consultas y aumenta la precisión de la búsqueda al reducir el ruido. RRF permite que tanto las búsquedas basadas en palabras clave como las vectoriales trabajen conjuntamente, mejorando la comprensión de la consulta del usuario.</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>Comparando resultados: búsqueda por palabras clave vs. búsqueda híbrida</h3><p>Ahora, comparemos los resultados de una búsqueda tradicional por palabras clave con la búsqueda híbrida. Al buscar "base para piel seca" usando la búsqueda por palabras clave, obtenemos los siguientes resultados:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcb5405df787bc8f5/6a17023e961e697ca1c4cdb4/52e717aa3c9c1fadfadb639f5fb77cf8e47e3b34-1600x1021.png" alt="Comparando resultados: búsqueda por palabras clave vs. búsqueda híbrida" /><ol><li><p><strong>Maquillaje Revlon ColorStay para piel normal / secaDescripción</strong>: Revlon ColorStay Makeup ofrece una cobertura duradera con una fórmula ligera que no se desvanece, ni se desvanece. Con Time Release \nTechnology, esta fórmula sin aceites y con equilibrio de humedad está especialmente formulada para piel normal o seca para proporcionar hidratación continua. Características: El maquillaje resulta cómodo y se usa hasta 24 horas\nCobertura media a total\nDisponible en una gama de tonos preciosos
</p></li><li><p><strong>Maybelline Dream Smooth Mousse BaseDescripción</strong>: Por qué te encantaráLa base única batida con crema ofrece una perfección 100% suave para bebés.\n\nPiel Se ve y se siente hidratado durante 14 horas - nunca áspero ni seco\tLa fórmula ligera ofrece una cobertura perfectamente hidratante\�Se difumina perfectamente y se siente fresca todo el día\tSin aceite, sin fragancia, probado por dermatólogos, probado por alergias, no comedogénico \u2019 no obstruirá los poros.\nSeguro Para piel sensible.</p></li></ol><p><strong>Análisis</strong>: Al buscar "base para piel seca", los resultados se obtuvieron mediante la coincidencia exacta entre las palabras clave de búsqueda y los títulos y descripciones de los productos. Sin embargo, este partido no siempre refleja la mejor elección. Por ejemplo, el <strong>maquillaje Revlon ColorStay para piel normal / seca</strong> es una buena opción, ya que está formulado específicamente para piel seca. Aunque no contiene aceite, su fórmula está diseñada para proporcionar hidratación continua. En cambio, también recibimos <strong>la Maybelline Dream Smooth Mousse Foundation</strong>, que, aunque sin aceite y mencionando hidratación, suele recomendar más para piel grasa o mixta, ya que los productos sin aceite tienden a centrar en controlar el sebo en lugar de proporcionar la hidratación extra necesaria para la piel seca. Esto pone de manifiesto la limitación de las búsquedas basadas en palabras clave, que pueden devolver productos que no satisfacen completamente las necesidades específicas de las personas con piel seca.</p><p>Ahora, al realizar la misma búsqueda usando el enfoque híbrido:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt412e38b327cf6a4f/6a17024066c4f94c52f8beb9/13b562a5120619355ba0861976102e208964a49f-1600x1021.png" alt="Realizar búsqueda mediante el enfoque híbrido" /><ol><li><p><strong>CoverGirl Outlast Stay Luminous Foundation Creamy Natural (820):D escription</strong>: CoverGirl Outlast Stay Luminous Foundation es perfecta para lograr un acabado luminoso y un brillo sutil. Es sin aceites, con una fórmula no grasienta que da a tu piel una luminosidad natural que dura todo el día. Esta base de maquillaje durante todo el día hidrata la piel y proporciona una cobertura impecable.

<strong>Análisis: </strong>Este producto es una combinación relevante porque enfatiza la hidratación, algo fundamental para usuarios con piel seca. Los términos "hidrata la piel" y "acabado húmedo" coinciden con la intención del usuario de encontrar una base para piel seca. La búsqueda vectorial probablemente entendió el concepto de hidratación y lo relacionó con la necesidad de una base que trate la piel seca.
</p></li><li><p><strong>Maquillaje Revlon ColorStay para piel normal / seca: Descripción:</strong> El maquillaje Revlon ColorStay ofrece una cobertura duradera con una fórmula ligera que no se empacha, no se desvanece ni se desprende de la piel. Con la Tecnología de Liberación Prolongada, esta fórmula sin aceites y equilibrada por la humedad está especialmente formulada para pieles normales o secas para proporcionar hidratación continua.

<strong>Análisis: </strong>Este producto responde directamente a las necesidades de los usuarios con piel seca, mencionando explícitamente que está formulado para piel normal o seca. La "fórmula de equilibrio de humedad" y la hidratación continua son ideales para quien busca una base adaptada a la piel seca. La búsqueda vectorial recuperó con éxito este resultado, no solo por la coincidencia de palabras clave, sino también por el enfoque en la hidratación y la mención específica de la piel seca como grupo objetivo.
</p></li><li><p><strong>Base de SérumDescripción: </strong>Las bases sérum son formulaciones ligeras de cobertura media disponibles en una amplia gama de tonos en 21 tonos. Estas bases ofrecen una cobertura moderada que parece natural y con una sensación de sérum muy ligera. Tienen una viscosidad muy baja y se dispensan con la bomba suministrada o con el gotero de vidrio opcional, disponible para su compra por separado si se prefiere.

<strong>Análisis:</strong> En este caso, la descripción enfatiza una base sérum ligera con un toque natural, que se adapta a las necesidades de las personas con piel seca, ya que suelen buscar productos suaves, hidratantes y que ofrezcan un acabado no empalagoso. La búsqueda vectorial probablemente captó el contexto más amplio de la ligera y la cobertura natural y la textura similar al sérum, que se asocia con la retención de humedad y una aplicación cómoda, lo que la hace relevante para piel seca, aunque el término "piel seca" no se mencione explícitamente.</p></li></ol><h2>Implementación de facetas</h2><p>Los aspectos son esenciales para refinar y filtrar los resultados de búsqueda de forma eficiente, proporcionando a los usuarios una navegación más enfocada, especialmente en escenarios con una gran variedad de productos, como el comercio electrónico. Permiten a los usuarios ajustar los resultados según atributos como categoría, marca o precio, haciendo la búsqueda más precisa. Para implementar esta función, empleamos <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html">agregaciones de términos</a> en los campos <code>category</code> y <code>brand</code> , que se definieron como <code>keyword</code> durante la fase de creación del í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>El código completo de la implementación se puede encontrar <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">aquí</a>.</p><p>A continuación se vean los resultados de la búsqueda de "base para piel seca":</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt31080652a60d8600/6a1702416234e0af7ddb18e7/e8907af359c021eaa38ec7a6a53f10c325ee8ade-1146x1248.png" alt="Resultados facetarios de la búsqueda de &quot;base para piel seca&quot;" /><h2>Personalización de resultados: consultas fijadas</h2><p>En algunos casos, puede ser beneficioso promocionar ciertos productos en los resultados de búsqueda. Para esto, usamos <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-pinned-query.html"><strong>Consultas Fijadas</strong></a>, que permiten que productos específicos aparezcan en la parte superior de los resultados. A continuación, realizaremos una búsqueda del término "Fundación" sin promocionar ningún producto:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt31e75c815262993e/6a170243509168ae42e1b95d/9396c4ed358e7a68eed47f17dd6915d0bad492aa-1600x1157.png" alt="Busca el término &quot;Fundación&quot; sin promocionar ningún producto" /><p>En nuestro ejemplo, podemos promocionar productos que lleven la etiqueta "Sin gluten". Al emplear los identificadores de producto, nos cercioramos de que se prioricen en los resultados de búsqueda. En concreto, promocionaremos los siguientes productos: <strong>Serum Foundation</strong> (ID: 1043), <strong>Coverage Foundation</strong> (ID: 1042) y <strong>Realist Invisible Setting Powder</strong> (ID: 1039).</p>{
   "query":{
      "pinned":{
         "ids":[
            "1043",
            "1042",
            "1039"
         ],
         "organic":{
            "bool":{
               "must":[
                  {
                     "multi_match":{
                        "query":"foundation",
                        "fields":[
                           "name",
                           "category",
                           "description"
                        ]
                     }
                  }
               ]
            }
         }
      }
   }
}<p>Empleamos identificadores de producto específicos para cerciorarnos de que se prioricen en los resultados de la consulta. La estructura de la consulta incluye una lista de IDs de producto que deben estar "fijados" en la parte superior (en este caso, IDs 1043, 1042 y 1039), mientras que los resultados restantes siguen el flujo orgánico de la búsqueda, usando una combinación de condiciones como la consulta de texto en los campos "nombre", "categoría",  y "descripción". De este modo, es posible promocionar los elementos de forma controlada, cerciorando su visibilidad, mientras que el resto de la búsqueda se basa en la relevancia habitual.</p><p>A continuación, puedes ver el resultado de la ejecución de la consulta con los productos promovidos:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt53a6d5cbef227f16/6a1702458b73cb68f0189ef3/8c1a547bfe31360c405eae0891c666635051a51b-1600x1039.png" alt="Resultado de la ejecución de la consulta con los productos promovidos" /><p>El código completo de la consulta se puede encontrar <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">aquí</a>.</p><h2>Análisis del comportamiento de búsqueda con análisis conductual</h2><p>Hasta ahora, ya agregamos funcionalidades para mejorar la relevancia de los resultados de búsqueda y facilitar la descubribilidad del producto. Ahora, finalizaremos nuestra solución de búsqueda incluyendo una función que nos ayudará a analizar el comportamiento de búsqueda de los usuarios, identificando patrones como consultas con o sin resultados y clics en los resultados. Para ello, emplearemos la función <strong>de Análisis de Comportamiento</strong> proporcionada por Elastic. Con él, en solo unos pocos pasos, podemos monitorizar y analizar el comportamiento de búsqueda de los usuarios, obteniendo información valiosa para optimizar la experiencia de búsqueda.</p><h3>Creación de la colección de análisis de comportamiento</h3><p>Nuestra primera acción será crear una colección que será responsable de recibir todos los eventos de análisis de conducta. Para crear la colección, accede a la interfaz Kibana en <strong>Search &gt; Behavioral Analytics</strong>. En el ejemplo siguiente, creamos la colección llamada <code>tracking-search</code>.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9b4cb5480ab0bfef/6a1702474a531b189936a7e7/c05e533212a3690c5ea9f2d5226cbcdc901c482a-1600x1009.png" alt="Análisis de comportamiento: nombrar tu colección" /><h3>Integración del análisis de comportamiento en la interfaz</h3><p>Nuestra aplicación <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> fue desarrollada en JavaScript y, para integrar Behavioral Analytics, seguiremos los pasos descritos en la documentación oficial de Elastic para instalar el <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>Implementación del rastreador JavaScript</h3><p>Ahora, importaremos el cliente tracker a nuestra aplicación y usaremos los métodos <code>trackPageView</code>, <code>trackSearch</code>y <code>trackSearchClick</code> para capturar las interacciones del usuario.</p><p><strong>Aviso legal</strong>: Aunque estamos empleando una herramienta para recopilar datos de interacción de usuarios, es esencial garantizar el cumplimiento del <strong>RGPD</strong>. Esto significa informar claramente a los usuarios sobre qué datos se están recopilando, cómo se emplearán y ofrecer la opción de optar por no participar en el seguimiento. Además, debemos implementar medidas de seguridad estables para proteger la información recopilada y respetar los derechos de los usuarios, como el acceso y la eliminación de datos, cerciorando que todos los pasos cumplan con los principios del RGPD.
</p><p><strong>Paso 1: Creación de la instancia del rastreador</strong></p><p>Primero, crearemos la instancia tracker que monitorizará las interacciones. En esta configuración, definimos el punto final objetivo, el nombre de la colección y la clave API:</p>createTracker({
  endpoint: "https://endpoint:443",
  collectionName: "tracking-search",
  apiKey: "api-key"
});<p><strong>Paso 2: Captura de vistas de página</strong></p><p>Para registrar las visualizaciones de página, podemos configurar el evento <code>trackPageView</code> :</p>    trackPageView({
      page: {
        title: "home-page"
      },
    });<p>Para más detalles sobre el evento <code>trackPageView</code> , puedes consultar esta <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/behavioral-analytics-event-reference.html#behavioral-analytics-event-reference-pageview-fields">documentación</a>.</p><p><strong>Paso 3: Captura de consultas de búsqueda</strong></p><p>Para monitorizar las acciones de búsqueda de los usuarios, emplearemos el método <code>trackSearch</code> :</p>      trackSearch({
        search: {
          query: searchTerm,
          results: {
            items: documents,
            total_results: response.data.length,
          },
        },
      });<p>Aquí estamos recopilando el término de búsqueda y los resultados de la búsqueda.</p><p><strong>Paso 4: Seguimiento de clics en los resultados de búsqueda</strong></p><p>Por último, para capturar clics en los resultados de búsqueda, emplearemos el 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>Recopilamos información sobre el ID del documento al que se hace clic, así como el término de búsqueda y los resultados.</p><h3>Análisis de los datos en Kibana</h3><p>Ahora que se están capturando eventos de interacción de usuarios, podemos obtener datos valiosos sobre las acciones de búsqueda. Kibana emplea la herramienta de Análisis del Comportamiento para visualizar y analizar estos datos conductuales. Para ver los resultados, simplemente navega a <strong>Búsqueda &gt; Análisis de Comportamiento &gt; Mi Colección</strong>, donde se mostrará un resumen de los eventos capturados.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdab4f4507c5a4732/6a17024860084b34ca3c4411/e219c4af2e01b0ccc1b9079459a07832835abc75-1600x1155.png" alt="Análisis de los datos en Kibana" /><p>En esta visión general, obtenemos una visión general de los eventos capturados para cada acción integrada en nuestra interfaz. A partir de esta información, podemos obtener información valiosa sobre el comportamiento de búsqueda de los usuarios. Sin embargo, si quieres crear paneles personalizados con métricas más relevantes para tu escenario específico, Kibana ofrece herramientas poderosas para crear paneles, permitiéndote crear diversas visualizaciones de tus métricas.</p><p>A continuación, creé algunas visualizaciones y gráficos para monitorizar, por ejemplo, los términos más buscados a lo largo del tiempo, consultas que no devolvieron resultados, una nube de palabras que resalta los términos más buscados y, finalmente, una visualización geográfica para identificar de dónde proviene el acceso a las búsquedas.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt04ced4406436f942/6a17024a5091685116e1b961/84a2c39dab77a3f9366c258a3a45d2cbc7df125e-1600x689.png" alt="Visualizaciones y gráficos para monitorizar" /><h2>Conclusión</h2><p>En este artículo, implementamos una solución de búsqueda híbrida que combina búsqueda por palabras clave y vectorial, ofreciendo resultados más precisos y relevantes para los usuarios. También exploramos cómo emplear funciones adicionales, como facetas y personalización de resultados con Consultas Fijadas, para crear una experiencia de búsqueda más completa y eficiente.</p><p>Además, integramos el <strong>Análisis Conductual</strong> de Elastic para capturar y analizar el comportamiento del usuario durante sus interacciones con el motor de búsqueda. Empleando métodos como <code>trackPageView</code>, <code>trackSearch</code>y <code>trackSearchClick</code>, pudimos monitorizar consultas de búsqueda, clics en los resultados y vistas de página, generando información valiosa sobre el comportamiento de búsqueda.</p><h2>Referencias</h2><p>Conjunto de datos</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>Fusión recíproca de rangos</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 fijada</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álisis de Comportamiento</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[Base de datos vectorial]]></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[Implementación de búsqueda semántica: Construcción de una búsqueda de recetas con Elasticsearch]]></title>
    <description><![CDATA[Implementación de la búsqueda semántica en el contexto de sitios web de comercio electrónico.]]></description>
    <content:encoded><![CDATA[<h2>Introducción</h2><p>Muchos sitios web de comercio electrónico están interesados en mejorar su experiencia de búsqueda de recetas. La búsqueda semántica, cuando se aplica correctamente, permite a los clientes encontrar rápidamente los ingredientes necesarios basar en consultas más naturales, como "algo para Santo Valentín" o "comidas de Acción de Gracias".</p><p>En este artículo, demostraremos cómo usar Elasticsearch para implementar una búsqueda semántica que soporte este tipo de consultas. Configuraremos un índice para almacenar el catálogo de ingredientes y productos de un supermercado y demostraremos cómo este índice puede emplear para mejorar la búsqueda de recetas. A lo largo del artículo, explicaremos cómo crear esta estructura de datos y aplicar técnicas de procesamiento de lenguaje natural para proporcionar resultados relevantes alineados con la intención del cliente.</p><p>Todo el código presentado en este artículo fue desarrollado en Python y está disponible en <a href="https://github.com/elastic/elasticsearch-labs/tree/main/supporting-blog-content/building-a-recipe-search-with-elasticsearch">GitHub</a>. Puedes acceder al repositorio para revisar el código fuente, hacer ajustes según sea necesario e implementar las soluciones directamente en tu entorno de desarrollo.</p><h2>Inicio de la implementación de la búsqueda semántica</h2><p>Para empezar a implementar la búsqueda semántica, primero necesitamos definir el modelo del lenguaje natural. Elastic proporciona su propio modelo, <a href="https://www.elastic.co/guide/en/machine-learning/8.15/ml-nlp-elser.html"><strong>ELSER</strong></a>, pero también ofrece soporte para integrar modelos de PLN de varios proveedores, como Hugging Face. Esta flexibilidad te permite elegir la opción que mejor se adapte a tus necesidades.</p><p>En este artículo, emplearemos <strong>ELSER</strong>, que reduce la complejidad de desplegar y gestionar modelos de PLN. Además, Elastic ofrece la <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/semantic-search-semantic-text.html"><strong>función semantic_text</strong></a> , que simplifica mucho el proceso. Con <strong>semantic_text</strong>, todo el proceso de generación de incrustaciones se vuelve sencillo y automatizado. Simplemente necesitas definir un punto de inferencia y especificar el campo que recibirá las incrustaciones en tu mapeo de índice. Durante la indexación de documentos, se generarán incrustaciones que se asociarán automáticamente con el campo especificado.</p><h3>Pasos de preparación</h3><p>A continuación se muestran los pasos para crear un índice con soporte para búsqueda semántica. Siguiendo estas instrucciones, tendrás un índice configurado y listo para búsquedas semánticas:</p><ol><li><p><strong>Crea el </strong><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/infer-service-elser.html"><strong>punto de inferencia</strong></a>.</p></li><li><p><a href="https://github.com/andreluiz1987/semantic-search-market/blob/main/infra.py"><strong>Crea el índice</strong></a>, configurando el campo de descripción como semantic_text para que pueda recibir las incrustaciones.</p></li><li><p><a href="https://github.com/andreluiz1987/semantic-search-market/blob/main/ingestion.py"><strong>Indexa los datos</strong></a> en el índice de catálogos de supermercados, que almacenará un catálogo de productos. Este catálogo se obtuvo a partir de un conjunto de datos disponible <a href="https://www.kaggle.com/datasets/bhavikjikadara/grocery-store-dataset?select=GroceryDataset.csv">aquí</a>.</p></li></ol><h2>Aplicación de la búsqueda semántica en supermercados</h2><p>Ahora que tenemos el índice lleno de datos de productos de supermercados, estamos probando y validando consultas para mejorar los resultados de búsqueda usando búsqueda semántica. Nuestro objetivo es ofrecer una experiencia de búsqueda más inteligente que entienda el contexto y la intención del usuario, ofreciendo resultados más relevantes y precisos.</p><h3>Desafíos resueltos por la búsqueda semántica</h3><p>Basándonos en el catálogo de productos, exploremos cómo la búsqueda semántica puede transformar la experiencia de búsqueda en supermercados abordando cuestiones de vocabulario y contexto con las que la búsqueda léxica tradicional a menudo tiene dificultades.</p><h4><strong>1. Interpretación de intenciones culinarias</strong></h4><p><strong>Problema 01</strong>: Un cliente puede buscar "marisco para asar", pero un sistema de búsqueda léxica puede no comprender completamente la intención detrás de la consulta. Podría no identificar todos los productos de marisco aptos para asar, devolviendo solo aquellos con el término exacto "marisco" o "parrilla" en el título del producto.</p><p>Primero, realizaremos una búsqueda léxica y analizaremos los resultados. Luego, haremos lo mismo con una búsqueda semántica, comparando los resultados del mismo término de búsqueda.</p><p><strong>Consulta de búsqueda léxica</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 búsqueda</p><p>Nombre</p><p>Puntaje</p><p>Léxico</p><p>Pescado del Noroeste del Cangrejo de las Nieves Bairdi de Alaska</p><p>10.453125</p><p>Léxico</p><p>Salsa Gourmet original del señor Yoshida.</p><p>7.2289705</p><p>Léxico</p><p>Pack Premium de Mariscos - 20 piezas</p><p>7.1924105</p><p>Léxico</p><p>Pargo rojo americano - entero, de frente, limpiado</p><p>6.998647</p><p>Léxico</p><p>Pinzas y brazos de langosta, capturados en la naturaleza sostenible</p><p>6.438654</p><p>La búsqueda léxica demostró algunos productos de marisco aptos para asar, como el pargo rojo americano y el cangrejo de nieve bairdi de Alaska de pesca del noroeste. Sin embargo, la búsqueda léxica devolvía productos menos relevantes en la parte superior de la lista, como la salsa Mr. Yoshida, que no es un producto de marisco sino una salsa de carne, lo que sugiere que el algoritmo léxico tuvo dificultades para comprender completamente el contexto de "para asar".</p><p><strong>Solución de búsqueda semántica</strong></p><p>Empleamos una consulta que combina el término "marisco" con contextos de preparación como "asar" para devolver una lista completa de opciones, como filetes de pescado, gambas y vieiras, que son ideales para asar a la parrilla, aunque las palabras "parrilla" o "marisco" no aparezcan directamente en el nombre del producto. Esto cerciora que los resultados de búsqueda se alineen más estrechamente con la intención del cliente.</p><p><strong>Consulta búsqueda semántica:</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 búsqueda</p><p>Nombre</p><p>Puntaje</p><p>Semántica</p><p>Pescado branzino completamente de cabeza</p><p>16.175909</p><p>Semántica</p><p>Bacalao negro de Alaska (pez sable)</p><p>15.855331</p><p>Semántica</p><p>Pargo rojo americano - entero, de frente</p><p>15.454779</p><p>Semántica</p><p>Pescado del Noroeste del Cangrejo de las Nieves Bairdi de Alaska</p><p>15.855331</p><p>Semántica</p><p>Pargo rojo americano - entero, de frente</p><p>15.3892355</p><p>La búsqueda semántica no solo devolvía productos directamente relacionados con el término "marisco", sino que también entendía el contexto de "asar", sacando pescado entero y filetes adecuados para asar. La clave aquí es la precisión de los resultados, que incluían opciones de pescado entero como branzino y bacalao negro de Alaska, ambos comúnmente usados para asar a la parrilla.</p><p><strong>Problema 02 </strong>: Muchos clientes buscan soluciones rápidas y fáciles para cenar tras un largo día de trabajo, usando términos como "comidas fáciles entre semana". La búsqueda léxica tradicional puede no captar completamente el concepto de comidas rápidas, ya que a menudo se centra solo en productos que incluyen la palabra "easy" en su nombre.</p><p>Como hicimos en el problema anterior, comenzaremos realizando una búsqueda léxica. Luego de eso, aplicaremos una solución usando búsqueda semántica.</p><p><strong>Consulta de búsqueda léxica</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 búsqueda</p><p>Nombre</p><p>Puntaje</p><p>Léxico</p><p>Etiquetas de dirección Avery Easy Peel, 4200</p><p>8.017723</p><p>Léxico</p><p>Omeals Comidas de Emergencia/Portátiles con Autocalentamiento 32</p><p>6.592727</p><p>Léxico</p><p>Pesquero costero atún amarillo en cubos</p><p>5.836883</p><p>Léxico</p><p>Espuma de 12 oz de súper peso</p><p>5.8116536</p><p>Léxico</p><p>Servilleta de Vanity Fair para el día a día, 2 capas, 110</p><p>5.752989</p><p>La búsqueda léxica devolvió resultados mucho menos relevantes, incluyendo elementos completamente ajenos a las comidas, como las etiquetas de dirección Avery Easy Peel y las servilletas cotidianas de Vanity Fair. Estos productos no satisfacen la necesidad del usuario de comidas rápidas. Aunque la búsqueda léxica sí devolvió un producto útil (Omeals Self Heating Emergency Meals), otros resultados, como servilletas y etiquetas, solo coincidían con las palabras "fácil" o "noche de semana" en sus descripciones, sin abordar realmente la intención del usuario de una solución de comida rápida.</p><p><strong>Solución de búsqueda semántica</strong></p><p>Implementamos una consulta que entiende la intención detrás de comidas rápidas y sencillas. Asocia productos que pueden preparar rápidamente, como carnes precocinadas, pasta congelada o kits de comida, aunque no incluyan explícitamente la palabra "fácil" en el nombre. Este enfoque garantiza que los clientes encuentren las opciones más adecuadas para cenas rápidas entre semana, atendiendo la necesidad de comodidad.</p><p><strong>Consulta a la búsqueda semántica</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 búsqueda</p><p>Nombre</p><p>Puntaje</p><p>Semántica</p><p>Omeals Comidas de Emergencia/Portátiles con Autocalentamiento 32</p><p>14.610006</p><p>Semántica</p><p>Nissin, Cup Noodles, Gambas, 2,5 oz</p><p>13.751424</p><p>Semántica</p><p>Mezcla de gofres y panqueques sin gluten de Namaste</p><p>13.73376</p><p>Semántica</p><p>Papa de Idaho, papa hashbrowns Golden Grill</p><p>12.549422</p><p>Semántica</p><p>Nissin, Fideos en Taza, Pollo, 24-Count</p><p>12.034527</p><p>La búsqueda semántica devolvió productos claramente relacionados con comidas rápidas y convenientes, como fideos instantáneos (Cup Noodles), papa precocinadas y mezclas para panqueques, que son opciones típicas para cenas fáciles entre semana. Esto demuestra que la búsqueda semántica puede captar el concepto detrás de la frase "comidas fáciles entre semana", captando la intención del usuario de encontrar comidas rápidas y convenientes. Curiosamente, productos de otras categorías, como "refrescos", también pueden incluir cuando sea relevante en el contexto (por ejemplo, bebidas para acompañar las comidas).</p><h4><strong>2. Términos regionales y variaciones de vocabulario</strong></h4><p><strong>Problema</strong>: Un cliente puede buscar "refresco", mientras que otro cliente podría usar "refresco" para el mismo producto. La búsqueda léxica tradicional no reconoce que ambos términos se refieren al mismo elemento.</p><p><strong>Consulta de búsqueda léxica</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 búsqueda</p><p>Nombre</p><p>Puntaje</p><p>Léxico</p><p>Prime Hydration+ Sticks mezcla de bebidas electrolíticas</p><p>14.492869</p><p>Léxico</p><p>Capri Sun, 100% jugo, paquete variado</p><p>12.340851</p><p>Léxico</p><p>Bebida energética Joyburst, Frose Rose, 12</p><p>11.839179</p><p>Léxico</p><p>Kellogg's Pop-Tarts, canela glaseada con azúcar moreno</p><p>9.97788</p><p>Léxico</p><p>Mini barras Kind, pack variado, 0,7</p><p>9.336912</p><p>La búsqueda léxica se centra en coincidencias exactas de palabras. Aunque devolvió productos como Prime Hydration y Capri Sun, la coincidencia directa con el término "pop" también llevó a resultados irrelevantes, como los Kellogg's Pop-Tarts, que son un tentempié y no una bebida. Esto pone de manifiesto cómo la búsqueda léxica puede ser menos efectiva cuando un término tiene múltiples significados o puede ser ambiguo.</p><p><strong>Solución de búsqueda semántica</strong></p><p>En consultas semánticas, podemos superar el problema de las variaciones de vocabulario que la búsqueda léxica no aborda. Al ampliar los términos de búsqueda, podemos obtener resultados basados en el significado contextual, proporcionando respuestas más relevantes y completas.</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 búsqueda</p><p>Nombre</p><p>Puntaje</p><p>Semántica</p><p>Variedad de refrescos Prebióticos de 12 oz de Olipop</p><p>14.776867</p><p>Semántica</p><p>Bai Antioxidant Cocofusion, Pack de variedades, 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 Variedad de Energía, 12 fl oz</p><p>14.007214</p><p>Semántica</p><p>Bebida energética Joyburst, Frose Rose, 12</p><p>13.641038</p><p>La búsqueda semántica devuelve productos que coinciden directamente con el concepto de "pop" como sinónimo de "refresco" (como Olipop Prebiotics Soda), aunque el término exacto "pop" no esté presente en el nombre del producto. La búsqueda entendió la intención del usuario — una bebida refrescante y baja en azúcar — y pudo devolver productos relevantes, incluyendo opciones como refrescos prebióticos (Olipop) y bebidas energéticas sin azúcar (Monster Energy Drink).</p><h2>Conclusión</h2><p>La implementación de la búsqueda semántica en el contexto de supermercados demostró ser muy eficaz para entender consultas complejas como "marisco para asar" y "comidas fáciles entre semana". Este enfoque nos permitió interpretar la intención del usuario con mayor precisión, devolviendo productos altamente relevantes.</p><p>Al usar Elasticsearch y simplificar el proceso con ELSER, pudimos aplicar la búsqueda semántica de forma rápida y eficiente, mejorando significativamente los resultados y proporcionando una experiencia de compra más ágil y dirigida. Esto no solo optimizó el proceso de búsqueda, sino que también aumentó la relevancia de los resultados ofrecidos a los clientes.</p><h2>Referencias</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 datos:</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>Búsqueda 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[Conceptos básicos]]></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[Cómo ingerir datos en Elasticsearch a través de Apache Camel]]></title>
    <description><![CDATA[Aprende a ingir datos en Elasticsearch a través de Apache Camel con un ejemplo práctico.]]></description>
    <content:encoded><![CDATA[<p>La ingestión de datos en Elasticsearch usando Apache Camel es un proceso que combina la robustez de un motor de búsqueda con la flexibilidad de un marco de integración. En este artículo, exploraremos cómo Apache Camel puede simplificar y optimizar la ingestión de datos en Elasticsearch. Para ilustrar esta funcionalidad, implementaremos una aplicación introductoria que demuestra, paso a paso, cómo configurar y usar Apache Camel para enviar datos a Elasticsearch.</p><h2>¿Qué es el camello apache?</h2><p>Apache Camel es un framework de integración de código abierto que simplifica la conexión de sistemas diversos, permitiendo a los desarrolladores centrar en la lógica de negocio sin preocupar por las complejidades de la comunicación del sistema. El concepto central en Camel son las "rutas", que definen el camino que sigue un mensaje desde el origen hasta el destino, incluyendo potencialmente pasos intermedios como transformaciones, validaciones y filtrado.</p><h3>Arquitectura del camello apache</h3><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt05652327efd4d5d1/6a17e6dafbc5f8a588491a8b/bef8145623a8fa80f929f9faa57ce0c460be2d0b-884x458.png" alt="Arquitectura del camello apache" /><p>Camel emplea "componentes" para conectarse a diferentes sistemas y protocolos, como bases de datos y servicios de mensajería, y "endpoints" para representar los puntos de entrada y salida de los mensajes. Estos conceptos proporcionan un diseño modular y flexible, facilitando la configuración y gestión de integraciones complejas de forma eficiente y escalable.</p><h2>Uso de Elasticsearch y Apache Camel</h2><p>Demostraremos cómo configurar una aplicación Java sencilla que emplea Apache Camel para ingirir datos en un clúster de Elasticsearch. También se cubrirán los procesos de creación, actualización y eliminación de datos en Elasticsearch usando rutas definidas en Apache Camel (Apache Camel).</p><h3>1. Agregar dependencias</h3><p>El primer paso para configurar esta integración es agregar las dependencias necesarias al archivo <code>pom.xml</code> de tu proyecto. Esto incluirá las bibliotecas Apache Camel y Elasticsearch. Vamos a usar la nueva biblioteca cliente de Java API, así que debemos importar el componente <code>camel-elasticsearch</code> y la versión debe ser la misma que la de la biblioteca <code>camel-core</code> .</p><p>Si quieres usar el cliente de descanso de bajo nivel de Java, debes emplear el componente de cliente de descanso de bajo nivel de 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. Configuración y ejecución del Camel Context</h3><p>La configuración comienza creando un nuevo contexto Camel usando la clase <code>DefaultCamelContext</code> , que sirve como base para definir y ejecutar rutas. A continuación, configuramos el componente Elasticsearch, que permitirá a Apache Camel interactuar con un clúster de Elasticsearch. La instancia <code>ESlasticsearchComponent</code> está configurada para conectarse a la dirección <code>localhost:9200</code>, que es la dirección predeterminada para un clúster local de Elasticsearch. Para una configuración de entorno que requiera autenticación, deberías leer la documentación sobre cómo configurar el componente y habilitar la autenticación básica, conocida como <strong>"Configurar el componente y habilitar la autenticación 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>Este componente se agrega al contexto de Camel, permitiendo que las rutas definidas empleen este componente para realizar operaciones en Elasticsearch.</p>try (var context = new DefaultCamelContext()) {
   context.addComponent(ESComponent.getName(), ESComponent.getInstance());
   context.addRoutes(new OperationBulkRoute());
   context.start();
}
<p>Después, las rutas se agregan al contexto. Crearemos rutas para la indexación masiva, actualización y eliminación de documentos.</p><h3>3. Configuración de rutas Camel</h3><h4>Indexación de datos</h4><p>La primera ruta que configuraremos es para la indexación de datos. Emplearemos un archivo JSON que contiene un catálogo de películas. La ruta se configurará para leer el archivo ubicado en <a href="https://gist.github.com/andreluiz1987/40756874b5fbea0a29586f9376d7f1f4"><code>src/main/resources/movies.json</code></a>, deserializar el contenido JSON en objetos Java y luego aplicar una estrategia de agregación para combinar múltiples mensajes en uno solo, permitiendo operaciones por lotes en Elasticsearch. Se configuró el tamaño de 500 elementos por mensaje, es decir, el volumen indexará 500 películas a la vez.</p><p>Operación de búsqueda elástica de ruta en masa</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>El lote de documentos se enviará al endpoint de operaciones masivas de Elasticsearch. Este enfoque garantiza eficiencia y rapidez al manejar grandes volúmenes de datos.</p><h4>Actualización de datos</h4><p>La siguiente opción será actualizar los documentos. Indexamos algunas películas en el paso anterior y ahora crearemos nuevas rutas para buscar un documento por código de referencia y luego actualizar el campo de calificación.</p><p>Configuramos un contexto Camel <code>(DefaultCamelContext)</code>, donde se registra un componente de Elasticsearch y se agrega una ruta personalizada llamada IngestionRoute. La operación comienza enviando el código del documento a través de ProducerTemplate, que inicia la ruta desde el punto final direct:update-ingestión.</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>A continuación, tenemos el IngestionRoute, que es el punto final de entrada para este flujo. La ruta realiza varias operaciones por oleoductos. Primero, se realiza una búsqueda en Elasticsearch para localizar el documento por código <code>(direct:search-by-id)</code>, donde el SearchByCodeProcessor ensambla la consulta a partir del código. Después, el documento recuperado es procesado por el UpdateRatingProcessor, que convierte el resultado en objetos Película, actualiza la calificación de la película a un valor específico y prepara el documento actualizado para ser enviado de nuevo a Elasticsearch para su actualización.</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>El procesador <code>SearchByCodeProcessor</code> estaba configurado solo para ejecutar la consulta de búsqueda:</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>El procesador <code>UpdateRatingProcessor</code> es responsable de actualizar el campo de calificación.</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>Eliminación de datos</h4><p>Finalmente, la ruta para eliminar documentos está configurada. Aquí, eliminaremos un documento usando su ID. En Elasticsearch, para eliminar un documento necesitamos conocer el identificador del documento, el índice donde se almacena el documento y ejecutar una solicitud de borrado. En Apache Camel realizaremos esta operación creando una nueva ruta como se muestra a continuación.</p><p>La ruta comienza desde el punto final direct:op-delete, que sirve como punto de entrada. Cuando un documento necesita ser eliminado, su identificador <code>(_id)</code> se recibe en el cuerpo del mensaje. La ruta entonces establece el encabezado indexId con el valor de este identificador usando<code>("${body}")</code>simple , que extrae el _id del cuerpo del mensaje.</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>Finalmente, el mensaje se dirige al punto final especificado por URI_DELETE_OPERATION, que se conecta con Elasticsearch para realizar la operación de eliminación de documentos en el índice correspondiente.
Ahora que creamos la ruta, podemos crear un contexto Camel <code>(DefaultCamelContext)</code>, que está configurado para incluir el 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>A continuación, se agrega la ruta de borrado, definida por la clase <code>OperationDeleteRoute</code> , al contexto. Con el contexto inicializado, se emplea un <code>ProducerTemplate</code> para pasar el identificador del documento que debe eliminar al punto final <code>direct:op-delete</code> , lo que activa la ruta de eliminación.</p><h2>Conclusión</h2><p>La integración entre Apache Camel y Elasticsearch permite una ingesta de datos robusta y eficiente, aprovechando la flexibilidad de Camel para definir rutas que pueden manejar diferentes escenarios de manipulación de datos, como indexación, actualización y eliminación. Con esta configuración, puedes orquestar y automatizar procesos complejos de forma escalable, cerciorando que tus datos se gestionen de forma eficiente en Elasticsearch. Este ejemplo demostró cómo estas herramientas pueden emplear juntas para crear una solución eficiente y adaptable para la ingestión de datos.</p><h2>Referencias</h2><ul><li><p><a href="https://camel.apache.org/manual/">Camello apache</a></p></li><li><p><a href="https://camel.apache.org/manual/architecture.html">Arquitectura del camello apache</a></p></li><li><p><a href="https://camel.apache.org/components/4.4.x/eips/aggregate-eip.html">Camello apache agregado</a></p></li><li><p><a href="https://camel.apache.org/components/4.4.x/file-component.html">Componente de archivo</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[Datos de índice]]></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>