Cómo ingerir datos en Elasticsearch a través de LlamaIndex
Un paso a paso sobre cómo ingerir datos y buscar usando RAG con LlamaIndex.
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.

¿Qué es LlamaIndex?
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.
Conceptos clave:
Agentes: Asistentes inteligentes que emplean LLMs para realizar tareas, desde respuestas simples hasta acciones complejas.
Flujos de trabajo: Procesos de varios pasos que combinan agentes, conectores de datos y herramientas para tareas avanzadas.
Aumento de contexto: Una técnica que enriquece el LLM con datos externos, superando sus limitaciones de entrenamiento.
Integración de LlamaIndex con Elasticsearch:
Elasticsearch puede usar de varias formas con LlamaIndex:
Fuente de datos: Emplea el Elasticsearch Reader para extraer documentos.
Modelo de incrustaciones: Codificar datos en vectores para búsquedas semánticas.
Almacenamiento vectorial: Emplea Elasticsearch como repositorio para buscar documentos vectorizados.
Almacenamiento avanzado: Configurar estructuras como resúmenes de documentos o grafos de conocimiento.
Uso de LlamaIndex y Elasticsearch para crear una búsqueda de preguntas frecuentes
Preparación de datos
Usaremos como ejemplo las preguntas frecuentes de Elasticsearch Service . 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.
Archivo de ejemplo:
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.Luego de almacenar todas las preguntas, el directorio se verá así:

Instalación de dependencias
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:
llama-index-vector-stores-elasticsearch
llama-index
openaiElasticsearch 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.
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:Ingesta de documentos usando LlamaIndex
Los documentos se indexarán en Elasticsearch usando LlamaIndex. Primero, cargamos los archivos con SimpleDirectoryReader, que permite cargar archivos desde un directorio local. Luego de cargar los documentos, los indexaremos usando el VectorStoreIndex.
documents = SimpleDirectoryReader("./faq").load_data()
storage_context = StorageContext.from_defaults(vector_store=es)
index = VectorStoreIndex(documents, storage_context=storage_context, embed_model=embed_model)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: ElasticsearchStore Configuration.
Por defecto, LlamaIndex emplea el modelo OpenAI text-embedding-ada-002 para generar embeddings. Sin embargo, en este ejemplo, usaremos el modelo text-embedding-3-small . Es importante señalar que se requerirá una clave API de OpenAI para usar el modelo.
A continuación se muestra el código completo para la ingestión de documentos.
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)Tras la ejecución, los documentos se indexarán en el índice de preguntas frecuentes como se muestra a continuación:

Búsqueda con RAG
Para realizar búsquedas, configuramos el cliente ElasticsearchStore , configurando los campos index_name y es_url con la URL de Elasticsearch. En retrieval_strategy, definimos la AsyncDenseVectorStrategy para búsquedas vectoriales. También están disponibles otras estrategias, como AsyncBM25Strategy (búsqueda por palabras clave) y AsyncSparseVectorStrategy (vectores dispersos). Se pueden encontrar más detalles en la documentación oficial.
es = ElasticsearchStore(
index_name="faq",
es_url="http://localhost:9200",
retrieval_strategy=AsyncDenseVectorStrategy(
)
)A continuación, se creará un objeto VectorStoreIndex , donde configuramos el vector_store usando el objeto ElasticsearchStore. Con el método as_retriever , realizamos la búsqueda de los documentos más relevantes para una consulta, estableciendo el número de resultados devueltos a 5 mediante el parámetro similarity_top_k .
index = VectorStoreIndex.from_vector_store(vector_store=es)
retriever = index.as_retriever(similarity_top_k=5)
results = retriever.retrieve(query)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.
En la PromptPlantilla, definimos el formato del prompt, que incluye:
Contexto ({context_str}): documentos recuperados por el recuperador.
Consulta ({query_str}): la pregunta del usuario.
Instrucciones: pautas para que el modelo responda según el contexto, sin depender de conocimientos externos.
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: "
)Finalmente, el LLM procesa el prompt y devuelve una respuesta precisa y contextual.
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)El código completo se encuentra a continuación:
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)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í.
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.Para generar esta respuesta, se emplearon los siguientes documentos:
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 & 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.Conclusión
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.
Este flujo de trabajo integra la recuperación de información con la generación contextualizada de respuestas para ofrecer resultados precisos y relevantes.
Referencias
https://www.elastic.co/guide/en/cloud/current/ec-faq-getting-started.html
https://docs.llamaindex.ai/en/stable/api_reference/readers/elasticsearch/
https://docs.llamaindex.ai/en/stable/module_guides/indexing/vector_store_index/
https://docs.llamaindex.ai/en/stable/examples/query_engine/custom_query_engine/
Preguntas frecuentes
¿Qué es LlamaIndex?
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.
¿Se puede integrar LlamaIndex con Elasticsearch?
Sí, Elasticsearch puede emplear de diversas formas con LlamaIndex, incluyendo como fuente de datos (usando el Elasticsearch Reader para extraer documentos), como modelo de incrustaciones (codificando datos en vectores para búsquedas semánticas), como almacenamiento vectorial (usando Elasticsearch como repositorio para buscar documentos vectorizados) y para almacenamiento avanzado (configuración de estructuras como resúmenes de documentos o grafos de conocimiento).




