No dia de hoje, na era digital, profissionais de todas as indústrias precisam se manter atualizados com eventos, conferências e workshops que estão por vir. No entanto, encontrar eventos que se alinhem com os interesses de alguém diante do vasto oceano de informações online representa um desafio significativo.
Este blog apresenta uma solução inovadora para esse desafio: um aplicativo abrangente projetado para coletar dados de eventos do Facebook e analisar esses dados coletados usando MyScale. Embora MyScale seja comumente associado à pilha de tecnologia RAG ou utilizado como um banco de dados vetorial, suas capacidades vão além desses domínios. Utilizaremos-o para análise de dados, aproveitando sua funcionalidade de busca vetorial para analisar eventos que são semanticamente similares, fornecendo assim resultados e insights melhores.
Você pode perceber que Grok AI utilizou o banco de dados vetorial Qdrant como mecanismo de busca para recuperar informações em tempo real a partir de dados da X (anteriormente conhecida como Twitter). Você também pode avaliar o poder dos bancos de dados vetoriais desta maneira com MyScale, integrando MyScale com outras plataformas como Apify para aprimorar tarefas diárias através do desenvolvimento de aplicativos personalizados simples.
Então, neste blog, vamos desenvolver um aplicativo que recebe apenas o nome de uma cidade como entrada e raspa todos os eventos relacionados do Facebook. Posteriormente, realizaremos a análise de dados e busca semântica usando as avançadas capacidades vetoriais SQL de MyScale.
Ferramentas e Tecnologias
Vamos usar várias ferramentas, incluindo Apify, MyScale e OpenAI, para desenvolver este aplicativo útil.
- Apify: Uma plataforma popular de web scraping e automação que significativamente simplifica o processo de coleta de dados. Ela oferece a capacidade de raspar dados e, em seguida, alimentá-los em LLMs. Isso nos permite treinar LLMs com dados em tempo real e desenvolver aplicativos.
- MyScale: MyScale é um banco de dados vetorial SQL que usamos para armazenar e processar dados estruturados e não estruturados de forma otimizada.
- OpenAI: Usaremos o modelo
text-embedding-3-small
da OpenAI para obter os embeddings do texto e, em seguida, salvar esses embeddings no MyScale para análise de dados e pesquisa semântica.
Como Configurar MyScale e Apify
Para começar a configurar MyScale e Apify, você precisará criar um novo diretório e um arquivo Python. Você pode fazer isso abrindo seu terminal ou linha de comando e inserindo os seguintes comandos:
mkdir MyScale
cd MyScale
touch main.ipynb
Vamos instalar os pacotes. Copie o comando abaixo e cole-o em seu terminal. Esses pacotes fornecerão as ferramentas e bibliotecas necessárias para desenvolver nosso aplicativo.
pip install openai apify-client clickhouse-connect pandas numpy
Isso deve instalar todas as dependências em seu sistema. Para confirmar se tudo está instalado corretamente, você pode inserir o seguinte comando em seu terminal.
pip freeze | egrep '(openai|apify-client|clickhouse-connect|pandas|numpy)'
Isso deve incluir todas as dependências instaladas com suas versões. Se você identificar alguma dependência ausente, pode ser necessário reexecutar o comando de instalação para esse pacote específico. Agora, estamos prontos para escrever nosso código após as instalações.
Nota: Estaremos trabalhando em um notebook Python. Considere cada bloco de código como uma célula de notebook.
Como Coletar Dados com Apify
Agora, usaremos a API do Apify para coletar dados de eventos de Nova York usando raspador de Eventos do Facebook.
import pandas as pd
from apify_client import ApifyClient
# Inicialize o ApifyClient com seu token de API
client = ApifyClient("Enter_your_apify_key_here")
# Prepare a entrada do Ator
run_input = {
"searchQueries": ["Sport New York"],
"startUrls": [],
"maxEvents": 50,
}
# Execute o Ator e espere que ele termine
run = client.actor("UZBnerCFBo5FgGouO").call(run_input=run_input)
df_columns = ['Name', 'Datetime', 'Description', 'Users_Going', 'Users_Interested', 'Users_Responded', 'City', 'Organized_By', 'Street_Address']
dataframe1 = pd.DataFrame(columns=df_columns)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
# Use uma compreensão de dicionário para substituir valores None por uma string vazia
row = {
'Name': item.get('name', ''),
'Datetime': item.get('dateTimeSentence', ''),
'Description': item.get('description', ''),
'Users_Going': item.get('usersGoing', ''),
'Users_Interested': item.get('usersInterested', ''),
'Users_Responded': item.get('usersResponded', ''),
'City': item.get('location', {}).get('city', '') if item.get('location') else '',
'Organized_By': item.get('organizedBy', ''),
'Street_Address': item.get('location', {}).get('streetAddress', '') if item.get('location') else ''
}
# Garanta que todos os valores None sejam substituídos por uma string vazia
row = {k: (v if v is not None else '') for k, v in row.items()}
dataframe1 = dataframe1._append(row, ignore_index=True)
# Limpe os dados
dataframe1['Description'] = dataframe1['Description'].replace('\\n', '', regex=True)
Este script nos fornece os detalhes dos próximos eventos na forma de um DataFrame pandas
.
Observação: Não se esqueça de adicionar sua chave de API do Apify no script acima. Você pode encontrar seu token de API na página Integrações no Console do Apify.
Pré-processamento de Dados
Ao coletar dados brutos, eles vêm em vários formatos. Neste script, vamos trazer as datas de eventos para um único formato para que nossa filtragem de dados possa ser feita de forma mais eficiente.
# Importar bibliotecas necessárias para manipulação de dados e análise de datas
import pandas as pd
import numpy as np
from datetime import datetime
from dateutil import parser
# Função para analisar strings de datas que podem representar um intervalo ou uma única data
def parse_dates(date_str):
# Verificar se a string de data contém um traço, indicando um intervalo
if '-' in date_str:
parts = date_str.split('-')
# Se a string se dividir em duas partes, é um intervalo válido
if len(parts) == 2:
try:
# Analisar datas de início e fim, formatando-as em um formato legível
start_date = parser.parse(parts[0], fuzzy=True).strftime('%a, %b %d')
end_date = parser.parse(parts[1], fuzzy=True).strftime('%a, %b %d')
return start_date, end_date
except ValueError:
# No caso de erro de análise, não faça nada (será tratado abaixo)
pass
# Se não for um intervalo ou se a análise do intervalo falhar, tente analisar como uma única data
try:
parsed_date = parser.parse(date_str, fuzzy=True)
# Formate a data única para start_date e de forma diferente para end_date
start_date = parsed_date.strftime('%a, %b %d AT %I:%M %p EDT')
end_date = parsed_date.strftime('%a, %b %d') # Omitting time for end_date
return start_date, end_date
except ValueError:
# Retorne NaN para ambas as datas se a análise falhar
return np.nan, np.nan
# Função para extrair data detalhada, hora e dia de uma string de data
def extract_date_time_day(date_str):
try:
# Analisar a string de data, permitindo alguma flexibilidade no formato de entrada
parsed_date = parser.parse(date_str, fuzzy=True)
# Extrair e formatar as partes de data, hora e dia
date = parsed_date.strftime('%Y-%m-%d')
day = parsed_date.strftime('%a')
# Determinar se a string original incluiu um componente de hora
time_component = parsed_date.strftime('%I:%M %p') not in date_str
time = parsed_date.strftime('%H:%M:%S') if not time_component else np.nan
except ValueError:
# Se a análise falhar, defina data, hora e dia como NaN
date, time, day = np.nan, np.nan, np.nan
return date, time, day
# Aplicar a função parse_dates em todo o dataframe, criando novas colunas para datas de início e fim
dataframe1[['Start_Date', 'End_Date']] = dataframe1.apply(lambda row: pd.Series(parse_dates(row['Datetime'])), axis=1)
# Excluir linhas onde Start_Date é NaN, indicando que a análise foi mal-sucedida
dataframe = dataframe1.dropna(subset=['Start_Date'])
# Aplicar extract_date_time_day para dividir as datas de início e fim em colunas separadas de data, hora e dia
dataframe['Start_Date'], dataframe['Start_Time'], dataframe['Start_Day'] = zip(*dataframe['Start_Date'].apply(extract_date_time_day))
dataframe['End_Date'], _, dataframe['End_Day'] = zip(*dataframe['End_Date'].apply(extract_date_time_day))
# Remover a coluna original 'Datetime' como não é mais necessária
dataframe=dataframe.drop(['Datetime'], axis=1)
# Converter 'Start_Date' e 'End_Date' para formato datetime, extraindo apenas a parte da data
dataframe['Start_Date'] = pd.to_datetime(dataframe['Start_Date']).dt.date
dataframe['End_Date'] = pd.to_datetime(dataframe['End_Date']).dt.date
# Converter 'Start_Time' para formato datetime, mantendo a informação de hora
dataframe['Start_Time'] = pd.to_datetime(dataframe['Start_Time'])
Este trecho de código utiliza o pandas
com os pacotes datetime
e dateutil
do Python para formatar os dados.
Gerando Embeddings
Para entender e pesquisar eventos profundamente, geraremos embeddings a partir de suas descrições usando o text-embedding-3-small
. Esses embeddings capturam a essência semântica de cada evento, ajudando o aplicativo a retornar resultados melhores.
# Importar a biblioteca OpenAI para acesso à API.
from openai import OpenAI
# Inicializar o cliente OpenAI com uma chave de API.
openai_client = OpenAI(api_key="your_openai_api_key_here")
# Função para obter embeddings de texto
def get_embedding(text, model="text-embedding-3-small"):
return openai_client.embeddings.create(input=text, model=model).data
embeddings = get_embedding(dataframe["Description"].tolist())
# Extrair vetores de embedding do objeto de embeddings
vectors = [embedding.embedding for embedding in embeddings]
array = np.array(vectors)
embeddings_series = pd.Series(list(array))
# Adicionar embeddings como uma nova coluna no DataFrame.
dataframe['Description_Embeddings'] = embeddings_series
Agora, inseriremos o novo DataFrame
com embeddings no MyScale.
Conectando com MyScale
Como discutido no início, usaremos o MyScale como um banco de dados vetorial para armazenar e gerenciar dados. Aqui, nos conectaremos ao MyScale em preparação para o armazenamento de dados.
import clickhouse_connect
client = clickhouse_connect.get_client(
host='host_name_here',
port=443,
username='username_here',
password='passwd_here'
)
Esta configuração de conexão garante que nosso aplicativo possa se comunicar com o MyScale e usar o poder do SQL para manipulação e análise de dados.
Nota: Consulte Detalhes da Conexão para obter mais informações sobre como conectar-se ao cluster MyScale.
Criar Tabelas e Índices Usando MyScale
Agora criamos uma tabela de acordo com nosso DataFrame. Todos os dados serão armazenados nesta tabela, incluindo os embeddings.
client.command("""
CREATE TABLE default.Events (
Name String,
Description String,
Users_Going Int64,
Users_Interested Int64,
Users_Responded Int64,
City String,
Organized_By String,
Street_Address String,
Start_Date Date32,
End_Date Nullable(Date32),
Start_Time Nullable(DateTime64),
Start_Day String,
End_Day String,
Description_Embeddings Array(Float32),
CONSTRAINT check_data_length CHECK length(Description_Embeddings) = 1536
) ENGINE = MergeTree()
ORDER BY (Name);
""")
As declarações SQL acima criam uma tabela chamada Events
no cluster. O CONSTRAINT
garante que todos os vetores de incorporação tenham o mesmo comprimento 1536
.
Armazenando os Dados e Criando um Índice no MyScale
Neste passo, inserimos os dados processados no MyScale. Isso envolve a inserção em lote dos dados para garantir um armazenamento e recuperação eficientes.
batch_size = 10 # Adjust based on your needs
num_batches = len(dataframe) // batch_size
for i in range(num_batches):
start_idx = i * batch_size
end_idx = start_idx + batch_size
batch_data = dataframe[start_idx:end_idx]
# print(batch_data["Description_Embeddings"])
client.insert("default.Events", batch_data.to_records(index=False).tolist(), column_names=batch_data.columns.tolist())
print(f"Batch {i+1}/{num_batches} inserted.")
client.command("""
ALTER TABLE default.Events
ADD VECTOR INDEX vector_index Description_Embeddings
TYPE MSTG
""")
Usando pandas
, o código acima transfere eficientemente nosso conjunto de dados preparado para o banco de dados MyScale.
Análise de Dados Usando MyScale
Finalmente, utilizamos as capacidades analíticas do MyScale para realizar análise e habilitar a pesquisa semântica. Executando consultas SQL, podemos analisar eventos com base em tópicos, localizações e datas. Então, vamos tentar escrever algumas consultas.
Consulta SQL Simples
Vamos primeiro tentar obter os 10 primeiros resultados da tabela.
results=client.query("""
SELECT Name,Description FROM default.Events LIMIT 10
""")
for row in results.named_results():
print(row["Name"])
print(row['Description'])
Esta consulta retornará simplesmente os 10 primeiros resultados da tabela events
.
Descobrir Eventos por Relevância Semântica
Vamos tentar encontrar os 10 próximos eventos com uma vibe semelhante a um evento de referência, como este: “Um dos Shows Mais Longos em Atividade no País – Funcionando desde 1974 …AGORA em nosso 50º ANO !!! Nosso Schenectady”. Isso é alcançado comparando as incorporações semânticas das descrições de eventos, garantindo um ajuste em temas e emoções.
embeddings=get_embedding(["One of the Longest Running Shows in the Country - Operating since 1974 ...NOW our 50th YEAR !!!Our Schenectady"])
embedding=embeddings[0].embedding
results = client.query(f"""
SELECT Name, Description,
distance(Description_Embeddings, {embedding}) as dist FROM default.Events ORDER BY dist LIMIT 10
""")
for row in results.named_results():
print("Title of the event ", row["Name"])
print("Description of the event ", row['Description'])
print("Distance : ", row["dist"])
Eventos em Destaque por Popularidade
Essa consulta classifica os 10 principais eventos pelo número de participantes e usuários interessados, destacando eventos populares de festivais de grandes cidades a conferências importantes. É ideal para aqueles que procuram ingressar em grandes encontros energéticos.
results = client.query(f"""
SELECT Name, City, Users_Going, Users_Interested, Users_Responded
FROM default.Events
ORDER BY Users_Going DESC, Users_Interested DESC
LIMIT 10
""")
for row in results.named_results():
print("Event Name ", row["Name"])
print("City ", row["City"])
print("Users Going ", row["Users_Going"])
print("Interested Users ", row["Users_Interested"])
Eventos Populares Locais em Nova York
Combinando relevância e popularidade, esta consulta identifica eventos similares em Nova York relacionados a um evento específico e os classifica por participação, oferecendo uma lista cuidadosamente selecionada de eventos que refletem a vibrante cultura da cidade e atraem interesse local.
embeddings=get_embedding(["One of the Longest Running Shows in the Country - Operating since 1974 ...NOW our 50th YEAR !!!Our Schenectady"])
embeddi=embeddings[0].embedding
results = client.query(f"""
SELECT Name,City, Description, Users_Going,distance(Description_Embeddings, {embeddi}) as dist
FROM default.Events
WHERE City LIKE '%New York%' and dist < 1.5
ORDER BY Users_Going DESC,dist
LIMIT 10
""")
for row in results.named_results():
print("Event Name ", row["Name"])
print("Description ", row["Description"])
print("Users Going ", row["Users_Going"])
Organizadores de Eventos Líderes
Esta consulta classifica os 10 principais organizadores de eventos pelo número total de participantes e usuários interessados, destacando aqueles que se destacam na criação de eventos cativantes e atraem grandes audiências. Fornece insights para planejadores de eventos e participantes interessados em eventos de primeira linha.
# Qual cliente atraiu o maior número de usuários
results = client.query(f"""
SELECT Organized_By, SUM(Users_Going + Users_Interested) AS Total_Users
FROM default.Events
GROUP BY Organized_By
ORDER BY Total_Users DESC
Limit 10
""")
for row in results.named_results():
print("Event Name ", row["Organized_By"])
print("Total_Users ", row["Total_Users"])
Implementar RAG
Anteriormente, exploramos o MyScale para análise de dados, destacando suas capacidades de aprimorar nossos fluxos de trabalho de dados. Avançando, daremos um passo adiante implementando a Geração Aumentada por Recuperação (RAG, na sigla em inglês), uma estrutura inovadora que combina uma base de conhecimento externa com LLMs. Este passo ajudará você a entender melhor seus dados e a encontrar insights mais detalhados. Em seguida, você verá como usar o RAG com o MyScale, o que tornará o trabalho com dados mais interessante e produtivo.
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
query="Can you please suggest me some events related to basketball"
# Use o método get_embedding definido acima, que aceita uma lista de sentenças
embeddings=get_embedding([query])
embeddings=embeddings[0].embedding
results = client.query(f"""
SELECT Name, City, Users_Going, Description, distance(Description_Embeddings, {embeddings}) as dist
FROM default.Events
ORDER BY Users_Going DESC,dist
LIMIT 5
""")
PROMPT_TEMPLATE = """
Your objective is to formulate a response to a question using only the information provided below:
{context}
---
Your task is to carefully analyze the provided context and provide an answer to the following question based solely on the information given:
{question}
"""
# Combine as descrições dos principais resultados.
descriptions = [row["Description"] for row in results.named_results()]
context_text = "\n\n---\n\n".join(descriptions)
prompt_template = ChatPromptTemplate.from_template(PROMPT_TEMPLATE)
prompt = prompt_template.format(context=context_text, question=query)
model = ChatOpenAI(openai_api_key="your_api_key_here")
response_text = model.predict(prompt)
formatted_response = f"Response: {response_text}\n"
print(formatted_response)
Ao longo deste blog, observamos que o MyScale é muito mais do que um banco de dados vetorial que pode ser usado para desenvolver todos os tipos de aplicações. Podemos usá-lo como um banco de dados SQL simples ou para aplicações avançadas de IA, abrangendo a maior parte do domínio de desenvolvimento. Encorajamos você a experimentar e explorar os recursos avançados inscrevendo-se na camada gratuita e obtendo 5 milhões de armazenamento vetorial gratuito.
Conclusão
Exploramos as habilidades e funcionalidades do MyScale com o Apify Scraper através do processo de desenvolvimento de uma aplicação de análise de eventos. O MyScale demonstrou suas capacidades excepcionais em pesquisa vetorial de alto desempenho, mantendo todas as funcionalidades dos bancos de dados SQL, o que ajuda os desenvolvedores a fazer pesquisas semânticas usando a sintaxe SQL familiar com muito mais velocidade e precisão.
As capacidades de MyScale não se limitam a este aplicativo: você pode adotá-lo para desenvolver qualquer aplicativo de IA usando o método RAG.
Se você tiver algum feedback ou sugestões, entre em contato conosco.
Source:
https://dzone.com/articles/performing-advanced-facebook-event-data-analysis-w