Skip to content

Commit a0a024d

Browse files
committed
refactor(search): strip experimental scaffolding, tighten public API
Reduce the search PR to its shippable surface and make the public docs match behaviour: - Remove research/experiment scaffolding: the #[ignore]d experiment tests in src/search/mod.rs (LPM reachability, DFA dumps, first_codes distribution, inner-range probes), docs/SEARCH_OPTIMIZATION.md, the C++ search_bench harness (cpp-bench/search_bench.cpp + its CMake target), the bench's ONPAIR_SEARCH_DUMP / TPC-H parquet-dump utilities, and the now-dead #[cfg(test)] debug methods on KmpAutomaton (step_from, boundary_state_counts, dump_dfa). - Document SearchParts as a caller-validated view (like Parts): its public fields are unchecked, and search indexes codes by code_offsets without revalidating. - Fix the Column::first_codes doc: Parser::parse always populates it; the Option exists for columns rehydrated from storage that did not persist it (prefix search then falls back to the per-row scan). Public API is unchanged (Pattern, RowMask, SearchParts, Column::as_search_parts). All lib tests pass; clippy is clean on all targets.
1 parent 5edb52e commit a0a024d

9 files changed

Lines changed: 13 additions & 1242 deletions

File tree

benches/search.rs

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -676,59 +676,11 @@ fn first_code_per_row(bencher: Bencher) {
676676
});
677677
}
678678

