mod common;
use std::hint::black_box;
use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main};
use laurus::lexical::TermQuery;
use laurus::lexical::search::features::highlight::{
HighlightConfig, Highlighter, SimpleHighlighter,
};
const VOCAB: &[&str] = &[
"search",
"engine",
"index",
"document",
"field",
"term",
"query",
"rust",
"performance",
"latency",
"throughput",
"cluster",
"node",
"leader",
"shard",
"tokenize",
"analyze",
"vector",
"similarity",
"ranking",
];
fn build_text(target_bytes: usize) -> String {
let mut out = String::with_capacity(target_bytes + 16);
let mut i = 0usize;
while out.len() < target_bytes {
if !out.is_empty() {
out.push(' ');
}
let word_idx = (i * 7 + i / 5) % VOCAB.len();
out.push_str(VOCAB[word_idx]);
i += 1;
}
out
}
fn pick_terms(n: usize) -> Vec<&'static str> {
(0..n).map(|i| VOCAB[(i * 13) % VOCAB.len()]).collect()
}
fn bench_simple_highlight_terms(c: &mut Criterion) {
let mut group = c.benchmark_group("highlight/simple_highlight");
let highlighter = SimpleHighlighter::new(HighlightConfig::default());
for &(label, target_bytes) in &[("1KB", 1024usize), ("100KB", 100 * 1024)] {
let text = build_text(target_bytes);
for &n_terms in &[1usize, 5, 20] {
let terms = pick_terms(n_terms);
let probe = highlighter.highlight_terms(&text, &terms);
assert!(
probe.contains("<mark>"),
"simple_highlight probe must contain at least one <mark> tag (size={label}, n_terms={n_terms})"
);
group.bench_with_input(
BenchmarkId::from_parameter(format!("{label}/n_terms_{n_terms}")),
&(),
|b, _| {
b.iter(|| {
let out = highlighter.highlight_terms(black_box(&text), black_box(&terms));
black_box(out);
});
},
);
}
}
group.finish();
}
fn bench_simple_highlight_terms_precompiled(c: &mut Criterion) {
let mut group = c.benchmark_group("highlight/simple_highlight_precompiled");
let highlighter = SimpleHighlighter::new(HighlightConfig::default());
for &(label, target_bytes) in &[("1KB", 1024usize), ("100KB", 100 * 1024)] {
let text = build_text(target_bytes);
for &n_terms in &[1usize, 5, 20] {
let terms = pick_terms(n_terms);
let patterns = SimpleHighlighter::compile_patterns(&terms);
let probe = highlighter.highlight_terms_compiled(&text, &patterns);
assert!(
probe.contains("<mark>"),
"simple_highlight_precompiled probe must contain at least one <mark> tag (size={label}, n_terms={n_terms})"
);
group.bench_with_input(
BenchmarkId::from_parameter(format!("{label}/n_terms_{n_terms}")),
&(),
|b, _| {
b.iter(|| {
let out = highlighter
.highlight_terms_compiled(black_box(&text), black_box(&patterns));
black_box(out);
});
},
);
}
}
group.finish();
}
fn bench_full_highlight_retokenize(c: &mut Criterion) {
let mut group = c.benchmark_group("highlight/retokenize");
let highlighter = Highlighter::new(HighlightConfig::default());
let query = TermQuery::new("body", "rust");
for &(label, target_bytes) in &[
("1KB", 1024usize),
("100KB", 100 * 1024),
("1MB", 1024 * 1024),
] {
let text = build_text(target_bytes);
let _probe = highlighter
.highlight(&query, "body", &text)
.expect("highlight probe must not error");
group.bench_with_input(BenchmarkId::from_parameter(label), &(), |b, _| {
b.iter(|| {
let out = highlighter
.highlight(black_box(&query), black_box("body"), black_box(&text))
.unwrap();
black_box(out);
});
});
}
group.finish();
}
fn bench_full_highlight_top_k(c: &mut Criterion) {
let mut group = c.benchmark_group("highlight/top_k");
let highlighter = Highlighter::new(HighlightConfig::default());
let query = TermQuery::new("body", "rust");
let text = build_text(10 * 1024);
let _probe = highlighter
.highlight(&query, "body", &text)
.expect("highlight probe must not error");
for &k in &[1usize, 10, 50] {
group.throughput(Throughput::Elements(k as u64));
group.bench_with_input(
BenchmarkId::from_parameter(format!("k_{k}")),
&k,
|b, &k| {
b.iter(|| {
for _ in 0..k {
let out = highlighter
.highlight(black_box(&query), black_box("body"), black_box(&text))
.unwrap();
black_box(out);
}
});
},
);
}
group.finish();
}
criterion_group!(
benches,
bench_simple_highlight_terms,
bench_simple_highlight_terms_precompiled,
bench_full_highlight_retokenize,
bench_full_highlight_top_k,
);
criterion_main!(benches);