Dans l’ère numérique d’aujourd’hui, les professionnels de tous les secteurs doivent rester à jour avec les événements à venir, les conférences et les ateliers. Cependant, trouver efficacement des événements qui correspondent à ses intérêts au milieu de l’immense océan d’informations en ligne présente un défi significatif.
Ce blog présente une solution innovante à ce défi : une application complète conçue pour récupérer des données d’événements à partir de Facebook et analyser les données récupérées en utilisant MyScale. Bien que MyScale soit généralement associé à la pile technologique RAG ou utilisé comme base de données vectorielle, ses capacités dépassent ces domaines. Nous allons l’utiliser pour l’analyse des données, en tirant parti de sa fonctionnalité de recherche vectorielle pour analyser les événements qui sont sémantiquement similaires, fournissant ainsi de meilleurs résultats et des insights.
Vous remarquerez peut-être que Grok AI a utilisé la base de données vectorielle Qdrant comme moteur de recherche pour récupérer des informations en temps réel à partir de X (anciennement connue sous le nom de Twitter) données. Vous pouvez également évaluer la puissance des bases de données vectorielles de cette façon avec MyScale en intégrant MyScale avec d’autres plateformes comme Apify pour améliorer les tâches quotidiennes grâce au développement d’applications personnalisées simples.
Alors dans ce blog, développons une application qui n’accepte que le nom d’une ville en entrée et récupère tous les événements connexes à partir de Facebook. Ensuite, nous procéderons à l’analyse des données et à la recherche sémantique en utilisant les capacités vectorielles SQL avancées de MyScale.
Outils et Technologies
Nous utiliserons plusieurs outils, y compris Apify, MyScale et OpenAI, pour développer cette application utile.
- Apify: Une plateforme populaire de web scraping et d’automatisation qui simplifie considérablement le processus de collecte de données. Elle offre la capacité de récupérer des données et de les alimenter ensuite dans les LLMs. Cela nous permet de former des LLMs sur des données en temps réel et de développer des applications.
- MyScale: MyScale est une base de données vectorielle SQL que nous utilisons pour stocker et traiter à la fois des données structurées et non structurées de manière optimisée.
- OpenAI: Nous utiliserons le modèle
text-embedding-3-small
d’OpenAI pour obtenir les embeddings du texte, puis enregistrer ces embeddings dans MyScale pour l’analyse des données et la recherche sémantique.
Comment configurer MyScale et Apify
Pour commencer à configurer MyScale et Apify, vous devrez créer un nouveau répertoire et un fichier Python. Vous pouvez le faire en ouvrant votre terminal ou ligne de commande et en entrant les commandes suivantes:
mkdir MyScale
cd MyScale
touch main.ipynb
Installons les packages. Copiez la commande ci-dessous et collez-la dans votre terminal. Ces packages fourniront les outils et les bibliothèques dont nous avons besoin pour développer notre application.
pip install openai apify-client clickhouse-connect pandas numpy
Cela devrait installer toutes les dépendances dans votre système. Pour confirmer que tout est installé correctement, vous pouvez entrer la commande suivante dans votre terminal.
pip freeze | egrep '(openai|apify-client|clickhouse-connect|pandas|numpy)'
Ceci doit inclure toutes les dépendances installées avec leurs versions. Si vous remarquez des dépendances manquantes, vous devrez peut-être réexécuter la commande d’installation pour ce package spécifique. Maintenant, nous sommes prêts à écrire notre code après les installations.
Remarque: Nous travaillerons dans un notebook Python. Considérez chaque bloc de code comme une cellule de notebook.
Comment Scraper des Données avec Apify
À présent, nous utiliserons l’API Apify pour scraper les données d’événements de la ville de New York à l’aide de scraper d’événements Facebook.
import pandas as pd
from apify_client import ApifyClient
# Initialiser le ApifyClient avec votre token API
client = ApifyClient("Enter_your_apify_key_here")
# Préparer l'entrée de l'Actor
run_input = {
"searchQueries": ["Sport New York"],
"startUrls": [],
"maxEvents": 50,
}
# Exécuter l'Actor et attendre qu'il se 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():
# Utiliser une compréhension de dictionnaire pour remplacer les valeurs None par une chaîne vide
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 ''
}
# Assurer que toutes les valeurs None sont remplacées par une chaîne vide
row = {k: (v if v is not None else '') for k, v in row.items()}
dataframe1 = dataframe1._append(row, ignore_index=True)
# Nettoyage des données
dataframe1['Description'] = dataframe1['Description'].replace('\\n', '', regex=True)
Ce script nous donne les détails des événements à venir sous la forme d’un DataFrame pandas
.
Note: N’oubliez pas d’ajouter votre clé API Apify dans le script ci-dessus. Vous pouvez trouver votre jeton API sur la page Intégrations dans la console Apify.
Prétraitement des données
Lorsque nous rassemblons des données brutes, elles sont disponibles dans divers formats. Dans ce script, nous allons convertir les dates d’événements en un format unique afin que notre filtrage de données puisse être effectué de manière plus efficace.
# Importation des bibliothèques nécessaires pour la manipulation de données et la conversion de dates
import pandas as pd
import numpy as np
from datetime import datetime
from dateutil import parser
# Fonction pour convertir des chaînes de dates qui peuvent représenter une plage ou une seule date
def parse_dates(date_str):
# Vérifier si la chaîne de date contient un trait d'union, indiquant une plage
if '-' in date_str:
parts = date_str.split('-')
# Si la chaîne se divise en deux parties, c'est une plage valide
if len(parts) == 2:
try:
# Convertir les dates de début et de fin, les formatant en un format lisible
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:
# En cas d'erreur de conversion, ne rien faire (traitement ci-dessous)
pass
# Si ce n'est pas une plage ou si la conversion de la plage a échoué, essayer de convertir en une seule date
try:
parsed_date = parser.parse(date_str, fuzzy=True)
# Formater la date unique pour Start_Date et différemment pour 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:
# Retourner NaN pour les deux dates si la conversion échoue
return np.nan, np.nan
# Fonction pour extraire les détails de date, heure et jour d'une chaîne de date
def extract_date_time_day(date_str):
try:
# Convertir la chaîne de date, permettant une certaine flexibilité dans le format d'entrée
parsed_date = parser.parse(date_str, fuzzy=True)
# Extraire et formater les parties de date, heure et jour
date = parsed_date.strftime('%Y-%m-%d')
day = parsed_date.strftime('%a')
# Déterminer si la chaîne d'origine incluait un composant horaire
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:
# Si la conversion échoue, mettre date, heure et jour à NaN
date, time, day = np.nan, np.nan, np.nan
return date, time, day
# Appliquer la fonction parse_dates à travers le dataframe, créant de nouvelles colonnes pour les dates de début et de fin
dataframe1[['Start_Date', 'End_Date']] = dataframe1.apply(lambda row: pd.Series(parse_dates(row['Datetime'])), axis=1)
# Supprimer les lignes où Start_Date est NaN, indiquant un échec de conversion
dataframe = dataframe1.dropna(subset=['Start_Date'])
# Appliquer extract_date_time_day pour diviser les dates de début et de fin en colonnes distinctes pour date, heure et jour
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))
# Supprimer la colonne 'Datetime' d'origine car elle n'est plus nécessaire
dataframe=dataframe.drop(['Datetime'], axis=1)
# Convertir 'Start_Date' et 'End_Date' en format datetime, extrayant uniquement la partie date
dataframe['Start_Date'] = pd.to_datetime(dataframe['Start_Date']).dt.date
dataframe['End_Date'] = pd.to_datetime(dataframe['End_Date']).dt.date
# Convertir 'Start_Time' en format datetime, conservant l'information horaire
dataframe['Start_Time'] = pd.to_datetime(dataframe['Start_Time'])
Ce code utilise pandas
avec les packages datetime
et dateutil
de Python pour formater les données.
Génération d’Embraquements
Pour comprendre et rechercher en profondeur les événements, nous générerons des embeddings à partir de leurs descriptions en utilisant text-embedding-3-small
. Ces embeddings capturent l’essence sémantique de chaque événement, aidant l’application à retourner de meilleurs résultats.
# Importer la bibliothèque OpenAI pour l'accès à l'API.
from openai import OpenAI
# Initialiser le client OpenAI avec une clé API.
openai_client = OpenAI(api_key="your_openai_api_key_here")
# Fonction pour obtenir des embeddings textuels
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())
# Extraire les vecteurs d'embedding de l'objet embeddings
vectors = [embedding.embedding for embedding in embeddings]
array = np.array(vectors)
embeddings_series = pd.Series(list(array))
# Ajouter les embeddings en tant que nouvelle colonne dans le DataFrame.
dataframe['Description_Embeddings'] = embeddings_series
Maintenant, nous insérerons le nouveau DataFrame
avec les embeddings dans MyScale.
Connexion avec MyScale
Comme discuté au début, nous utiliserons MyScale en tant que base de données vectorielle pour stocker et gérer les données. Ici, nous nous connecterons à MyScale en préparation du stockage des données.
import clickhouse_connect
client = clickhouse_connect.get_client(
host='host_name_here',
port=443,
username='username_here',
password='passwd_here'
)
Cette configuration de connexion garantit que notre application peut communiquer avec MyScale et utiliser la puissance de SQL pour la manipulation et l’analyse des données.
Note: Voir Détails de la connexion pour plus d’informations sur la manière de se connecter au cluster MyScale.
Créer des tables et des index en utilisant MyScale
Nous créons maintenant une table selon notre DataFrame. Toutes les données seront stockées dans cette table, y compris les 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);
""")
Les instructions SQL ci-dessus créent une table nommée Events
sur le cluster. La CONSTRAINT
garantit que tous les vecteurs d’embedding ont la même longueur 1536
.
Stockage des données et création d’un index dans MyScale
Dans cette étape, nous insérons les données traitées dans MyScale. Cela implique l’insertion par lots des données pour assurer un stockage et une récupération efficaces.
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
""")
En utilisant pandas
, le code ci-dessus transfère efficacement notre jeu de données préparé dans la base de données MyScale.
Analyse des données à l’aide de MyScale
Enfin, nous utilisons les capacités analytiques de MyScale pour effectuer des analyses et activer la recherche sémantique. En exécutant des requêtes SQL, nous pouvons analyser les événements en fonction des sujets, des lieux et des dates. Donc, essayons d’écrire quelques requêtes.
Requête SQL simple
Essayons d’abord d’obtenir les 10 premiers résultats de la table.
results=client.query("""
SELECT Name,Description FROM default.Events LIMIT 10
""")
for row in results.named_results():
print(row["Name"])
print(row['Description'])
Cette requête retournera simplement les 10 premiers résultats de la table events
.
Découvrir des événements par pertinence sémantique
Essayons de trouver les 10 prochains événements ayant une ambiance similaire à un événement de référence, comme ceci : « L’un des spectacles les plus longs en cours dans le pays – En opération depuis 1974… MAINTENANT notre 50ème ANNÉE !!! Notre Schenectady ». Ceci est réalisé en comparant les embeddings sémantiques des descriptions des événements, assurant un match sur les thèmes et les émotions.
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"])
Événements en tendance par popularité
Cette requête classe les 10 meilleurs événements en fonction du nombre de participants et d’utilisateurs intéressés, mettant en évidence des événements populaires allant des festivals de grandes villes aux conférences majeures. Elle est idéale pour ceux qui cherchent à rejoindre de grandes assemblées animées.
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"])
Événements locaux populaires à New York
En combinant pertinence et popularité, cette requête identifie des événements similaires à New York liés à un événement spécifique et les classe par participation, offrant une liste sélectionnée d’événements qui reflète la culture vibrante de la ville et attirent l’intérêt 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"])
Organisateurs d’événements de premier plan
Cette requête classe les 10 meilleurs organisateurs d’événements en fonction du nombre total de participants et d’utilisateurs intéressés, mettant en avant ceux qui s’illustrent dans la création d’événements captivants et l’attraction de grandes audiences. Elle fournit des informations pour les planificateurs d’événements et les participants intéressés par les événements de haut niveau.
# Quel client a attiré le plus grand nombre d'utilisateurs
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"])
Mettre en œuvre RAG
Auparavant, nous avons exploré MyScale pour l’analyse des données, soulignant ses capacités à améliorer nos workflows de données. Ensuite, nous allons franchir une étape supplémentaire en mettant en œuvre la Génération Augmentée par Récupération (RAG), un cadre innovant qui combine une base de connaissances externe avec des LLMs. Cette étape vous aidera à mieux comprendre vos données et à trouver des insights plus détaillés. Ensuite, vous verrez comment utiliser RAG avec MyScale, ce qui rendra le travail avec les données plus intéressant et productif.
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
query="Can you please suggest me some events related to basketball"
# Utilisez la méthode get_embedding définie ci-dessus, elle accepte une liste de phrases
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}
"""
# Combinez les descriptions des résultats principaux.
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)
Tout au long de ce blog, nous avons constaté que MyScale est bien plus qu’une base de données vectorielle pouvant être utilisée pour développer toutes sortes d’applications. Nous pouvons l’utiliser comme une base de données SQL simple ou pour des applications d’IA avancées, couvrant la majorité du domaine de développement. Nous vous encourageons à l’essayer et à explorer les fonctionnalités avancées en vous inscrivant au forfait gratuit et en obtenant 5 millions de stockage vectoriel gratuit.
Conclusion
Nous avons exploré les capacités et les fonctionnalités de MyScale avec Apify Scraper à travers le processus de développement d’une application d’analyse d’événements. MyScale a démontré ses capacités exceptionnelles en matière de recherche vectorielle haute performance tout en conservant toutes les fonctionnalités des bases de données SQL, ce qui aide les développeurs à effectuer des recherches sémantiques à l’aide d’une syntaxe SQL familière avec une bien meilleure vitesse et précision.
Les capacités de MyScale ne se limitent pas à cette application : vous pouvez l’adopter pour développer n’importe quelle application IA en utilisant la méthode RAG.
Si vous avez des commentaires ou des suggestions, n’hésitez pas à nous contacter.
Source:
https://dzone.com/articles/performing-advanced-facebook-event-data-analysis-w