Eseguire un’analisi avanzata dei dati degli eventi di Facebook con un database vettoriale

Nell’era digitale di oggi, i professionisti in tutti i settori devono rimanere aggiornati su eventi imminenti, conferenze e workshop. Tuttavia, trovare efficientemente eventi che corrispondono ai propri interessi nel vasto oceano di informazioni online rappresenta una sfida significativa.

Questo blog introduce una soluzione innovativa a questa sfida: un’applicazione completa progettata per estrarre dati sugli eventi da Facebook e analizzare i dati estratti utilizzando MyScale. Mentre MyScale è comunemente associato alla pila tecnologica RAG o utilizzato come database vettoriale, le sue capacità si estendono oltre questi ambiti. Utilizzeremo MyScale per l’analisi dei dati, sfruttando la sua funzionalità di ricerca vettoriale per analizzare eventi semanticamente simili, fornendo così risultati e insight migliori.

Potreste notare che Grok AI ha utilizzato il database vettoriale Qdrant come motore di ricerca per recuperare informazioni in tempo reale da X (precedentemente conosciuto come Twitter). Potete anche valutare il potere dei database vettoriali in questo modo con MyScale integrando MyScale con altre piattaforme come Apify per migliorare le attività quotidiane attraverso lo sviluppo di semplici applicazioni personalizzate.

Quindi in questo blog, sviluppiamo un’applicazione che accetta solo il nome di una città come input e estrae tutti gli eventi correlati da Facebook. Successivamente, condurremo un’analisi dei dati e una ricerca semantica utilizzando le avanzate funzionalità SQL vettoriali di MyScale.

Strumenti e Tecnologie

Utilizzeremo diversi strumenti, tra cui Apify, MyScale e OpenAI, per sviluppare questa utile applicazione.

  • Apify: Una popolare piattaforma web scraping e di automazione che semplifica notevolmente il processo di raccolta dei dati. Offre la capacità di estrarre dati e successivamente iniettarli nei LLMs. Ciò ci consente di addestrare i LLMs su dati in tempo reale e sviluppare applicazioni.
  • MyScale: MyScale è un database vettoriale SQL che utilizziamo per memorizzare e elaborare sia dati strutturati che non strutturati in modo ottimizzato.
  • OpenAI: Utilizzeremo il modello text-embedding-3-small di OpenAI per ottenere gli embedding del testo e poi salvarli in MyScale per l’analisi dei dati e la ricerca semantica.

Come Configurare MyScale e Apify

Per iniziare a configurare MyScale e Apify, dovrai creare una nuova directory e un file Python. Puoi fare ciò aprendo il tuo terminale o linea di comando ed immettendo i seguenti comandi:

Shell

 

mkdir MyScale
cd MyScale
touch main.ipynb

Installiamo i pacchetti. Copia il comando seguente e incollalo nel tuo terminale. Questi pacchetti forniranno gli strumenti e le librerie di cui abbiamo bisogno per sviluppare la nostra applicazione.

Shell

 

pip install openai apify-client clickhouse-connect pandas numpy

Questo dovrebbe installare tutte le dipendenze nel tuo sistema. Per confermare che tutto sia installato correttamente, puoi inserire il seguente comando nel terminale.

Shell

 

pip freeze | egrep '(openai|apify-client|clickhouse-connect|pandas|numpy)'

Ciò dovrebbe includere tutte le dipendenze installate con le loro versioni. Se noti alcune dipendenze mancanti, potrebbe essere necessario ri-eseguire il comando di installazione per quel pacchetto specifico. Ora siamo pronti a scrivere il nostro codice dopo le installazioni.

Nota: Stiamo lavorando in un notebook Python. Considerare ogni blocco di codice come una cella del notebook.

Come Estrarre Dati con Apify

Ora, utilizzeremo l’API di Apify per estrarre i dati degli eventi di New York City usando Raccoglitore di Eventi Facebook

Python

 

     import pandas as pd
from apify_client import ApifyClient
# Inizializza l'ApifyClient con il tuo token API
client = ApifyClient("Enter_your_apify_key_here")

# Prepara l'input per l'Actor
run_input = {
    "searchQueries": ["Sport New York"],
    "startUrls": [],
    "maxEvents": 50,
}

# Esegui l'Actor e attendi che finisca
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():
    # Usa una comprensione di dizionario per sostituire i valori None con una stringa vuota
    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 ''
    }
    # Assicurati che tutti i valori None siano sostituiti da una stringa vuota
    row = {k: (v if v is not None else '') for k, v in row.items()}
    dataframe1 = dataframe1._append(row, ignore_index=True)

# Pulizia dei dati
dataframe1['Description'] = dataframe1['Description'].replace('\\n', '', regex=True)

Questo script ci fornisce i dettagli degli eventi futuri sotto forma di DataFrame pandas.

Nota: Non dimenticare di aggiungere la tua chiave API di Apify nello script indicato. Puoi trovare il tuo token API sulla pagina Integrazioni nella Console Apify.