679-
/// Dump the corpus and selected needles as length-prefixed little-endian
680-
/// binary so the C++ harness (`search_bench.cpp`) searches byte-identical
681-
/// inputs. Triggered by `ONPAIR_SEARCH_DUMP=<dir>`.
682-
///
683-
/// `corpus.bin`: `u64 n_rows`, then `n_rows × u32 row_len`, then the
684-
/// concatenated row bytes. `needles.bin`: `u32 count`, then per needle
685-
/// `u8 mode (0=contains,1=prefix)`, `u8 bucket_len` + bucket, `f64 sel`,
686-
/// `u32 len` + needle bytes.
687-
fn dump_for_cpp(dir: &str) {
688-
use std::io::Write;
689-
690-
let rows = &corpus().rows;
691-
let mut cf = std::io::BufWriter::new(File::create(format!("{dir}/corpus.bin")).unwrap());
692-
cf.write_all(&(rows.len() as u64).to_le_bytes()).unwrap();
693-
for r in rows {
694-
cf.write_all(&(r.len() as u32).to_le_bytes()).unwrap();
695-
}
696-
for r in rows {
697-
cf.write_all(r).unwrap();
698-
}
699-
cf.flush().unwrap();
700-
701-
let needles = select_needles();
702-
let mut nf = std::io::BufWriter::new(File::create(format!("{dir}/needles.bin")).unwrap());
703-
nf.write_all(&(needles.len() as u32).to_le_bytes()).unwrap();
704-
for n in needles {
705-
let mode: u8 = match n.mode {
706-
Mode::Contains => 0,
707-
Mode::Prefix => 1,
708-
};
709-
nf.write_all(&[mode]).unwrap();
710-
nf.write_all(&[n.bucket.len() as u8]).unwrap();
711-
nf.write_all(n.bucket.as_bytes()).unwrap();
712-
nf.write_all(&n.selectivity.to_le_bytes()).unwrap();
713-
nf.write_all(&(n.bytes.len() as u32).to_le_bytes()).unwrap();
714-
nf.write_all(&n.bytes).unwrap();
715-
}
716-
nf.flush().unwrap();
717-
eprintln!(
718-
"[onpair search] dumped {} rows + {} needles to {dir}",
719-
rows.len(),
720-
needles.len()
721-
);
722-
}
723-
724679
fn main() {
725680
// Touch corpus, column, and needles so the report prints before divan runs,
726681
// and cross-check the compressed-domain count against brute force.
727682
let _ = column();
728683
let rows = &corpus().rows;
729-
if let Ok(dir) = env::var("ONPAIR_SEARCH_DUMP") {
730-
dump_for_cpp(&dir);
731-
}
732684
eprintln!("[onpair search] selected needles (compressed-domain vs brute-force):");
733685
for n in select_needles() {
734686
let mode = match n.mode {

benches/tpch.rs

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -242,40 +242,7 @@ fn decompress_all(bencher: Bencher, param: (&'static str, u8)) {
242242
.bench(|| divan::black_box(decompress(column.as_parts())));
243243
}
244244

245-
/// EXPERIMENT #10: dump a TPC-H string column to parquet so the search bench can
246-
/// run prefix/contains on it.
247-
/// `ONPAIR_TPCH_DUMP_COL=l_comment ONPAIR_TPCH_DUMP_PATH=/tmp/tpch_lc.parquet \
248-
/// ONPAIR_TPCH_DUMP_PATH=/tmp/tpch_lc.parquet cargo bench --bench tpch`
249-
fn tpch_dump_parquet() {
250-
use arrow_array::{ArrayRef, RecordBatch, StringArray};
251-
use parquet::arrow::arrow_writer::ArrowWriter;
252-
use std::sync::Arc;
253-
let col = env::var("ONPAIR_TPCH_DUMP_COL").unwrap_or_else(|_| "l_comment".into());
254-
let path = env::var("ONPAIR_TPCH_DUMP_PATH").unwrap_or_else(|_| "/tmp/tpch.parquet".into());
255-
let (bytes, offsets) = generate_column(&col, scale_factor(), max_bytes());
256-
let strings: Vec<&str> = offsets
257-
.windows(2)
258-
.map(|w| std::str::from_utf8(&bytes[w[0] as usize..w[1] as usize]).unwrap_or(""))
259-
.collect();
260-
let arr: ArrayRef = Arc::new(StringArray::from(strings));
261-
let batch = RecordBatch::try_from_iter([(col.as_str(), arr)]).unwrap();
262-
let file = std::fs::File::create(&path).unwrap();
263-
let mut w = ArrowWriter::try_new(file, batch.schema(), None).unwrap();
264-
w.write(&batch).unwrap();
265-
w.close().unwrap();
266-
eprintln!(
267-
"[tpch dump] wrote {} rows of {col} to {path}",
268-
offsets.len() - 1
269-
);
270-
}
271-
272245
fn main() {
273-
// Experiment #10: if ONPAIR_TPCH_DUMP_PATH is set, dump one TPC-H string
274-
// column to parquet (for the search bench) and exit instead of benchmarking.
275-
if env::var_os("ONPAIR_TPCH_DUMP_PATH").is_some() {
276-
tpch_dump_parquet();
277-
return;
278-
}
279246
// Pre-warm every (col, bits) combo so the source + compression-ratio lines
280247
// print before divan starts emitting per-bench output.
281248
eprintln!("\n[onpair tpch bench] === corpora + compression ratios ===");

benchmarks/onpair-bench/README.md

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -89,28 +89,6 @@ uv sync --extra paper # HuggingFace datasets only
8989
uv sync --extra full # both
9090
```
9191

92-
## Compressed-domain search comparison
93-
94-
`benches/search.rs` (Rust, divan) and `cpp-bench/search_bench.cpp` (C++)
95-
benchmark the same `Contains` / `Prefix` searches over the same corpus and
96-
needles. The Rust bench's pre-pass buckets needles by selectivity (rare /
97-
medium / common) and, when `ONPAIR_SEARCH_DUMP=<dir>` is set, dumps
98-
`corpus.bin` + `needles.bin` so the C++ harness searches byte-identical
99-
inputs. Both count matches via a callback and cross-check against brute force.
100-
101-
```bash
102-
# Rust side (+ dump shared inputs). Defaults to a synthetic URL corpus;
103-
# point ONPAIR_BENCH_PARQUET at a parquet file for real data.
104-
mkdir -p /tmp/onpair_dump
105-
ONPAIR_SEARCH_DUMP=/tmp/onpair_dump cargo bench --bench search
106-
107-
# C++ side, on the dumped inputs (needs the submodule + Boost.Unordered ≥ 1.81):
108-
cmake -S benchmarks/onpair-bench/cpp-bench -B benchmarks/onpair-bench/cpp-bench/build \
109-
-DCMAKE_BUILD_TYPE=Release
110-
cmake --build benchmarks/onpair-bench/cpp-bench/build --target search_bench -j
111-
benchmarks/onpair-bench/cpp-bench/build/search_bench /tmp/onpair_dump --bits 16
112-
```
113-
11492
## Implementations
11593

11694
- **Rust**: `rust-bench` is a separate workspace whose `Cargo.toml` carries a

benchmarks/onpair-bench/cpp-bench/CMakeLists.txt

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,3 @@ target_compile_options(cpp_bench PRIVATE -O3 -DNDEBUG)
2828
if(COMMAND onpair_apply_configured_optimizations)
2929
onpair_apply_configured_optimizations(cpp_bench)
3030
endif()
31-
32-
add_executable(search_bench search_bench.cpp)
33-
target_link_libraries(search_bench PRIVATE onpair)
34-
target_compile_options(search_bench PRIVATE -O3 -DNDEBUG)
35-
if(COMMAND onpair_apply_configured_optimizations)
36-
onpair_apply_configured_optimizations(search_bench)
37-
endif()

benchmarks/onpair-bench/cpp-bench/search_bench.cpp

Lines changed: 0 additions & 231 deletions
This file was deleted.

0 commit comments

Comments
 (0)