0% found this document useful (0 votes)
10 views4 pages

Process CSV Reviews with Rayon

The document outlines a Rust program that processes CSV files containing game reviews, utilizing the Rayon library for parallel processing. It calculates the top games and languages based on review counts and helpful votes, returning a final summary with detailed statistics. Key functions include grouping reviews by game and language, sorting them, and selecting the top entries for each category.

Uploaded by

Sol U
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as ODT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
10 views4 pages

Process CSV Reviews with Rayon

The document outlines a Rust program that processes CSV files containing game reviews, utilizing the Rayon library for parallel processing. It calculates the top games and languages based on review counts and helpful votes, returning a final summary with detailed statistics. Key functions include grouping reviews by game and language, sorting them, and selecting the top entries for each category.

Uploaded by

Sol U
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as ODT, PDF, TXT or read online on Scribd

use rayon::prelude::*;

use std::{fs::File, io::{self, BufRead, BufReader}};


use std::path::Path;
use csv::ReaderBuilder;
use crate::models::{Review, GameSummary, LanguageSummary, FinalSummary,
ReviewSummary, LanguageTopReviews};
use std::time::Instant;
use std::collections::HashMap;

// Función principal para procesar los archivos CSV


pub fn process_csv_files(file_path: &str, num_threads: usize) -> io::Result<FinalSummary>
{
// Configurar el pool de threads de rayon
rayon::ThreadPoolBuilder::new()
.num_threads(num_threads)
.build_global()
.unwrap();

let path = Path::new(file_path);


let file = File::open(path)?;
let reader = BufReader::new(file);

// Usamos csv::ReaderBuilder si es CSV bien estructurado


let mut rdr = csv::Reader::from_reader(reader);
let mut reviews = Vec::new();

for result in [Link]() {


let review: Review = match result {
Ok(r) => r,
Err(_) => continue,
};
[Link](review);
}

let top_games = calculate_top_games(&reviews);


let top_languages = calculate_top_languages(&reviews);

Ok(FinalSummary {
padron: 123456, // Reemplazá con tu padrón real
top_games,
top_languages,
})
}
fn calculate_top_games(reviews: &[Review]) -> Vec<GameSummary> {
// Agrupar las reseñas por `app_name`
let game_reviews: HashMap<String, Vec<Review>> = reviews.par_iter()
.fold(HashMap::new, |mut acc, review| {
[Link](review.app_name.clone())
.or_insert_with(Vec::new)
.push([Link]());
acc
})
.reduce(HashMap::new, |mut acc, part| {
for (key, value) in part {
[Link](key)
.or_insert_with(Vec::new)
.extend(value);
}
acc
});

// Crear un vector con el número de reseñas por juego


let mut game_summary: Vec<(String, usize)> = game_reviews.iter()
.map(|(game, reviews)| ([Link](), [Link]()))
.collect();

// Ordenar por la cantidad de reseñas (de mayor a menor)


game_summary.sort_by(|a, b| [Link](&a.1));

// Seleccionar los top 10 juegos


game_summary.into_iter()
.take(3)
.map(|(game, count)| {
let languages = calculate_languages(&game_reviews[&game]); // Recalcular los idiomas
para cada juego
GameSummary {
game,
review_count: count as u32,
languages,
}
})
.collect()
}

fn calculate_languages(reviews: &[Review]) -> Vec<LanguageSummary> {


// Agrupar las reseñas por idioma
let mut language_reviews: HashMap<String, Vec<Review>> = reviews.par_iter()
.fold(HashMap::new, |mut acc, review| {
[Link]([Link]())
.or_insert_with(Vec::new)
.push([Link]());
acc
})
.reduce(HashMap::new, |mut acc, part| {
for (key, value) in part {
[Link](key)
.or_insert_with(Vec::new)
.extend(value);
}
acc
});
// Ordenar los idiomas por cantidad de reseñas (de mayor a menor)
let mut language_summary: Vec<(String, usize)> = language_reviews.iter()
.map(|(language, reviews)| ([Link](), [Link]()))
.collect();

language_summary.sort_by(|a, b| [Link](&a.1).then([Link](&b.0))); // Ordenar por


cantidad y alfabéticamente en caso de empate

// Seleccionar los 3 idiomas más utilizados


let top_languages = language_summary.into_iter()
.take(3)
.map(|(language, count)| {
let top_review = language_reviews[&language].iter()
.max_by_key(|r| r.votes_helpful)
.map(|review| ReviewSummary {
review: [Link](),
votes: review.votes_helpful,
})
.unwrap_or(ReviewSummary {
review: String::new(),
votes: 0,
});

LanguageSummary {
language,
review_count: count as u32,
top_review: top_review.review,
top_review_votes: top_review.votes,
}
})
.collect(); // Se agregó el `collect` correctamente aquí para que la función devuelva el
valor esperado

top_languages
}
fn calculate_top_languages(reviews: &[Review]) -> Vec<LanguageTopReviews> {
use rayon::prelude::*;
use std::collections::HashMap;

// Agrupar reseñas por idioma


let mut language_map: HashMap<String, Vec<Review>> = HashMap::new();
for review in [Link]().cloned() {
language_map
.entry([Link]())
.or_insert_with(Vec::new)
.push(review);
}

// Calcular el top 3 de idiomas más utilizados (orden alfabético en caso de empate)


let mut language_counts: Vec<(String, usize)> = language_map
.iter()
.map(|(lang, reviews)| ([Link](), [Link]()))
.collect();

language_counts.sort_by(|a, b| [Link](&a.1).then([Link](&b.0)));

language_counts
.into_iter()
.take(3)
.map(|(language, count)| {
let mut reviews = language_map.remove(&language).unwrap_or_default();

// Obtener el top 10 de reseñas más votadas


reviews.sort_by(|a, b| b.votes_helpful.cmp(&a.votes_helpful));
let top_reviews: Vec<ReviewSummary> = reviews
.into_iter()
.take(10)
.map(|r| ReviewSummary {
review: [Link],
votes: r.votes_helpful,
})
.collect();

LanguageTopReviews {
language,
review_count: count as u32,
top_reviews,
}
})
.collect()
}

You might also like