Pre-elaborazione dei dati

Quando raccolgiamo dati grezzi, questi arrivano in vari formati. In questo script, trasformeremo le date degli eventi in un formato unico per facilitare la filtrazione dei dati in modo più efficiente.

Python

 

     # Importa i necessari moduli per la manipolazione dei dati e la parsing delle date
import pandas as pd
import numpy as np
from datetime import datetime
from dateutil import parser

# Funzione per parsificare stringhe di date che possono rappresentare un range o una singola data
def parse_dates(date_str):
    # Verifica se la stringa di data contiene un trattino, indicando un range
    if '-' in date_str:
        parts = date_str.split('-')
        # Se la stringa si divide in due parti, è un range valido
        if len(parts) == 2:
            try:
                # Parsifica le date di inizio e fine, formattandole in un formato leggibile
                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:
                # In caso di errore di parsificazione, non fare nulla (verrà gestito di seguito)
                pass  
    # Se non è un range o se la parsificazione del range ha fallito, prova a parsificare come data singola
    try:
        parsed_date = parser.parse(date_str, fuzzy=True)
        # Formatta la data singola per Start_Date e formattare diversamente per 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:
        # Restituisci NaN per entrambe le date se la parsificazione fallisce
        return np.nan, np.nan  

# Funzione per estrarre data dettagliata, ora e giorno da una stringa di data
def extract_date_time_day(date_str):
    try:
        # Parsifica la stringa di data, permettendo una certa flessibilità nel formato di input
        parsed_date = parser.parse(date_str, fuzzy=True)
        # Estrai e formattare le parti di data, ora e giorno
        date = parsed_date.strftime('%Y-%m-%d')
        day = parsed_date.strftime('%a')
        # Determina se la stringa originale includeva una componente temporale
        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 la parsificazione fallisce, imposta data, ora e giorno su NaN
        date, time, day = np.nan, np.nan, np.nan
    
    return date, time, day

# Applica la funzione parse_dates attraverso il dataframe, creando nuove colonne per le date di inizio e fine
dataframe1[['Start_Date', 'End_Date']] = dataframe1.apply(lambda row: pd.Series(parse_dates(row['Datetime'])), axis=1)

# Elimina le righe in cui Start_Date è NaN, indicando che la parsificazione non è riuscita
dataframe = dataframe1.dropna(subset=['Start_Date'])

# Applica extract_date_time_day per dividere le date di inizio e fine in colonne separate per data, ora e giorno
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))

# Rimuovi la colonna originale 'Datetime' poiché non è più necessaria
dataframe=dataframe.drop(['Datetime'], axis=1)

# Converti 'Start_Date' e 'End_Date' in formato datetime, estraendo solo la parte della data
dataframe['Start_Date'] = pd.to_datetime(dataframe['Start_Date']).dt.date
dataframe['End_Date'] = pd.to_datetime(dataframe['End_Date']).dt.date

# Converti 'Start_Time' in formato datetime, mantenendo le informazioni temporali
dataframe['Start_Time'] = pd.to_datetime(dataframe['Start_Time'])

Questo frammento di codice utilizza pandas insieme ai pacchetti datetime e dateutil di Python per formattare i dati.

Generazione di Inbeddings

Per comprendere a fondo e ricercare eventi, genereremo embedding dalle loro descrizioni utilizzando il text-embedding-3-small. Questi embedding catturano l’essenza semantica di ogni evento, aiutando l’applicazione a restituire risultati migliori.

Python

 

     # Importa la libreria OpenAI per l'accesso all'API.
from openai import OpenAI 
# Inizializza il client OpenAI con una chiave API.
openai_client = OpenAI(api_key="your_openai_api_key_here")
# Funzione per ottenere embedding di testo 
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())
# Estrai i vettori di embedding dall'oggetto embedding
vectors = [embedding.embedding for embedding in embeddings]
array = np.array(vectors)
embeddings_series = pd.Series(list(array))
# Aggiungi gli embedding come nuova colonna nel DataFrame.
dataframe['Description_Embeddings'] = embeddings_series

Ora, inseriremo il nuovo DataFrame con gli embedding in MyScale.

Connessione con MyScale

Come discusso all’inizio, utilizzeremo MyScale come database vettoriale per memorizzare e gestire i dati. Qui, ci connetteremo a MyScale in preparazione per la memorizzazione dei dati.

Python

 

     import clickhouse_connect
client = clickhouse_connect.get_client(
    host='host_name_here',
    port=443,
    username='username_here',
    password='passwd_here'
)

Questa configurazione della connessione garantisce che il nostro applicazione possa comunicare con MyScale e utilizzare il potere di SQL per la manipolazione e l’analisi dei dati.

Nota: Consulta Dettagli della Connessione per ulteriori informazioni su come connettersi al cluster MyScale.

Creare Tabelle e Indici Utilizzando MyScale

