Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion laurus/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1530,7 +1530,7 @@ impl Engine {
.collect();

// Sort by fused score descending
intermediate.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal));
intermediate.sort_by(|a, b| b.1.total_cmp(&a.1));

// Limit results
if intermediate.len() > limit {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ impl IndexOptimizer {

// Get all segments sorted by deletion ratio (highest first)
let mut segments = segment_manager.get_segments();
segments.sort_by(|a, b| b.deletion_ratio().partial_cmp(&a.deletion_ratio()).unwrap());
segments.sort_by(|a, b| b.deletion_ratio().total_cmp(&a.deletion_ratio()));

// Merge segments with any deletions first
let segments_with_deletions: Vec<_> = segments
Expand Down
25 changes: 6 additions & 19 deletions laurus/src/lexical/index/inverted/searcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -814,9 +814,7 @@ impl InvertedIndexSearcher {
SortField::Score => {
// Default behavior: already sorted by score from collector
// Re-sort to ensure descending order
hits.sort_unstable_by(|a, b| {
b.score.partial_cmp(&a.score).unwrap_or(Ordering::Equal)
});
hits.sort_unstable_by(|a, b| b.score.total_cmp(&a.score));
}
SortField::Field { name, order } => {
// Sort by field value
Expand Down Expand Up @@ -853,16 +851,13 @@ impl InvertedIndexSearcher {
// Same type comparisons
(Text(a_str), Text(b_str)) => a_str.cmp(b_str),
(Integer(a_int), Integer(b_int)) => a_int.cmp(b_int),
(Float(a_float), Float(b_float)) => {
a_float.partial_cmp(b_float).unwrap_or(Ordering::Equal)
}
(Float(a_float), Float(b_float)) => a_float.total_cmp(b_float),
(Boolean(a_bool), Boolean(b_bool)) => a_bool.cmp(b_bool),
(DateTime(a_dt), DateTime(b_dt)) => a_dt.cmp(b_dt),
(Geo(a), Geo(b)) => a
.lat
.partial_cmp(&b.lat)
.unwrap_or(Ordering::Equal)
.then_with(|| a.lon.partial_cmp(&b.lon).unwrap_or(Ordering::Equal)),
.total_cmp(&b.lat)
.then_with(|| a.lon.total_cmp(&b.lon)),
(Bytes(_, a_bytes), Bytes(_, b_bytes)) => a_bytes.cmp(b_bytes),
(Null, Null) => Ordering::Equal,

Expand Down Expand Up @@ -1259,21 +1254,13 @@ mod tests {
.search(LexicalSearchRequest::new(make_query()).limit(usize::MAX))
.unwrap();
let mut hits: Vec<_> = big.hits.into_iter().map(|h| (h.doc_id, h.score)).collect();
hits.sort_by(|x, y| {
y.1.partial_cmp(&x.1)
.unwrap_or(Ordering::Equal)
.then(x.0.cmp(&y.0))
});
hits.sort_by(|x, y| y.1.total_cmp(&x.1).then(x.0.cmp(&y.0)));
hits.truncate(10);
hits
};

let mut bmw_hits: Vec<_> = bmw.hits.iter().map(|h| (h.doc_id, h.score)).collect();
bmw_hits.sort_by(|x, y| {
y.1.partial_cmp(&x.1)
.unwrap_or(Ordering::Equal)
.then(x.0.cmp(&y.0))
});
bmw_hits.sort_by(|x, y| y.1.total_cmp(&x.1).then(x.0.cmp(&y.0)));
assert_eq!(bmw_hits.len(), reference.len(), "result count differs");
for (idx, (x, y)) in bmw_hits.iter().zip(reference.iter()).enumerate() {
assert_eq!(x.0, y.0, "rank {idx}: doc_id mismatch");
Expand Down
5 changes: 2 additions & 3 deletions laurus/src/lexical/index/inverted/segment/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -696,8 +696,7 @@ impl SegmentManager {
.filter(|s| s.deletion_ratio() > self.config.max_deletion_ratio / 2.0)
.collect();

high_deletion_segments
.sort_by(|a, b| b.deletion_ratio().partial_cmp(&a.deletion_ratio()).unwrap());
high_deletion_segments.sort_by(|a, b| b.deletion_ratio().total_cmp(&a.deletion_ratio()));

// Group high-deletion segments
for chunk in high_deletion_segments.chunks(self.config.segments_per_tier) {
Expand Down Expand Up @@ -765,7 +764,7 @@ impl SegmentManager {
all_candidates.extend(self.generate_time_based_candidates(segments));

// Sort by priority and remove duplicates
all_candidates.sort_by(|a, b| b.priority.partial_cmp(&a.priority).unwrap());
all_candidates.sort_by(|a, b| b.priority.total_cmp(&a.priority));
all_candidates.dedup_by(|a, b| a.segments == b.segments);

// Take top candidates
Expand Down
5 changes: 2 additions & 3 deletions laurus/src/lexical/index/inverted/segment/merge_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,7 @@ impl MergeEngine {
) -> Result<MergeResult> {
// Sort by deletion ratio (highest first for better compaction)
let mut sorted_segments = segments.to_vec();
sorted_segments
.sort_by(|a, b| b.deletion_ratio().partial_cmp(&a.deletion_ratio()).unwrap());
sorted_segments.sort_by(|a, b| b.deletion_ratio().total_cmp(&a.deletion_ratio()));

self.perform_merge(&sorted_segments, new_segment_id)
}
Expand Down Expand Up @@ -251,7 +250,7 @@ impl MergeEngine {
.collect();

// Sort by composite score (highest first)
scored_segments.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
scored_segments.sort_by(|a, b| b.1.total_cmp(&a.1));

let sorted_segments: Vec<_> = scored_segments.into_iter().map(|(seg, _)| seg).collect();

Expand Down
4 changes: 2 additions & 2 deletions laurus/src/lexical/index/inverted/segment/merge_policy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ impl MergePolicy for TieredMergePolicy {
}

// Sort by priority (highest first)
all_candidates.sort_by(|a, b| b.priority.partial_cmp(&a.priority).unwrap());
all_candidates.sort_by(|a, b| b.priority.total_cmp(&a.priority));

all_candidates
}
Expand Down Expand Up @@ -336,7 +336,7 @@ impl MergePolicy for LogStructuredMergePolicy {
}
}

candidates.sort_by(|a, b| b.priority.partial_cmp(&a.priority).unwrap());
candidates.sort_by(|a, b| b.priority.total_cmp(&a.priority));
candidates
}

Expand Down
2 changes: 1 addition & 1 deletion laurus/src/lexical/query/advanced_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ impl AdvancedQuery {
}

// Sort by score descending
results.sort_by(|a, b| b.score.partial_cmp(&a.score).unwrap());
results.sort_by(|a, b| b.score.total_cmp(&a.score));

Ok(results)
}
Expand Down
39 changes: 15 additions & 24 deletions laurus/src/lexical/query/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,17 +238,15 @@ impl<'a> Collector for TopFieldCollector<'a> {
sorted_docs.sort_unstable_by(|a, b| match (&a.field_value, &b.field_value) {
(FieldValue::Text(av), FieldValue::Text(bv)) => av.cmp(bv),
(FieldValue::Int64(av), FieldValue::Int64(bv)) => av.cmp(bv),
(FieldValue::Float64(av), FieldValue::Float64(bv)) => {
av.partial_cmp(bv).unwrap_or(Ordering::Equal)
}
(FieldValue::Float64(av), FieldValue::Float64(bv)) => av.total_cmp(bv),
(FieldValue::Bool(av), FieldValue::Bool(bv)) => av.cmp(bv),
(FieldValue::DateTime(av), FieldValue::DateTime(bv)) => av.cmp(bv),
(FieldValue::Geo(a), FieldValue::Geo(b)) => {
let lat_cmp = a.lat.partial_cmp(&b.lat).unwrap_or(Ordering::Equal);
let lat_cmp = a.lat.total_cmp(&b.lat);
if lat_cmp != Ordering::Equal {
lat_cmp
} else {
a.lon.partial_cmp(&b.lon).unwrap_or(Ordering::Equal)
a.lon.total_cmp(&b.lon)
}
}
(FieldValue::Bytes(av, _), FieldValue::Bytes(bv, _)) => av.cmp(bv),
Expand All @@ -262,17 +260,15 @@ impl<'a> Collector for TopFieldCollector<'a> {
sorted_docs.sort_unstable_by(|a, b| match (&a.field_value, &b.field_value) {
(FieldValue::Text(av), FieldValue::Text(bv)) => bv.cmp(av),
(FieldValue::Int64(av), FieldValue::Int64(bv)) => bv.cmp(av),
(FieldValue::Float64(av), FieldValue::Float64(bv)) => {
bv.partial_cmp(av).unwrap_or(Ordering::Equal)
}
(FieldValue::Float64(av), FieldValue::Float64(bv)) => bv.total_cmp(av),
(FieldValue::Bool(av), FieldValue::Bool(bv)) => bv.cmp(av),
(FieldValue::DateTime(av), FieldValue::DateTime(bv)) => bv.cmp(av),
(FieldValue::Geo(a), FieldValue::Geo(b)) => {
let lat_cmp = b.lat.partial_cmp(&a.lat).unwrap_or(Ordering::Equal);
let lat_cmp = b.lat.total_cmp(&a.lat);
if lat_cmp != Ordering::Equal {
lat_cmp
} else {
b.lon.partial_cmp(&a.lon).unwrap_or(Ordering::Equal)
b.lon.total_cmp(&a.lon)
}
}
(FieldValue::Bytes(av, _), FieldValue::Bytes(bv, _)) => bv.cmp(av),
Expand Down Expand Up @@ -342,17 +338,15 @@ impl Ord for FieldScoredDoc {
match (&self.field_value, &other.field_value) {
(FieldValue::Text(a), FieldValue::Text(b)) => b.cmp(a),
(FieldValue::Int64(a), FieldValue::Int64(b)) => b.cmp(a),
(FieldValue::Float64(a), FieldValue::Float64(b)) => {
b.partial_cmp(a).unwrap_or(Ordering::Equal)
}
(FieldValue::Float64(a), FieldValue::Float64(b)) => b.total_cmp(a),
(FieldValue::Bool(a), FieldValue::Bool(b)) => b.cmp(a),
(FieldValue::DateTime(a), FieldValue::DateTime(b)) => b.cmp(a),
(FieldValue::Geo(a), FieldValue::Geo(b)) => {
let lat_cmp = b.lat.partial_cmp(&a.lat).unwrap_or(Ordering::Equal);
let lat_cmp = b.lat.total_cmp(&a.lat);
if lat_cmp != Ordering::Equal {
lat_cmp
} else {
b.lon.partial_cmp(&a.lon).unwrap_or(Ordering::Equal)
b.lon.total_cmp(&a.lon)
}
}
(FieldValue::Bytes(a, _), FieldValue::Bytes(b, _)) => b.cmp(a),
Expand All @@ -366,17 +360,15 @@ impl Ord for FieldScoredDoc {
match (&self.field_value, &other.field_value) {
(FieldValue::Text(a), FieldValue::Text(b)) => a.cmp(b),
(FieldValue::Int64(a), FieldValue::Int64(b)) => a.cmp(b),
(FieldValue::Float64(a), FieldValue::Float64(b)) => {
a.partial_cmp(b).unwrap_or(Ordering::Equal)
}
(FieldValue::Float64(a), FieldValue::Float64(b)) => a.total_cmp(b),
(FieldValue::Bool(a), FieldValue::Bool(b)) => a.cmp(b),
(FieldValue::DateTime(a), FieldValue::DateTime(b)) => a.cmp(b),
(FieldValue::Geo(a), FieldValue::Geo(b)) => {
let lat_cmp = a.lat.partial_cmp(&b.lat).unwrap_or(Ordering::Equal);
let lat_cmp = a.lat.total_cmp(&b.lat);
if lat_cmp != Ordering::Equal {
lat_cmp
} else {
a.lon.partial_cmp(&b.lon).unwrap_or(Ordering::Equal)
a.lon.total_cmp(&b.lon)
}
}
(FieldValue::Bytes(a, _), FieldValue::Bytes(b, _)) => a.cmp(b),
Expand Down Expand Up @@ -411,8 +403,7 @@ impl Ord for ScoredDoc {
// Min-heap: lower scores come first
other
.score
.partial_cmp(&self.score)
.unwrap_or(Ordering::Equal)
.total_cmp(&self.score)
.then_with(|| other.doc_id.cmp(&self.doc_id))
}
}
Expand Down Expand Up @@ -496,7 +487,7 @@ impl Collector for TopDocsCollector {
.collect();

// Sort by score descending
results.sort_unstable_by(|a, b| b.score.partial_cmp(&a.score).unwrap_or(Ordering::Equal));
results.sort_unstable_by(|a, b| b.score.total_cmp(&a.score));

results
}
Expand Down Expand Up @@ -685,7 +676,7 @@ impl Collector for AllDocsCollector {
return cached.clone();
}
let mut results = self.hits.clone();
results.sort_unstable_by(|a, b| b.score.partial_cmp(&a.score).unwrap_or(Ordering::Equal));
results.sort_unstable_by(|a, b| b.score.total_cmp(&a.score));
*cache = Some(results.clone());
results
}
Expand Down
20 changes: 5 additions & 15 deletions laurus/src/lexical/query/geo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,13 +206,8 @@ impl GeoDistanceQuery {
// Sort by distance (closest first), then by relevance score
matches.sort_by(|a, b| {
a.distance_m
.partial_cmp(&b.distance_m)
.unwrap_or(std::cmp::Ordering::Equal)
.then_with(|| {
b.relevance_score
.partial_cmp(&a.relevance_score)
.unwrap_or(std::cmp::Ordering::Equal)
})
.total_cmp(&b.distance_m)
.then_with(|| b.relevance_score.total_cmp(&a.relevance_score))
});

Ok(matches)
Expand Down Expand Up @@ -575,9 +570,8 @@ impl GeoBoundingBoxQuery {
// Sort by relevance score (highest first), then by distance to center
matches.sort_by(|a, b| {
b.relevance_score
.partial_cmp(&a.relevance_score)
.unwrap()
.then_with(|| a.distance_m.partial_cmp(&b.distance_m).unwrap())
.total_cmp(&a.relevance_score)
.then_with(|| a.distance_m.total_cmp(&b.distance_m))
});

Ok(matches)
Expand Down Expand Up @@ -831,11 +825,7 @@ impl GeoMatcher {
/// Create a new geo matcher.
pub fn new(mut matches: Vec<GeoMatch>) -> Self {
// Sort matches by distance (closest first)
matches.sort_by(|a, b| {
a.distance_m
.partial_cmp(&b.distance_m)
.unwrap_or(std::cmp::Ordering::Equal)
});
matches.sort_by(|a, b| a.distance_m.total_cmp(&b.distance_m));

GeoMatcher {
matches,
Expand Down
28 changes: 8 additions & 20 deletions laurus/src/lexical/query/geo3d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,19 +136,13 @@ impl Geo3dDistanceQuery {

// Multi-segment readers can produce duplicates; keep the closest.
matches.sort_by(|a, b| {
a.doc_id.cmp(&b.doc_id).then_with(|| {
a.distance_m
.partial_cmp(&b.distance_m)
.unwrap_or(std::cmp::Ordering::Equal)
})
a.doc_id
.cmp(&b.doc_id)
.then_with(|| a.distance_m.total_cmp(&b.distance_m))
});
matches.dedup_by_key(|m| m.doc_id);
// Final order: distance ascending.
matches.sort_by(|a, b| {
a.distance_m
.partial_cmp(&b.distance_m)
.unwrap_or(std::cmp::Ordering::Equal)
});
matches.sort_by(|a, b| a.distance_m.total_cmp(&b.distance_m));

Ok(matches)
}
Expand Down Expand Up @@ -718,11 +712,9 @@ impl Geo3dNearestQuery {
// duplicates) to get an accurate "unique candidates" count.
let mut deduped = current.hits.clone();
deduped.sort_by(|a, b| {
a.doc_id.cmp(&b.doc_id).then_with(|| {
a.distance_sq
.partial_cmp(&b.distance_sq)
.unwrap_or(std::cmp::Ordering::Equal)
})
a.doc_id
.cmp(&b.doc_id)
.then_with(|| a.distance_sq.total_cmp(&b.distance_sq))
});
deduped.dedup_by_key(|h| h.doc_id);
let unique_count = deduped.len();
Expand Down Expand Up @@ -761,11 +753,7 @@ impl Geo3dNearestQuery {

// Final sort by distance ascending and truncation to top-k.
let mut hits = visitor.hits;
hits.sort_by(|a, b| {
a.distance_sq
.partial_cmp(&b.distance_sq)
.unwrap_or(std::cmp::Ordering::Equal)
});
hits.sort_by(|a, b| a.distance_sq.total_cmp(&b.distance_sq));
hits.truncate(self.k);

// Normalize scores against the farthest distance in the returned
Expand Down
6 changes: 2 additions & 4 deletions laurus/src/lexical/search/features/facet.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//! Faceted search functionality for categorizing and filtering search results.

use std::cmp::Ordering;
use std::collections::HashMap;

use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -623,7 +622,7 @@ impl FacetedSearchEngine {
}

// Sort hits by score
hits.sort_by(|a, b| b.score.partial_cmp(&a.score).unwrap_or(Ordering::Equal));
hits.sort_by(|a, b| b.score.total_cmp(&a.score));

// Finalize facet collection
let facet_results = facet_collector.finalize()?;
Expand Down Expand Up @@ -776,8 +775,7 @@ impl SearchGroup {

/// Sort documents in this group by score.
pub fn sort_by_score(&mut self) {
self.documents
.sort_by(|a, b| b.score.partial_cmp(&a.score).unwrap_or(Ordering::Equal));
self.documents.sort_by(|a, b| b.score.total_cmp(&a.score));
}

/// Limit the number of documents in this group.
Expand Down
14 changes: 4 additions & 10 deletions laurus/src/lexical/search/features/highlight.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,9 @@ impl FieldHighlight {

/// Get the best fragment (highest score).
pub fn best_fragment(&self) -> Option<&HighlightFragment> {
self.fragments.iter().max_by(|a, b| {
a.score
.partial_cmp(&b.score)
.unwrap_or(std::cmp::Ordering::Equal)
})
self.fragments
.iter()
.max_by(|a, b| a.score.total_cmp(&b.score))
}

/// Combine all fragments into a single string.
Expand Down Expand Up @@ -441,11 +439,7 @@ impl Highlighter {
}

// Sort fragments by score (highest first)
fragments.sort_by(|a, b| {
b.score
.partial_cmp(&a.score)
.unwrap_or(std::cmp::Ordering::Equal)
});
fragments.sort_by(|a, b| b.score.total_cmp(&a.score));

// Limit number of fragments
fragments.truncate(self.config.max_fragments);
Expand Down
Loading
Loading