Construir una tabla de comparación completa

Big DataBeginner
Practicar Ahora

Introducción

La tienda ya distingue un par sesión/producto visualizado de eventos repetidos. Ahora pregunta qué productos tienen una gran proporción de sesiones con visualización sin una adición válida al carrito y cuánta evidencia respalda cada comparación.

Producirá una tabla completa con el denominador de sesiones con visualización, el recuento completado, el incompleto y la proporción incompleta. Conserve los productos sin adiciones válidas y todos los empates. El resultado es una pista para investigar, no una prueba de que un producto o una página causó que la visita terminara.

Este laboratorio independiente suministra el módulo de recorridos completado del laboratorio guiado anterior y archivos originales nuevos. Debe conocer sus reglas de primera visualización, sesión/producto y tiempo, además de agrupación Spark y Parquet. Use Terminal. El lote es finito y cerrado; los identificadores y timestamps UTC con precisión de segundos son válidos, y los IDs de evento repetidos son copias exactas. El autor estima 35–45 minutos. No hay streaming, estimación de personas únicas ni inferencia causal.

Construir la comparación completa de productos

En este paso, agregará una fila por recorrido visualizado para obtener una fila por producto. Comience en Terminal. De los programas suministrados, edite solo analysis.py. Conserve intactos los archivos originales y run_analysis.py, read_result.py y support.py; los resultados derivados pertenecen a output/:

cd /home/labex/project
cat data/batch.csv
cat analysis.py

Este módulo contiene read_events, build_views y build_journeys, preparados independientemente a partir del laboratorio anterior. Un módulo contiene funciones reutilizables. El controlador proporciona la SparkSession y ruta actuales y después pasa el DataFrame de recorridos devuelto a su nueva función build_report(journeys). No necesita nada de una VM o sesión de terminal anterior.

Recuerde el contrato: se eliminan copias completas idénticas de eventos; cada (session_id, product_id) visualizado usa su primera visualización; una adición solo es válida para esas dos claves y en ese momento o después. Varias adiciones válidas siguen produciendo un único recorrido completado. El controlador utiliza local[2], formato UTC y el mismo Python para driver y workers. Escribe las salidas después de que sus funciones retornen.

Para un producto con tres pares visualizados y dos completados, calcule a mano tres sesiones con visualización, dos con adición al carrito, una sin ella y una proporción sin adición de 1/3. Sin ese denominador, una sola visita podría parecer tan convincente como una muestra grande.

count("*") ahora cuenta filas de recorridos, no eventos originales. Convertir el Boolean completed a long asigna 1 a true y 0 a false. La función sum de Spark suma esos valores. Restar los completados da el recuento incompleto; dividir entre el número positivo de sesiones visualizadas da una proporción entre cero y uno. Cada grupo tiene al menos una visualización. Un producto con solo adiciones no tiene grupo ni denominador; no inventamos una proporción con denominador cero.

Escribir solo la agregación de productos

Conserve las funciones suministradas read_events, build_views y build_journeys: son el trabajo completado del laboratorio anterior. No vuelva a escribirlas. F es su alias existente de las funciones Spark. Abra el mismo módulo con nano:

nano analysis.py

Use las flechas para llegar al final de build_journeys y deje una línea en blanco. Como ya practicó, Ctrl+W busca el nombre de una función; cada declaración nueva comienza en el margen izquierdo y su cuerpo usa cuatro espacios. Escribirá la función build_report completa, sin rellenar una plantilla de respuesta preparada.

Primero agrupe el DataFrame de recorridos por producto. Derive dos recuentos en esa misma agregación: todas las filas para el denominador de visualizaciones y después la suma de la finalización Boolean convertida a entero. Conserve los nombres de campo utilizados por el controlador:

def build_report(journeys):
    counts = journeys.groupBy("product_id").agg(
        F.count("*").alias("view_sessions"),
        F.sum(F.col("completed").cast("long")).alias("cart_sessions"),
    )

Continúe dentro de su función. withColumn deriva una columna con nombre a partir de los recuentos agrupados. Reste los completados de los visualizados antes de dividir entre ese mismo denominador positivo de visualizaciones. No filtre primero por completados: borraría los productos sin adiciones válidas. No seleccione solo un máximo: todos los productos empatados pertenecen al informe.

    return counts.withColumn(
        "no_cart_sessions", F.col("view_sessions") - F.col("cart_sessions")
    ).withColumn(
        "no_cart_ratio", F.col("no_cart_sessions") / F.col("view_sessions")
    )

Guarde con Ctrl+O, confirme analysis.py con Enter y salga con Ctrl+X. Vuelva a abrir el archivo para revisar su función guardada y verificar que las funciones anteriores permanecen:

nano analysis.py

Use Ctrl+W para encontrar build_report. Si hay un error, use las flechas y Backspace/Delete para reemplazar solo la línea afectada; no añada una segunda definición. Conserve la indentación de las continuaciones y los paréntesis de cierre. Guarde los cambios, salga y lea el archivo:

cat analysis.py