Ora creiamo una tabella secondo il nostro DataFrame. Tutti i dati saranno memorizzati in questa tabella, compresi gli embedding.

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);
    """)

Le dichiarazioni SQL sopra creano una tabella chiamata Eventi nel cluster. Il vincolo CONSTRAINT si assicura che tutti i vettori di embedding siano della stessa lunghezza 1536.

Memorizzazione dei dati e creazione di un indice in MyScale

In questo passaggio, inseriamo i dati elaborati in MyScale. Ciò comporta l’inserimento batch dei dati per garantire una memorizzazione e un recupero efficienti.

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
""")

Utilizzando pandas, il codice sopra trasferisce efficientemente il nostro dataset preparato nel database MyScale.

Analisi dei dati utilizzando MyScale

Infine, utilizziamo le capacità analitiche di MyScale per eseguire analisi e abilitare la ricerca semantica. Eseguendo query SQL, possiamo analizzare eventi basati su argomenti, luoghi e date. Quindi, proviamo a scrivere alcune query.

Query SQL semplice

Proviamo prima a ottenere i primi 10 risultati dalla tabella.

Python

 

     results=client.query("""
        SELECT Name,Description FROM default.Events LIMIT 10
    """)
for row in results.named_results():
        print(row["Name"])
        print(row['Description'])

Questa query restituirà semplicemente i primi 10 risultati dalla tabella eventi.

Scoprire eventi per rilevanza semantica

Proviamo a trovare i primi 10 eventi imminenti con un’atmosfera simile a un evento di riferimento, come questo: “Uno degli spettacoli più longevi del paese – Attivo dal 1974 … ORA il nostro 50° ANNO!!! Il nostro Schenectady”. Ciò viene realizzato confrontando gli embedding semantici delle descrizioni degli eventi, garantendo una corrispondenza nei temi e nelle emozioni.

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"])

Eventi in tendenza per popolarità

Questa query classifica i primi 10 eventi per numero di partecipanti e utenti interessati, evidenziando eventi popolari dai grandi festival cittadini alle principali conferenze. È ideale per coloro che cercano di partecipare a raduni grandi ed energici.

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"])

Eventi Locali Popolari a New York

Combinando rilevanza e popolarità, questa query identifica eventi simili a New York City legati a un evento specifico e li classifica per partecipanti, offrendo un elenco curato di eventi che riflettono la vibrante cultura della città e attirano l’interesse locale.

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"])

Principali Organizzatori di Eventi

Questa query classifica i primi 10 organizzatori di eventi per il numero totale di partecipanti e utenti interessati, evidenziando coloro che eccellono nella creazione di eventi coinvolgenti e nell’attrarre grandi pubblici. Fornisce spunti per pianificatori di eventi e partecipanti interessati agli eventi di alto livello.

Python

 

     # Quale cliente ha attirato il maggior numero di utenti 
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"])

Implementare RAG;

In precedenza, abbiamo esplorato MyScale per l’analisi dei dati, evidenziando le sue capacità nel migliorare i nostri flussi di lavoro con i dati. Andando avanti, faremo un passo in più implementando Retrieval-Augmented Generation (RAG), un innovativo framework che combina una base di conoscenza esterna con modelli di linguaggio di grandi dimensioni (LLM). Questo passo aiuterà a comprendere meglio i dati e a trovare intuizioni più dettagliate. Successivamente, vedremo come utilizzare RAG con MyScale, rendendo il lavoro con i dati più interessante e produttivo.

Python

 

     from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate

query="Can you please suggest me some events related to basketball"
# Usa il metodo get_embedding definito in precedenza, accetta una lista di frasi
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}
"""
# Combina le descrizioni dei risultati principali. 
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)

In tutto questo blog, abbiamo osservato che MyScale è molto più di un database vettoriale che può essere utilizzato per sviluppare ogni tipo di applicazione. Possiamo usarlo come un semplice database SQL o per applicazioni AI avanzate, coprendo la maggior parte del dominio dello sviluppo. Ci incoraggiamo a provarlo e ad esplorare le funzionalità avanzate iscrivendosi al livello gratuito e ottenendo 5 milioni di archiviazione vettoriale gratuita.

Conclusione

Abbiamo esplorato le capacità e le funzionalità di MyScale con Apify Scraper attraverso il processo di sviluppo di un’applicazione di analisi degli eventi. MyScale ha dimostrato le sue eccezionali capacità nella ricerca vettoriale ad alta prestazione pur mantenendo tutte le funzionalità dei database SQL, il che aiuta gli sviluppatori a effettuare ricerche semantiche utilizzando la sintassi SQL familiare con una velocità e precisione molto superiori.

Le capacità di MyScale non si limitano a questa applicazione: puoi adottarla per sviluppare qualsiasi applicazione AI utilizzando il metodo RAG

Se hai feedback o suggerimenti, non esitare a contattarci.

Source:
https://dzone.com/articles/performing-advanced-facebook-event-data-analysis-w