Skip to content

Commit 6cc3cd9

Browse files
committed
fix: Rank missing field values lower than extant
1 parent e5221f0 commit 6cc3cd9

File tree

2 files changed

+66
-9
lines changed

2 files changed

+66
-9
lines changed

src/aggregation/metric/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ pub struct TopHitsVecEntry {
9191
/// The document id, composed of segment local `DocId` and segment ordinal.
9292
pub id: DocAddress,
9393
/// The sort values of the document, depending on the sort criteria in the request.
94-
pub sort: Vec<u64>,
94+
pub sort: Vec<Option<u64>>,
9595
}
9696

9797
/// The top_hits metric aggregation results a list of top hits by sort criteria.

src/aggregation/metric/top_hits.rs

+65-8
Original file line numberDiff line numberDiff line change
@@ -110,16 +110,23 @@ impl TopHitsAggregation {
110110
#[derive(Clone, Serialize, Deserialize, Debug)]
111111
struct ComparableDocFeature {
112112
/// Stores any u64-mappable feature.
113-
value: u64,
113+
value: Option<u64>,
114114
/// Sort order for the doc feature
115115
order: Order,
116116
}
117117

118118
impl Ord for ComparableDocFeature {
119119
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
120-
match self.order {
121-
Order::Asc => self.value.cmp(&other.value),
122-
Order::Desc => other.value.cmp(&self.value),
120+
let invert = |cmp: std::cmp::Ordering| match self.order {
121+
Order::Asc => cmp,
122+
Order::Desc => cmp.reverse(),
123+
};
124+
125+
match (self.value, other.value) {
126+
(Some(self_value), Some(other_value)) => invert(self_value.cmp(&other_value)),
127+
(Some(_), None) => std::cmp::Ordering::Greater,
128+
(None, Some(_)) => std::cmp::Ordering::Less,
129+
(None, None) => std::cmp::Ordering::Equal,
123130
}
124131
}
125132
}
@@ -290,10 +297,9 @@ impl SegmentAggregationCollector for SegmentTopHitsCollector {
290297
.zip(self.inner_collector.req.sort.iter())
291298
.map(|((c, _), KeyOrder(_, order))| {
292299
let order = *order;
293-
match c.values_for_doc(doc_id).next() {
294-
Some(value) => ComparableDocFeature { value, order },
295-
// TODO: confirm if this default 0-value is correct
296-
None => ComparableDocFeature { value: 0, order },
300+
ComparableDocFeature {
301+
value: c.values_for_doc(doc_id).next(),
302+
order,
297303
}
298304
})
299305
.collect();
@@ -323,3 +329,54 @@ impl SegmentAggregationCollector for SegmentTopHitsCollector {
323329
Ok(())
324330
}
325331
}
332+
333+
#[cfg(test)]
334+
mod tests {
335+
use serde_json::Value;
336+
337+
use super::{ComparableDoc, ComparableDocFeature, ComparableDocFeatures, Order};
338+
use crate::aggregation::agg_req::Aggregations;
339+
use crate::aggregation::agg_result::AggregationResults;
340+
use crate::aggregation::bucket::tests::get_test_index_from_docs;
341+
use crate::aggregation::tests::get_test_index_from_values;
342+
use crate::aggregation::AggregationCollector;
343+
use crate::query::AllQuery;
344+
345+
fn invert_order(cmp_feature: ComparableDocFeature) -> ComparableDocFeature {
346+
let ComparableDocFeature { value, order } = cmp_feature;
347+
let order = match order {
348+
Order::Asc => Order::Desc,
349+
Order::Desc => Order::Asc,
350+
};
351+
ComparableDocFeature { value, order }
352+
}
353+
354+
#[test]
355+
fn test_comparable_doc_feature() -> crate::Result<()> {
356+
let small = ComparableDocFeature {
357+
value: Some(1),
358+
order: Order::Asc,
359+
};
360+
let big = ComparableDocFeature {
361+
value: Some(2),
362+
order: Order::Asc,
363+
};
364+
let none = ComparableDocFeature {
365+
value: None,
366+
order: Order::Asc,
367+
};
368+
369+
assert!(small < big);
370+
assert!(none < small);
371+
assert!(none < big);
372+
373+
let small = invert_order(small);
374+
let big = invert_order(big);
375+
let none = invert_order(none);
376+
377+
assert!(small > big);
378+
assert!(none < small);
379+
assert!(none < big);
380+
381+
Ok(())
382+
}

0 commit comments

Comments
 (0)