Si la siguiente ejecución informa de SyntaxError o IndentationError, localice la línea indicada en nano, compruebe la función que la rodea, los paréntesis y la indentación de cuatro espacios, guarde y repita la ejecución. Si el cálculo termina con éxito pero el recuento o la proporción es incorrecto, revise la agrupación, la conversión y el denominador. No reinicie la VM ni reescriba las funciones funcionales de G1 para reparar su informe.

Ejecute la etapa de informe con rutas de entrada y salida explícitas:

bigdata-python run_analysis.py data/batch.csv output/main --stage report

Espere esta tabla lógica completa; los valores flotantes mostrados pueden tener más dígitos:

product_id  view_sessions  cart_sessions  no_cart_sessions  no_cart_ratio
card        1              0              1                 1.0
pin         1              0              1                 1.0
tea         3              1              2                 0.6666666666666666
book        2              1              1                 0.5
mug         3              2              1                 0.3333333333333333

El controlador lee el Parquet realmente guardado antes de presentarlo. Ordena por no_cart_ratio descendente y después por identificador de producto, solo para facilitar la lectura de empates. Se conservan tanto card como pin; un empate no autoriza a eliminar uno. El producto poster, que solo tiene una adición, se excluye porque no tiene un par visualizado.

Los resultados son conjuntos de datos con tipos en output/main/journeys y output/main/report. El segundo tiene un identificador de producto de cadena, recuentos enteros y una proporción numérica. Los nombres y el número de partes Parquet son detalles de implementación, no la identidad del informe. Se aceptan expresiones Spark DataFrame/SQL equivalentes; mantenga una canalización desde la entrada suministrada y las transformaciones dentro de Spark. No recopile recorridos originales en Python, no cambie a RDD/pandas ni los recree tras un checkpoint.

Consumir los archivos y reconstruir la instantánea

En este paso, consumirá el pequeño CSV y reemplazará la instantánea derivada sin cambiar su fuente. Continúe en Terminal, en /home/labex/project.

El controlador preparado guarda output/main/report.csv como un único CSV UTF-8 pequeño para un compañero. Solo recopila la tabla final de productos, ya agregada, para serializarla después de que retorne build_report. Esta presentación final no sustituye las transformaciones Spark. Examine el archivo real:

cat output/main/report.csv

La cabecera contiene los mismos cinco campos que el informe Parquet. Compruebe los cinco productos, los recuentos cero de adiciones de card y pin y ambas proporciones empatadas de 1.0. Un CSV se lee como filas y campos; contar líneas o confiar en su nombre no demostraría esas relaciones.

Use el lector suministrado para consumir los dos conjuntos Parquet reales y el CSV. read_result.py lee la ruta de salida, formatea timestamps dentro de Spark en UTC y compara el contenido CSV con el informe guardado; no crea ni completa resultados ausentes:

bigdata-python read_result.py output/main

Espere diez filas de recorridos, cinco de productos y CSV matches stored report. Si falta un archivo, vuelva a ejecutar el análisis con la entrada y destino correctos; el lector falla deliberadamente en vez de inventar una respuesta.

sha256sum imprime una huella del contenido de cada archivo original. El patrón *.csv selecciona los CSV de data/. Compare estas líneas antes y después de reconstruir:

sha256sum data/*.csv
bigdata-python run_analysis.py data/batch.csv output/main --stage report
bigdata-python read_result.py output/main
sha256sum data/*.csv

La misma entrada produce el mismo informe lógico sin productos ni recorridos duplicados. Las huellas originales deben permanecer iguales. Los nombres o bytes Parquet pueden variar entre construcciones; la repetibilidad exige el mismo contenido lógico. El escritor solo reemplaza este destino derivado conocido, no los archivos originales ni otro directorio de resultados.

Ahora use el módulo guardado con el ejemplo normal y un destino separado:

bigdata-python run_analysis.py data/normal.csv output/normal --stage report
bigdata-python read_result.py output/normal

Espere dos filas de productos, cada una con una sesión visualizada, una con adición al carrito, cero sin adición y proporción 0. El resultado principal sigue intacto. Las mismas funciones parametrizadas admiten ambos lotes.

card y pin merecen atención en este lote pequeño, pero cada uno tiene una sola sesión observada. Una proporción alta no establece por qué se detuvo un visitante, no identifica personas únicas ni garantiza que el patrón continúe. Los recuentos y todos los empates permiten revisar la observación; haría falta más evidencia para afirmar causalidad.

La evaluación lee los resultados reales sin reconstruirlos. También carga el módulo sin modificarlo y llama a sus funciones sobre un lote desechable con otros identificadores y orden de filas, observa el linaje real de entrada Spark y consume salidas desechables. No puntúa una escritura exacta del comando, un plan propio ni una marca de nombre de aplicación, y nunca repara el resultado real. Mantenga las funciones sin escrituras; la serialización pertenece al controlador.

Resumen

Construyó y consumió comparaciones Parquet y CSV completas, mantuvo los productos sin adiciones y los empates y reconstruyó una instantánea derivada conservando las entradas originales. Los denominadores y recuentos explican cada proporción. Estos patrones de sesiones cerradas respaldan nuevas observaciones, no afirmaciones causales.