Como ingerir dados no Elasticsearch através do LlamaIndex
Um guia passo a passo sobre como ingerir dados e realizar buscas usando RAG com LlamaIndex.
Neste artigo, implementaremos um mecanismo de busca para FAQs usando o LlamaIndex para indexar os dados. O Elasticsearch servirá como nosso banco de dados de vetores, permitindo a busca vetorial, enquanto o RAG (Retrieval-Augmented Generation) enriquecerá o contexto, fornecendo respostas mais precisas.

O que é o LlamaIndex?
O LlamaIndex é uma estrutura que facilita a criação de agentes e fluxos de trabalho baseados em Modelos de Linguagem de Grande Porte (LLMs, na sigla em inglês) para interagir com dados específicos ou privados. Permite a integração de dados de diversas fontes (APIs, PDFs, bases de dados) com LLMs, possibilitando tarefas como pesquisa, extração de informações e geração de respostas contextualizadas.
Conceitos-chave:
Agentes: Assistentes inteligentes que utilizam LLMs para executar tarefas, desde respostas simples até ações complexas.
Fluxos de trabalho: Processos de várias etapas que combinam agentes, conectores de dados e ferramentas para tarefas avançadas.
Aumento de contexto: uma técnica que enriquece o modelo de aprendizagem linear (LLM) com dados externos, superando suas limitações de treinamento.
Integração do LlamaIndex com o Elasticsearch:
O Elasticsearch pode ser usado de diversas maneiras com o LlamaIndex:
Fonte de dados: Utilize o Elasticsearch Reader para extrair os documentos.
Modelo de embeddings: Codifica dados em vetores para buscas semânticas.
Armazenamento vetorial: Utilize o Elasticsearch como repositório para busca de documentos vetorizados.
Armazenamento avançado: configure estruturas como resumos de documentos ou grafos de conhecimento.
Utilizando LlamaIndex e Elasticsearch para construir uma busca de perguntas frequentes (FAQ).
Preparação de dados
Usaremos as Perguntas Frequentes do Elasticsearch Service como exemplo. Cada pergunta foi extraída do site e salva em um arquivo de texto individual. Você pode usar qualquer abordagem para organizar os dados; neste exemplo, optamos por salvar os arquivos localmente.
Arquivo de exemplo:
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.Após salvar todas as perguntas, o diretório ficará assim:

Instalação de dependências
Implementaremos a ingestão e a pesquisa usando a linguagem Python, sendo a versão utilizada a 3.9. Como pré-requisito, será necessário instalar as seguintes dependências:
llama-index-vector-stores-elasticsearch
llama-index
openaiO Elasticsearch e o Kibana serão criados com o Docker, configurados via docker-compose.yml para executar a versão 8.16.2. Isso facilita a criação do ambiente local.
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:Ingestão de documentos usando LlamaIndex
Os documentos serão indexados no Elasticsearch usando o LlamaIndex. Primeiro, carregamos os arquivos com SimpleDirectoryReader, que permite carregar arquivos de um diretório local. Após carregar os documentos, iremos indexá-los usando o 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)Os Vector Stores no LlamaIndex são responsáveis por armazenar e gerenciar incorporações de documentos. O LlamaIndex suporta diferentes tipos de armazenamentos vetoriais e, neste caso, usaremos o Elasticsearch. No StorageContext, configuramos a instância do Elasticsearch. Como o contexto é local, não foram necessários parâmetros adicionais. Para configurações em outros ambientes, consulte a documentação para verificar os parâmetros necessários: Configuração do ElasticsearchStore.
Por padrão, o LlamaIndex usa o modelo text-embedding-ada-002 da OpenAI para gerar embeddings. No entanto, neste exemplo, usaremos o modelo text-embedding-3-small . É importante ressaltar que será necessária uma chave de API da OpenAI para usar o modelo.
Abaixo está o código completo para ingestão 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)Após a execução, os documentos serão indexados no índice de perguntas frequentes , conforme mostrado abaixo:

Pesquisar com RAG
Para realizar buscas, configuramos o cliente ElasticsearchStore , definindo os campos index_name e es_url com a URL do Elasticsearch. Em retrieval_strategy, definimos a AsyncDenseVectorStrategy para buscas vetoriais. Outras estratégias, como AsyncBM25Strategy (busca por palavra-chave) e AsyncSparseVectorStrategy (vetores esparsos), também estão disponíveis. Mais detalhes podem ser encontrados na documentação oficial.
es = ElasticsearchStore(
index_name="faq",
es_url="http://localhost:9200",
retrieval_strategy=AsyncDenseVectorStrategy(
)
)Em seguida, será criado um objeto VectorStoreIndex , onde configuraremos o vector_store usando o objeto ElasticsearchStore. Com o método as_retriever , realizamos a busca pelos documentos mais relevantes para uma consulta, definindo o número de resultados retornados para 5 através do 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)O próximo passo é o RAG. Os resultados da busca vetorial são incorporados a um prompt formatado para o LLM, permitindo uma resposta contextualizada com base nas informações recuperadas.
No PromptTemplate, definimos o formato do prompt, que inclui:
Contexto ({context_str}): documentos recuperados pelo recuperador.
Consulta ({query_str}): a pergunta do usuário.
Instruções: diretrizes para o modelo responder com base no contexto, sem depender de conhecimento externo.
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: "
)Por fim, o LLM processa a solicitação e retorna uma resposta precisa e contextualizada.
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)O código completo está abaixo:
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)Agora podemos realizar nossa busca, por exemplo, "Os serviços da Elastic são gratuitos?" e obter uma resposta contextualizada com base nos próprios dados das perguntas frequentes.
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 gerar esta resposta, foram utilizados os seguintes 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.Conclusão
Utilizando o LlamaIndex, demonstramos como criar um sistema de busca de FAQs eficiente com suporte para o Elasticsearch como banco de dados vetorial. Os documentos são ingeridos e indexados usando incorporações, possibilitando buscas vetoriais. Por meio de um PromptTemplate, os resultados da pesquisa são incorporados ao contexto e enviados ao LLM, que gera respostas precisas e contextualizadas com base nos documentos recuperados.
Este fluxo de trabalho integra a recuperação de informações com a geração de respostas contextualizadas para fornecer resultados precisos e relevantes.
Referências
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/
Perguntas frequentes
O que é o LlamaIndex?
O LlamaIndex é uma estrutura que facilita a criação de agentes e fluxos de trabalho baseados em Modelos de Linguagem de Grande Porte (LLMs, na sigla em inglês) para interagir com dados específicos ou privados.
É possível integrar o LlamaIndex com o Elasticsearch?
Sim, o Elasticsearch pode ser usado de várias maneiras com o LlamaIndex, incluindo como fonte de dados (usando o Elasticsearch Reader para extrair documentos), como modelo de incorporação (codificando dados em vetores para buscas semânticas), como armazenamento vetorial (usando o Elasticsearch como repositório para busca de documentos vetorizados) e para armazenamento avançado (configurando estruturas como resumos de documentos ou grafos de conhecimento).




