Realizando Análise Avançada de Dados de Eventos do Facebook com uma Base de Dados Vetorial

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:

Shell

 

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.

Shell

 

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.

Shell

 

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

Python

 

     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.

Python

 

     # 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.

Python

 

     # 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.

Python

 

     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.

Python

 

     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.

Python

 

     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.

Python

 

     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.

Python

 

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.

Python

 

     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.

Python

 

     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.

Python

 

     # 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.

Python

 

     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