caio.co/de/cantine

Add (partial) support for ascending sort

Now this works for everything fast-field. A new collector will be
needed for reversing `Sort::Relevance`
Id
311f2a6daa10848d4fad67083a132c52d52f2dcc
Author
Caio
Commit time
2020-01-09T20:31:30+01:00

Modified cantine/src/index.rs

@@ -17,7 +17,7

use tique::top_collector::{
fastfield, CheckCondition, ConditionForSegment, ConditionalTopCollector,
- CustomScoreTopCollector, SearchMarker,
+ CustomScoreTopCollector, ScorerForSegment, SearchMarker,
};

#[derive(Clone)]
@@ -77,17 +77,16
Ok(items)
}

- fn topk_u64(
+ fn topk_u64<S: 'static + ScorerForSegment<u64>>(
&self,
searcher: &Searcher,
query: &dyn Query,
limit: usize,
after: After,
- field: Field,
+ scorer: S,
) -> Result<(usize, Vec<RecipeId>, Option<After>)> {
let condition = Paginator::new_u64(self.id, after);
- let top_collector =
- CustomScoreTopCollector::new(limit, condition, fastfield::descending::<u64>(field));
+ let top_collector = CustomScoreTopCollector::new(limit, condition, scorer);

let result = searcher.search(query, &top_collector)?;
let items = self.addresses_to_ids(&searcher, &result.items)?;
@@ -104,17 +103,16
Ok((result.total, items, cursor))
}

- fn topk_f64(
+ fn topk_f64<S: 'static + ScorerForSegment<f64>>(
&self,
searcher: &Searcher,
query: &dyn Query,
limit: usize,
after: After,
- field: Field,
+ scorer: S,
) -> Result<(usize, Vec<RecipeId>, Option<After>)> {
let condition = Paginator::new_f64(self.id, after);
- let top_collector =
- CustomScoreTopCollector::new(limit, condition, fastfield::descending::<f64>(field));
+ let top_collector = CustomScoreTopCollector::new(limit, condition, scorer);

let result = searcher.search(query, &top_collector)?;
let items = self.addresses_to_ids(&searcher, &result.items)?;
@@ -137,22 +135,49
query: &dyn Query,
limit: usize,
sort: Sort,
+ ascending: bool,
after: After,
) -> Result<(usize, Vec<RecipeId>, Option<After>)> {
+ macro_rules! collect {
+ ($topk: ident, $field:ident) => {{
+ if ascending {
+ self.$topk(
+ searcher,
+ query,
+ limit,
+ after,
+ fastfield::ascending(self.features.$field),
+ )
+ } else {
+ self.$topk(
+ searcher,
+ query,
+ limit,
+ after,
+ fastfield::descending(self.features.$field),
+ )
+ }
+ }};
+ }
+
macro_rules! collect_unsigned {
($field:ident) => {{
- self.topk_u64(searcher, query, limit, after, self.features.$field)
+ collect!(topk_u64, $field)
}};
}

macro_rules! collect_float {
($field:ident) => {{
- self.topk_f64(searcher, query, limit, after, self.features.$field)
+ collect!(topk_f64, $field)
}};
}

match sort {
Sort::Relevance => {
+ if ascending {
+ todo!("TweakedScoreCollector");
+ }
+
let condition = Paginator::new(self.id, after);
let top_collector = ConditionalTopCollector::with_limit(limit, condition);

Modified cantine/src/main.rs

@@ -127,6 +127,7
&interpreted_query,
limit,
query.sort.unwrap_or(Sort::Relevance),
+ query.ascending,
after,
)?;

Modified cantine/src/model.rs

@@ -146,11 +146,14
#[serde(deny_unknown_fields)]
pub struct SearchQuery {
pub fulltext: Option<String>,
- pub sort: Option<Sort>,
pub num_items: Option<u8>,
pub filter: Option<FeaturesFilterQuery>,
pub agg: Option<FeaturesAggregationQuery>,
pub after: Option<SearchCursor>,
+
+ pub sort: Option<Sort>,
+ #[serde(default)]
+ pub ascending: bool,
}

#[derive(Serialize, Debug, Default)]

Modified cantine/tests/index_integration.rs

@@ -62,7 +62,7
let (_total, found_ids, next) =
GLOBAL
.cantine
- .search(&searcher, &AllQuery, 10, Sort::Relevance, after)?;
+ .search(&searcher, &AllQuery, 10, Sort::Relevance, false, after)?;

for id in found_ids {
seen.insert(id);
@@ -90,6 +90,7
&AllQuery,
INDEX_SIZE,
Sort::NumIngredients,
+ false,
After::START,
)?;

@@ -114,6 +115,7
&AllQuery,
INDEX_SIZE,
Sort::ProteinContent,
+ false,
After::START,
)?;

@@ -127,6 +129,31
}

assert!(last_protein < std::f32::MAX);
+
+ Ok(())
+}
+
+#[test]
+fn ascending_sort() -> Result<()> {
+ let reader = GLOBAL.index.reader()?;
+ let searcher = reader.searcher();
+
+ let (_total, found_ids, _next) = GLOBAL.cantine.search(
+ &searcher,
+ &AllQuery,
+ INDEX_SIZE,
+ Sort::InstructionsLength,
+ true,
+ After::START,
+ )?;
+
+ let mut last_len = 0;
+ for id in found_ids {
+ let recipe = GLOBAL.db.get(&id).unwrap();
+ let cur_len = recipe.features.instructions_length;
+ assert!(cur_len >= last_len);
+ last_len = cur_len;
+ }

Ok(())
}