В нашем цифровом веке профессионалы во всех отраслях должны быть в курсе предстоящих мероприятий, конференций и мастер-классов. Однако эффективно находить мероприятия, соответствующие интересам, среди огромного количества информации в интернете представляет собой серьезную проблему.
В этом блоге представлено инновационное решение этой проблемы: комплексная программа, предназначенная для сбора данных о мероприятиях с Facebook и анализа собранных данных с использованием MyScale. Хотя MyScale обычно ассоциируется с технологической пачкой RAG или используется в качестве векторной базы данных, его возможности выходят за рамки этих областей. Мы будем использовать его для анализа данных, используя функцию векторного поиска для анализа мероприятий, которые являются семантически похожими, тем самым обеспечивая более точные результаты и понимание.
Вы можете заметить, что Grok AI использовала векторную базу данных Qdrant в качестве поисковой системы для извлечения реальной информации из X (ранее известного как Twitter) данных. Вы также можете оценить возможности векторных баз данных таким образом с MyScale, интегрировав MyScale с другими платформами, такими как Apify, чтобы улучшить повседневные задачи путем разработки простых персонализированных приложений.
Итак, в этом блоге давайте разработаем приложение, которое принимает только название города в качестве входных данных и собирает все связанные мероприятия с Facebook. Затем мы проведем анализ данных и семантический поиск с использованием передовых векторных возможностей SQL MyScale.
Инструменты и технологии
Мы будем использовать несколько инструментов, включая Apify, MyScale и OpenAI, для разработки этого полезного приложения.
- Apify: Популярная платформа для web scraping и автоматизации, значительно упрощающая процесс сбора данных. Она предоставляет возможность собирать данные и затем передавать их LLMs. Это позволяет нам обучать LLMs на реальных данных и разрабатывать приложения.
- MyScale: MyScale – это векторная база данных SQL, которую мы используем для хранения и обработки как структурированных, так и неструктурированных данных оптимизированным способом.
- OpenAI: Мы будем использовать модель
text-embedding-3-small
от OpenAI для получения векторов текста, а затем сохраним эти векторы в MyScale для анализа данных и семантического поиска.
Как настроить MyScale и Apify
Чтобы начать настройку MyScale и Apify, вам нужно создать новый каталог и файл Python. Вы можете сделать это, открыв терминал или командную строку и введя следующие команды:
mkdir MyScale
cd MyScale
touch main.ipynb
Давайте установим пакеты. Скопируйте команду ниже и вставьте ее в свой терминал. Эти пакеты предоставят инструменты и библиотеки, необходимые для разработки нашего приложения.
pip install openai apify-client clickhouse-connect pandas numpy
Это должно установить все зависимости в вашей системе. Чтобы убедиться, что все установлено правильно, вы можете ввести следующую команду в терминале.
pip freeze | egrep '(openai|apify-client|clickhouse-connect|pandas|numpy)'
Это должно включать все установленные зависимости вместе с их версиями. Если вы заметили какие-либо недостающие зависимости, вам, возможно, потребуется повторно запустить команду установки для этого конкретного пакета. Теперь, после установки, мы готовы написать наш код.
Примечание: Мы будем работать в ноутбуке на Python. Рассмотрите каждый блок кода как ячейку ноутбука.
Как собирать данные с помощью Apify
Теперь мы будем использовать API Apify для сбора данных о событиях в Нью-Йорке с помощью скраппера событий Facebook.
import pandas as pd
from apify_client import ApifyClient
# Инициализируйте ApifyClient с вашим токеном API
client = ApifyClient("Enter_your_apify_key_here")
# Подготовьте входные данные для Актора
run_input = {
"searchQueries": ["Sport New York"],
"startUrls": [],
"maxEvents": 50,
}
# Запустите Актора и дождитесь его завершения
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():
# Используйте понимание словаря для замены значений None на пустую строку
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 ''
}
# Убедитесь, что все значения None заменены на пустую строку
row = {k: (v if v is not None else '') for k, v in row.items()}
dataframe1 = dataframe1._append(row, ignore_index=True)
# Очистка данных
dataframe1['Description'] = dataframe1['Description'].replace('\\n', '', regex=True)
Этот скрипт предоставляет нам детали предстоящих событий в виде DataFrame pandas
.
Примечание: Не забудьте добавить свой ключ API Apify в скрипт выше. Вы можете найти свой токен API на странице Интеграции в консоли Apify.
Предварительная обработка данных
Когда мы собираем необработанные данные, они поступают в различных форматах. В этом скрипте мы преобразуем даты событий в единый формат, чтобы наша фильтрация данных могла быть более эффективной.
# Импортировать необходимые библиотеки для манипуляций с данными и парсинга дат
import pandas as pd
import numpy as np
from datetime import datetime
from dateutil import parser
# Функция для парсинга строк дат, которые могут представлять диапазон или одну дату
def parse_dates(date_str):
# Проверить, содержит ли строка даты дефис, указывающий на диапазон
if '-' in date_str:
parts = date_str.split('-')
# Если строка разделяется на две части, это действительный диапазон
if len(parts) == 2:
try:
# Распарсить начальную и конечную даты, форматируя их в читаемый формат
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:
# В случае ошибки парсинга, ничего не делать (будет обработано ниже)
pass
# Если это не диапазон или если парсинг диапазона не удался, попытаться распарсить как одну дату
try:
parsed_date = parser.parse(date_str, fuzzy=True)
# Форматировать одну дату для start_date и по-другому для 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:
# Вернуть NaN для обеих дат, если парсинг не удался
return np.nan, np.nan
# Функция для извлечения подробной даты, времени и дня из строки даты
def extract_date_time_day(date_str):
try:
# Распарсить строку даты, разрешая некоторую гибкость в формате ввода
parsed_date = parser.parse(date_str, fuzzy=True)
# Извлечь и отформатировать части даты, времени и дня
date = parsed_date.strftime('%Y-%m-%d')
day = parsed_date.strftime('%a')
# Определить, включала ли исходная строка компонент времени
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:
# Если парсинг не удался, установить дату, время и день в NaN
date, time, day = np.nan, np.nan, np.nan
return date, time, day
# Применить функцию parse_dates к датафрейму, создавая новые столбцы для начальной и конечной дат
dataframe1[['Start_Date', 'End_Date']] = dataframe1.apply(lambda row: pd.Series(parse_dates(row['Datetime'])), axis=1)
# Удалить строки, где Start_Date является NaN, указывая на неудачный парсинг
dataframe = dataframe1.dropna(subset=['Start_Date'])
# Применить extract_date_time_day для разделения начальной и конечной дат на отдельные столбцы даты, времени и дня
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))
# Удалить исходный столбец 'Datetime', так как он больше не нужен
dataframe=dataframe.drop(['Datetime'], axis=1)
# Преобразовать 'Start_Date' и 'End_Date' в формат даты, извлекая только часть даты
dataframe['Start_Date'] = pd.to_datetime(dataframe['Start_Date']).dt.date
dataframe['End_Date'] = pd.to_datetime(dataframe['End_Date']).dt.date
# Преобразовать 'Start_Time' в формат даты, сохраняя информацию о времени
dataframe['Start_Time'] = pd.to_datetime(dataframe['Start_Time'])
Этот фрагмент кода использует pandas
вместе с пакетами datetime
и dateutil
Python для форматирования данных.
Генерация эмбеддингов
Для глубокого понимания и поиска событий мы будем генерировать эмбеддинги из их описаний с использованием text-embedding-3-small
. Эти эмбеддинги улавливают семантическую сущность каждого события, что помогает приложению возвращать лучшие результаты.
# Импортируем библиотеку OpenAI для доступа к API.
from openai import OpenAI
# Инициализируем клиент OpenAI с помощью ключа API.
openai_client = OpenAI(api_key="your_openai_api_key_here")
# Функция для получения текстовых эмбеддингов
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())
# Извлекаем векторы эмбеддингов из объекта эмбеддингов
vectors = [embedding.embedding for embedding in embeddings]
array = np.array(vectors)
embeddings_series = pd.Series(list(array))
# Добавляем эмбеддинги как новый столбец в DataFrame.
dataframe['Description_Embeddings'] = embeddings_series
Теперь мы вставим новый DataFrame
с эмбеддингами в MyScale.
Подключение к MyScale
Как обсуждалось в начале, мы будем использовать MyScale в качестве векторной базы данных для хранения и управления данными. Здесь мы подключимся к MyScale в преддверии хранения данных.
import clickhouse_connect
client = clickhouse_connect.get_client(
host='host_name_here',
port=443,
username='username_here',
password='passwd_here'
)
Эта настройка подключения обеспечивает возможность коммуникации нашего приложения с MyScale и использование мощности SQL для манипуляции и анализа данных.
Примечание: См. Детали подключения для получения более подробной информации о том, как подключиться к кластеру MyScale.
Создание таблиц и индексов с использованием MyScale
Теперь мы создадим таблицу в соответствии с нашим DataFrame. Все данные будут храниться в этой таблице, включая эмбеддинги.
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);
""")
Вышеприведенные SQL-запросы создают таблицу с именем Events
в кластере. CONSTRAINT
обеспечивает, что все векторные вложения имеют одинаковую длину 1536
.
Хранение данных и создание индекса в MyScale
На этом этапе мы вставляем обработанные данные в MyScale. Это включает в себя массовую вставку данных для обеспечения эффективного хранения и извлечения.
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
""")
Используя pandas
, приведенный выше код эффективно переносит наш подготовленный набор данных в базу данных MyScale.
Анализ данных с использованием MyScale
Наконец, мы используем аналитические возможности MyScale для проведения анализа и обеспечения семантического поиска. Выполняя SQL-запросы, мы можем анализировать события по темам, местам и датам. Итак, давайте попробуем написать несколько запросов.
Простой SQL-запрос
Сначала давайте попробуем получить 10 лучших результатов из таблицы.
results=client.query("""
SELECT Name,Description FROM default.Events LIMIT 10
""")
for row in results.named_results():
print(row["Name"])
print(row['Description'])
Этот запрос просто вернет 10 лучших результатов из таблицы events
.
Открытие событий по семантической релевантности
Давайте попробуем найти 10 ближайших событий с похожей атмосферой на ссылочное событие, например: “Одно из самых долгоиграющих шоу в стране – работает с 1974 года …СЕЙЧАС наше 50-летие !!! Наше Скенектади”. Это достигается путем сравнения семантических вложений описаний событий, обеспечивая соответствие в темах и эмоциях.
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"])
Трендовые события по популярности
Этот запрос ранжирует топ 10 мероприятий по количеству участников и заинтересованных пользователей, выделяя популярные мероприятия от крупных городских фестивалей до главных конференций. Он идеален для тех, кто стремится присоединиться к большим, энергичным событиям.
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"])
Популярные местные мероприятия в Нью-Йорке
Объединяя релевантность и популярность, этот запрос определяет подобные мероприятия в Нью-Йорке по отношению к конкретному событию и ранжирует их по посещаемости, предлагая отсортированный список мероприятий, отражающих яркую культуру города и привлекающих местный интерес.
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"])
Лидеры организаторов мероприятий
Этот запрос ранжирует топ 10 организаторов мероприятий по общему количеству участников и заинтересованных пользователей, выделяя тех, кто преуспевает в создании захватывающих мероприятий и привлечении большой аудитории. Он предоставляет информацию для организаторов мероприятий и участников, заинтересованных в мероприятиях высшего уровня.
# Какой клиент привлек наибольшее количество пользователей
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"])
Реализовать RAG
Ранее мы исследовали MyScale для анализа данных, выделяя его возможности в улучшении наших рабочих процессов с данными. Двигаясь вперед, мы сделаем еще один шаг, внедрив Retrieval-Augmented Generation (RAG), инновационную структуру, объединяющую внешнюю базу знаний с LLM. Этот шаг поможет вам лучше понять свои данные и найти более детальные сведения. Далее вы увидите, как использовать RAG с MyScale, что сделает работу с данными более интересной и продуктивной.
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
query="Can you please suggest me some events related to basketball"
# Используйте метод get_embedding, описанный выше, он принимает список предложений
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}
"""
# Объедините описания лучших результатов.
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)
На протяжении этого блога мы наблюдали, что MyScale – это гораздо больше, чем векторная база данных, которую можно использовать для разработки всевозможных приложений. Мы можем использовать его как простую SQL-базу данных или для продвинутых приложений AI, охватывая большую часть области разработки. Мы призываем вас попробовать и исследовать продвинутые функции, зарегистрировавшись на бесплатный тариф и получив 5 миллионов бесплатного векторного хранилища.
Заключение
Мы исследовали возможности и функциональность MyScale с помощью Apify Scraper в процессе разработки приложения для анализа событий. MyScale продемонстрировал свои выдающиеся возможности в высокопроизводительном векторном поиске, сохраняя все функциональности SQL-баз данных, что помогает разработчикам делать семантические запросы с использованием знакомого синтаксиса SQL с гораздо лучшей скоростью и точностью.
Возможности MyScale не ограничиваются этим приложением: вы можете применять его для разработки любых AI-приложений с использованием метода RAG.
Если у вас есть какие-либо отзывы или предложения, пожалуйста, свяжитесь с нами.
Source:
https://dzone.com/articles/performing-advanced-facebook-event-data-analysis-w