1use {
2 crate::{
3 benchmark::{BenchmarkConfig, BenchmarkMetadata, SubTask, 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 subtasks: &[
25 SubTask {
26 name: "Scale 1",
27 data_paths: &["data/dataset1-uniform/scale1"],
28 query_paths: &[
29 "queries/query1.txt",
30 "queries/query2.txt",
31 "queries/query3.txt",
32 ],
33 description: "Scale 1 Dataset",
34 },
35 SubTask {
36 name: "Scale 2",
37 data_paths: &["data/dataset1-uniform/scale2"],
38 query_paths: &[
39 "queries/query1.txt",
40 "queries/query2.txt",
41 "queries/query3.txt",
42 ],
43 description: "Scale 2 Dataset",
44 },
45 SubTask {
46 name: "Scale 3",
47 data_paths: &["data/dataset1-uniform/scale3"],
48 query_paths: &[
49 "queries/query1.txt",
50 "queries/query2.txt",
51 "queries/query3.txt",
52 ],
53 description: "Scale 3 Dataset",
54 },
55 SubTask {
56 name: "Scale 4",
57 data_paths: &["data/dataset1-uniform/scale4"],
58 query_paths: &[
59 "queries/query1.txt",
60 "queries/query2.txt",
61 "queries/query3.txt",
62 ],
63 description: "Scale 4 Dataset",
64 },
65 SubTask {
66 name: "Scale 5",
67 data_paths: &["data/dataset1-uniform/scale5"],
68 query_paths: &[
69 "queries/query1.txt",
70 "queries/query2.txt",
71 "queries/query3.txt",
72 ],
73 description: "Scale 5 Dataset",
74 },
75 SubTask {
76 name: "Scale 6",
77 data_paths: &["data/dataset1-uniform/scale6"],
78 query_paths: &[
79 "queries/query1.txt",
80 "queries/query2.txt",
81 "queries/query3.txt",
82 ],
83 description: "Scale 6 Dataset",
84 },
85 ],
86 },
87 Task {
88 name: "Zipf",
89 description: "Zipf distributed data",
90 subtasks: &[
91 SubTask {
92 name: "Scale 1",
93 data_paths: &["data/dataset2-zipf/scale1"],
94 query_paths: &[
95 "queries/query1.txt",
96 "queries/query2.txt",
97 "queries/query3.txt",
98 ],
99 description: "Scale 1 Dataset",
100 },
101 SubTask {
102 name: "Scale 2",
103 data_paths: &["data/dataset2-zipf/scale2"],
104 query_paths: &[
105 "queries/query1.txt",
106 "queries/query2.txt",
107 "queries/query3.txt",
108 ],
109 description: "Scale 2 Dataset",
110 },
111 SubTask {
112 name: "Scale 3",
113 data_paths: &["data/dataset2-zipf/scale3"],
114 query_paths: &[
115 "queries/query1.txt",
116 "queries/query2.txt",
117 "queries/query3.txt",
118 ],
119 description: "Scale 3 Dataset",
120 },
121 SubTask {
122 name: "Scale 4",
123 data_paths: &["data/dataset2-zipf/scale4"],
124 query_paths: &[
125 "queries/query1.txt",
126 "queries/query2.txt",
127 "queries/query3.txt",
128 ],
129 description: "Scale 4 Dataset",
130 },
131 SubTask {
132 name: "Scale 5",
133 data_paths: &["data/dataset2-zipf/scale5"],
134 query_paths: &[
135 "queries/query1.txt",
136 "queries/query2.txt",
137 "queries/query3.txt",
138 ],
139 description: "Scale 5 Dataset",
140 },
141 SubTask {
142 name: "Scale 6",
143 data_paths: &["data/dataset2-zipf/scale6"],
144 query_paths: &[
145 "queries/query1.txt",
146 "queries/query2.txt",
147 "queries/query3.txt",
148 ],
149 description: "Scale 6 Dataset",
150 },
151 ],
152 },
153 ],
154};
155
156fn translate_dataset(source: &Path, dest: &Path) {
157 let header_path = source.join("databasefile");
159 let headers: Vec<String> = std::fs::read_to_string(&header_path)
160 .unwrap()
161 .lines()
162 .map(|s| s.to_string())
163 .collect();
164
165 for header in headers {
166 let header_content: Vec<String> = header.split(",").map(|s| s.trim().to_string()).collect();
167
168 let rel_file_name = &header_content[0];
169 let rel_name = &header_content[1];
170 let rel_attrs: Vec<String> = header_content[2..]
171 .iter()
172 .map(|s| s.trim().to_string())
173 .filter(|s| !s.is_empty())
174 .collect();
175
176 let data_path = source.join(rel_file_name);
177
178 let data_content: Vec<Vec<usize>> = std::fs::read_to_string(data_path)
179 .unwrap()
180 .trim()
181 .lines()
182 .map(|line| {
183 line.split(",")
184 .take(rel_attrs.len())
185 .map(|s| s.trim().parse::<usize>().unwrap())
186 .collect()
187 })
188 .collect();
189
190 utils::write_relation_to_parquet(
191 &dest.join(format!("{}.parquet", rel_name)),
192 &rel_attrs,
193 &data_content,
194 )
195 .unwrap();
196 }
197}
198
199fn translate_query(source: &Path, dest: &Path) {
200 let query_content: Vec<_> = std::fs::read_to_string(source)
201 .unwrap()
202 .lines()
203 .map(|s| s.to_string())
204 .collect();
205 let rels = query_content[0]
206 .split(",")
207 .filter(|s| !s.is_empty())
208 .map(|s| s.trim())
209 .collect::<Vec<_>>();
210 let attrs = query_content[1]
211 .split(",")
212 .filter(|s| !s.is_empty())
213 .map(|s| s.trim())
214 .collect::<Vec<_>>();
215 let mut file = std::fs::File::create(dest).unwrap();
217 use std::io::Write;
218 writeln!(file, "{}", rels.join(",")).unwrap();
219 writeln!(file, "{}", attrs.join(",")).unwrap();
220}
221
222impl BenchmarkConfig for OxfordBenchmark {
223 fn metadata(&self) -> &BenchmarkMetadata { &METADATA }
224
225 fn load(&self, source: &Path, path: &Path) -> Result<(), Box<dyn std::error::Error>> {
226 let dl_spec = &self.metadata().download_spec;
227
228 let data_dir = path.join(dl_spec.name).join("data");
234
235 let ds_tmp_path = source.join("datasets");
237
238 for dataset_parent in ["dataset1-uniform", "dataset2-zipf"] {
239 for dataset_sub in ["scale1", "scale2", "scale3", "scale4", "scale5", "scale6"] {
240 let source_path = ds_tmp_path.join(dataset_parent).join(dataset_sub);
242
243 let dest_path = data_dir.join(dataset_parent).join(dataset_sub);
245
246 if !dest_path.exists() {
248 std::fs::create_dir_all(&dest_path)?;
249 }
250
251 translate_dataset(&source_path, &dest_path);
252 }
253 }
254
255 let queries_dest = path.join(dl_spec.name).join("queries");
257
258 if !queries_dest.exists() {
259 std::fs::create_dir_all(&queries_dest)?;
260 }
261 for query_file in ["query1", "query2", "query3"] {
262 let source_path = ds_tmp_path.join(query_file);
264 let dest_path = queries_dest.join(format!("{}.txt", query_file));
266 translate_query(&source_path, &dest_path);
267 }
268
269 Ok(())
270 }
271}