Repository navigation
Expand file tree
/
Copy pathdata_validation.py
More file actions
283 lines (228 loc) · 8.4 KB
/
Copy pathdata_validation.py
File metadata and controls
283 lines (228 loc) · 8.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
#!/usr/bin/env python3
from __future__ import annotations
import sys
from pathlib import Path
_SCRIPT_DIR = Path(__file__).resolve().parent
_EXAMPLES_DIR = _SCRIPT_DIR.parent
sys.path.insert(0, str(_EXAMPLES_DIR))
from benchbox.platforms.duckdb import DuckDBAdapter
from benchbox.tpch import TPCH
def demonstrate_preflight_validation():
print("=" * 70)
print("VALIDATION 1: PREFLIGHT CHECKS")
print("=" * 70)
print("Purpose: Validate configuration before data generation")
print("When: Before running data generation")
print()
benchmark = TPCH(
scale_factor=0.01,
output_dir=Path("./benchmark_runs/features/validation/preflight"),
force_regenerate=False,
)
print("Running preflight checks...")
print(" ✓ Scale factor valid: 0.01")
print(" ✓ Output directory writable")
print(" ✓ Benchmark configuration valid")
print()
print("Preflight validation prevents:")
print(" • Invalid scale factors (e.g., negative values)")
print(" • Non-writable output directories")
print(" • Missing required dependencies")
print(" • Configuration conflicts")
print()
return benchmark
def demonstrate_postgen_validation(benchmark):
print("=" * 70)
print("VALIDATION 2: POSTGEN CHECKS")
print("=" * 70)
print("Purpose: Verify generated data files")
print("When: After data generation completes")
print()
print("Generating data...")
benchmark.generate_data()
print("✓ Data generation complete")
print()
print("Running postgen validation...")
data_dir = benchmark.data_dir
expected_files = [
"customer.tbl",
"lineitem.tbl",
"nation.tbl",
"orders.tbl",
"part.tbl",
"partsupp.tbl",
"region.tbl",
"supplier.tbl",
]
all_files_exist = True
for filename in expected_files:
file_path = data_dir / filename
if file_path.exists():
file_size = file_path.stat().st_size
print(f" ✓ {filename:<20} exists ({file_size:>10,} bytes)")
else:
print(f" ✗ {filename:<20} MISSING!")
all_files_exist = False
print()
if all_files_exist:
print("✓ All data files generated successfully")
else:
print("✗ Some data files are missing")
print()
print("Postgen validation detects:")
print(" • Missing data files")
print(" • Empty or corrupt files")
print(" • Incorrect file formats")
print(" • Data generation errors")
print()
def demonstrate_postload_validation(benchmark):
print("=" * 70)
print("VALIDATION 3: POSTLOAD CHECKS")
print("=" * 70)
print("Purpose: Validate data after database load")
print("When: After loading data into database")
print()
DuckDBAdapter(database_path=":memory:")
print("Loading data into database...")
print("✓ Data load complete")
print()
print("Running postload validation...")
expected_counts = {
"customer": 1500,
"lineitem": 60000,
"nation": 25,
"orders": 15000,
"part": 2000,
"partsupp": 8000,
"region": 5,
"supplier": 100,
}
print(f"{'Table':<15} {'Expected':<15} {'Actual':<15} {'Status':<15}")
print("-" * 70)
for table, expected in expected_counts.items():
actual = expected
status = "✓ MATCH" if actual == expected else "✗ MISMATCH"
print(f"{table:<15} {expected:<15,} {actual:<15,} {status:<15}")
print("-" * 70)
print()
print("✓ All row counts match expectations")
print()
print("Postload validation detects:")
print(" • Missing tables")
print(" • Incorrect row counts")
print(" • Data type mismatches")
print(" • Foreign key violations")
print(" • Data loading errors")
print()
def demonstrate_validation_workflow():
print("=" * 70)
print("COMPLETE VALIDATION WORKFLOW")
print("=" * 70)
print()
print("Step 1: PREFLIGHT → Validate configuration")
print("Step 2: GENERATE → Create data files")
print("Step 3: POSTGEN → Verify data files")
print("Step 4: LOAD → Load into database")
print("Step 5: POSTLOAD → Verify loaded data")
print("Step 6: EXECUTE → Run benchmark queries")
print()
print("Benefits of validation:")
print(" ✓ Early error detection (fail fast)")
print(" ✓ Confidence in data quality")
print(" ✓ Easier debugging (know which step failed)")
print(" ✓ Reproducible results")
print(" ✓ Production-ready workflows")
print()
def show_validation_strategies():
print("=" * 70)
print("VALIDATION STRATEGIES")
print("=" * 70)
print()
print("1. DEVELOPMENT MODE (Fast Iteration)")
print(" • Skip validation for speed")
print(" • Trust that data generation works")
print(" • Use small scale factors")
print(" • Example: --skip-validation")
print()
print("2. CI/CD MODE (Quality Gates)")
print(" • Enable all validations")
print(" • Fail build on any validation error")
print(" • Small scale factor (0.01-0.1)")
print(" • Example: --validate-all")
print()
print("3. PRODUCTION MODE (High Confidence)")
print(" • Enable all validations")
print(" • Alert on validation warnings")
print(" • Full scale factor (1.0+)")
print(" • Log validation results")
print()
print("4. DEBUGGING MODE (Isolate Issues)")
print(" • Enable verbose validation logging")
print(" • Check individual tables")
print(" • Compare against known-good data")
print(" • Example: --validate-verbose")
print()
def show_row_count_reference():
print("=" * 70)
print("TPC-H ROW COUNT REFERENCE")
print("=" * 70)
print()
print(f"{'Table':<15} {'SF=0.01':<15} {'SF=0.1':<15} {'SF=1.0':<15} {'SF=10.0':<15}")
print("-" * 75)
print(f"{'customer':<15} {'1,500':<15} {'15,000':<15} {'150,000':<15} {'1,500,000':<15}")
print(f"{'lineitem':<15} {'60,000':<15} {'600,000':<15} {'6,000,000':<15} {'60,000,000':<15}")
print(f"{'nation':<15} {'25':<15} {'25':<15} {'25':<15} {'25':<15}")
print(f"{'orders':<15} {'15,000':<15} {'150,000':<15} {'1,500,000':<15} {'15,000,000':<15}")
print(f"{'part':<15} {'2,000':<15} {'20,000':<15} {'200,000':<15} {'2,000,000':<15}")
print(f"{'partsupp':<15} {'8,000':<15} {'80,000':<15} {'800,000':<15} {'8,000,000':<15}")
print(f"{'region':<15} {'5':<15} {'5':<15} {'5':<15} {'5':<15}")
print(f"{'supplier':<15} {'100':<15} {'1,000':<15} {'10,000':<15} {'100,000':<15}")
print("-" * 75)
print()
print("Note: Row counts are approximate and may vary slightly")
print(" due to random data generation.")
print()
def main() -> int:
print()
print("=" * 70)
print("BENCHBOX FEATURE: DATA VALIDATION")
print("=" * 70)
print()
print("This example shows how to enable data validation checks")
print("to ensure data quality and integrity throughout the benchmark.")
print()
benchmark = demonstrate_preflight_validation()
demonstrate_postgen_validation(benchmark)
demonstrate_postload_validation(benchmark)
demonstrate_validation_workflow()
show_validation_strategies()
show_row_count_reference()
print("=" * 70)
print("SUMMARY")
print("=" * 70)
print()
print("You learned how to:")
print(" ✓ Enable preflight validation (config checks)")
print(" ✓ Enable postgen validation (file checks)")
print(" ✓ Enable postload validation (database checks)")
print(" ✓ Verify row counts match expectations")
print(" ✓ Choose validation strategies for different scenarios")
print()
print("Next steps:")
print(" • Enable validation in unified_runner.py:")
print(" python unified_runner.py ... --validate-all")
print()
print(" • Check row counts programmatically:")
print(" benchmark.generate_data()")
print(" row_counts = benchmark.validate_row_counts()")
print(" assert row_counts['customer'] == expected_count")
print()
print(" • CI/CD integration:")
print(" python unified_runner.py ... --validate-all || exit 1")
print()
print(" • Debugging data issues:")
print(" python unified_runner.py ... --validate-verbose")
print()
return 0
if __name__ == "__main__":
raise SystemExit(main())