kermit_bench/benchmarks/
oxford.rs

1use {
2    crate::{
3        benchmark::{Benchmark, BenchmarkMetadata, Task},
4        downloader::{DownloadMethod, DownloadSpec},
5        utils,
6    },
7    std::path::Path,
8};
9
10pub struct OxfordBenchmark;
11
12static METADATA: BenchmarkMetadata = BenchmarkMetadata {
13    name: "Oxford Dataset",
14    description: "Oxford Database Systems and Implementation final course exam",
15    download_spec: DownloadSpec {
16        name: "oxford_dataset",
17        method: DownloadMethod::CLONE,
18        url: "https://github.com/schroederdewitt/leapfrog-triejoin",
19    },
20    tasks: &[
21        Task {
22            name: "Uniform",
23            description: "Uniformly distributed data",
24            location: "dataset1-uniform",
25        },
26        Task {
27            name: "Zipf",
28            description: "Zipf distributed data",
29            location: "dataset2-zipf",
30        },
31    ],
32};
33
34fn translate_dataset(source: &Path, dest: &Path) {
35    // Get header names
36    let header_path = source.join("databasefile");
37    let headers: Vec<String> = std::fs::read_to_string(&header_path)
38        .unwrap()
39        .lines()
40        .map(|s| s.to_string())
41        .collect();
42
43    for header in headers {
44        let header_content: Vec<String> = header.split(",").map(|s| s.trim().to_string()).collect();
45
46        let rel_file_name = &header_content[0];
47        let rel_name = &header_content[1];
48        let rel_attrs: Vec<String> = header_content[2..]
49            .iter()
50            .map(|s| s.trim().to_string())
51            .filter(|s| !s.is_empty())
52            .collect();
53
54        let data_path = source.join(rel_file_name);
55
56        let data_content: Vec<Vec<usize>> = std::fs::read_to_string(data_path)
57            .unwrap()
58            .trim()
59            .lines()
60            .map(|line| {
61                line.split(",")
62                    .take(rel_attrs.len())
63                    .map(|s| s.trim().parse::<usize>().unwrap())
64                    .collect()
65            })
66            .collect();
67
68        utils::write_relation_to_parquet(
69            &dest.join(format!("{}.parquet", rel_name)),
70            &rel_attrs,
71            &data_content,
72        )
73        .unwrap();
74    }
75}
76
77fn translate_query(source: &Path, dest: &Path) {
78    let query_content: Vec<_> = std::fs::read_to_string(source)
79        .unwrap()
80        .lines()
81        .map(|s| s.to_string())
82        .collect();
83    let rels = query_content[0]
84        .split(",")
85        .filter(|s| !s.is_empty())
86        .map(|s| s.trim())
87        .collect::<Vec<_>>();
88    let attrs = query_content[1]
89        .split(",")
90        .filter(|s| !s.is_empty())
91        .map(|s| s.trim())
92        .collect::<Vec<_>>();
93    // Write files
94    let mut file = std::fs::File::create(dest).unwrap();
95    use std::io::Write;
96    writeln!(file, "{}", rels.join(",")).unwrap();
97    writeln!(file, "{}", attrs.join(",")).unwrap();
98}
99
100impl Benchmark for OxfordBenchmark {
101    fn metadata(&self) -> &BenchmarkMetadata { &METADATA }
102
103    fn load(&self, source: &Path, path: &Path) -> Result<(), Box<dyn std::error::Error>> {
104        let dl_spec = &self.metadata().download_spec;
105        let data_dest = path.join(dl_spec.name).join("data");
106        let ds_tmp_path = source.join("datasets");
107        for dataset_parent in ["dataset1-uniform", "dataset2-zipf"] {
108            for dataset_sub in ["scale1", "scale2", "scale3", "scale4", "scale5", "scale6"] {
109                let source_path = ds_tmp_path.join(dataset_parent).join(dataset_sub);
110                let dest_path = data_dest.join(dataset_parent).join(dataset_sub);
111                if !dest_path.exists() {
112                    std::fs::create_dir_all(&dest_path)?;
113                }
114                translate_dataset(&source_path, &dest_path);
115            }
116        }
117        let queries_dest = path.join(dl_spec.name).join("queries");
118        if !queries_dest.exists() {
119            std::fs::create_dir_all(&queries_dest)?;
120        }
121        for query_file in ["query1", "query2", "query3"] {
122            let source_path = ds_tmp_path.join(query_file);
123            let dest_path = queries_dest.join(format!("{}.txt", query_file));
124            translate_query(&source_path, &dest_path);
125        }
126        Ok(())
127    }
128}