
pyspark_report
.docxОтчёт по решению задачи в PySpark
Введение
Этот отчёт содержит описание и реализацию решения задачи анализа данных с использованием PySpark. Основная цель — обработка текстовых данных, хэширование подстрок, и вычисление совпадений между авторами на основе общих хэшей.
Описание решения
Решение включает следующие этапы: 1. Очистка текстовых данных от пробелов. 2. Разделение содержимого текста на подстроки фиксированной длины. 3. Хэширование подстрок с использованием алгоритма CRC32. 4. Группировка уникальных хэшей для каждого автора. 5. Поиск общих хэшей между различными авторами. 6. Вычисление метрики совпадения и упорядочивание результатов.
Код реализации
Ниже представлен код реализации задачи:
from pyspark.sql import DataFrame
from pyspark.sql.functions import (
col, explode, lit, udf, collect_set, size, count
)
from pyspark.sql.types import StringType, ArrayType
from zlib import crc32
from lab2.common import SparkContextCommon
# Функция для очистки строки от пробелов
def clean_data(inp: str) -> str:
return "".join(inp.split())
# Функция для получения хэша строки
def get_hash(cont: str) -> int:
return crc32(cont.encode())
# Разделение строки на подстроки длиной n
def split_content(cont: str, n: int = 5) -> list:
return [cont[i:i + n] for i in range(0, len(cont) - n)]
# Регистрация пользовательских функций (UDF)
clean_data_udf = udf(clean_data, StringType())
split_content_udf = udf(split_content, ArrayType(StringType()))
hash_udf = udf(get_hash, StringType())
def solve(common: SparkContextCommon) -> DataFrame:
# Чтение данных
inp = common.read_data()
# Очистка контента
df = inp.withColumn('content', clean_data_udf(col('content')))
# Разделение на подстроки и хэширование
substrings_df = (
df.withColumn('substrings', split_content_udf(col('content')))
.withColumn('substrings', explode(col('substrings')))
.withColumn('hash', hash_udf(col('substrings')))
)
# Сбор уникальных хэшей для каждого автора
hashed_df = substrings_df.groupBy('author').agg(
collect_set('hash').alias('hashes')
)
# Перекрёстное соединение авторов
joined_df = hashed_df.alias('df1').join(
hashed_df.alias('df2'),
col('df1.author') != col('df2.author')
)
# Формирование шаблона для подсчёта совпадений
template_df = joined_df.select(
col('df1.author').alias('_lhs_author'),
col('df2.author').alias('_rhs_author'),
size(col('df1.hashes')).alias('total'),
lit(0.0).alias('match')
)
# Подсчёт общих хэшей между авторами
common_hashes_df = (
joined_df.select(
col('df1.author').alias('lhs_author'),
explode(col('df1.hashes')).alias('lhs_hash'),
col('df2.author').alias('rhs_author'),
explode(col('df2.hashes')).alias('rhs_hash')
)
.filter(col('lhs_hash') == col('rhs_hash'))
.groupBy('lhs_author', 'rhs_author')
.agg(count('lhs_hash').alias('common'))
)
# Объединение с шаблоном и расчёт метрики "совпадение"
result_df = (
common_hashes_df.alias('common')
.join(template_df.alias('template'),
(col('template._lhs_author') == col('common.lhs_author')) &
(col('template._rhs_author') == col('common.rhs_author')),
'right'
)
.fillna(0, subset=['common'])
.withColumn('match', col('common') / col('total'))
.select(
col('_lhs_author').alias('lhs_author'),
col('_rhs_author').alias('rhs_author'),
col('match')
)
.orderBy(col('match').desc())
)
return result_df
Заключение
Представленный код демонстрирует использование PySpark для обработки больших данных. Подход с использованием UDF (пользовательских функций) и встроенных методов PySpark позволяет эффективно выполнять сложные преобразования данных.