diff --git a/milli/src/search/criteria/asc_desc.rs b/milli/src/search/criteria/asc_desc.rs index 7b619f26a..31edc453e 100644 --- a/milli/src/search/criteria/asc_desc.rs +++ b/milli/src/search/criteria/asc_desc.rs @@ -215,7 +215,7 @@ fn iterative_facet_ordered_iter<'t>( docids_values.push((docid, OrderedFloat(value))); } } - docids_values.sort_unstable_by_key(|(_, v)| v.clone()); + docids_values.sort_unstable_by_key(|(_, v)| *v); let iter = docids_values.into_iter(); let iter = if ascending { Box::new(iter) as Box> @@ -226,7 +226,7 @@ fn iterative_facet_ordered_iter<'t>( // The itertools GroupBy iterator doesn't provide an owned version, we are therefore // required to collect the result into an owned collection (a Vec). // https://github.com/rust-itertools/itertools/issues/499 - let vec: Vec<_> = iter.group_by(|(_, v)| v.clone()) + let vec: Vec<_> = iter.group_by(|(_, v)| *v) .into_iter() .map(|(_, ids)| ids.map(|(id, _)| id).collect()) .collect(); diff --git a/milli/src/search/criteria/attribute.rs b/milli/src/search/criteria/attribute.rs index fc7050a7f..9d4d88d0d 100644 --- a/milli/src/search/criteria/attribute.rs +++ b/milli/src/search/criteria/attribute.rs @@ -155,7 +155,7 @@ impl<'t, 'q> WordLevelIterator<'t, 'q> { fn new(ctx: &'t dyn Context<'t>, word: Cow<'q, str>, in_prefix_cache: bool) -> heed::Result> { match ctx.word_position_last_level(&word, in_prefix_cache)? { Some(level) => { - let interval_size = LEVEL_EXPONENTIATION_BASE.pow(Into::::into(level.clone()) as u32); + let interval_size = LEVEL_EXPONENTIATION_BASE.pow(Into::::into(level) as u32); let inner = ctx.word_position_iterator(&word, level, in_prefix_cache, None, None)?; Ok(Some(Self { inner, level, interval_size, word, in_prefix_cache, inner_next: None, current_interval: None })) }, @@ -164,8 +164,8 @@ impl<'t, 'q> WordLevelIterator<'t, 'q> { } fn dig(&self, ctx: &'t dyn Context<'t>, level: &TreeLevel, left_interval: Option) -> heed::Result { - let level = level.min(&self.level).clone(); - let interval_size = LEVEL_EXPONENTIATION_BASE.pow(Into::::into(level.clone()) as u32); + let level = *level.min(&self.level); + let interval_size = LEVEL_EXPONENTIATION_BASE.pow(Into::::into(level) as u32); let word = self.word.clone(); let in_prefix_cache = self.in_prefix_cache; let inner = ctx.word_position_iterator(&word, level, in_prefix_cache, left_interval, None)?; @@ -214,7 +214,7 @@ struct QueryLevelIterator<'t, 'q> { } impl<'t, 'q> QueryLevelIterator<'t, 'q> { - fn new(ctx: &'t dyn Context<'t>, queries: &'q Vec, wdcache: &mut WordDerivationsCache) -> anyhow::Result> { + fn new(ctx: &'t dyn Context<'t>, queries: &'q [Query], wdcache: &mut WordDerivationsCache) -> anyhow::Result> { let mut inner = Vec::with_capacity(queries.len()); for query in queries { match &query.kind { @@ -244,7 +244,7 @@ impl<'t, 'q> QueryLevelIterator<'t, 'q> { } } - let highest = inner.iter().max_by_key(|wli| wli.level).map(|wli| wli.level.clone()); + let highest = inner.iter().max_by_key(|wli| wli.level).map(|wli| wli.level); match highest { Some(level) => Ok(Some(Self { parent: None, @@ -287,7 +287,7 @@ impl<'t, 'q> QueryLevelIterator<'t, 'q> { let u8_level = Into::::into(level); let interval_size = LEVEL_EXPONENTIATION_BASE.pow(u8_level as u32); for wli in self.inner.iter_mut() { - let wli_u8_level = Into::::into(wli.level.clone()); + let wli_u8_level = Into::::into(wli.level); let accumulated_count = LEVEL_EXPONENTIATION_BASE.pow((u8_level - wli_u8_level) as u32); for _ in 0..accumulated_count { if let Some((next_left, _, next_docids)) = wli.next()? { @@ -364,8 +364,8 @@ fn interval_to_skip( already_skiped: usize, allowed_candidates: &RoaringBitmap, ) -> usize { - parent_accumulator.into_iter() - .zip(current_accumulator.into_iter()) + parent_accumulator.iter() + .zip(current_accumulator.iter()) .skip(already_skiped) .take_while(|(parent, current)| { let skip_parent = parent.as_ref().map_or(true, |(_, _, docids)| docids.is_empty()); @@ -410,7 +410,7 @@ impl<'t, 'q> Branch<'t, 'q> { /// update inner interval in order to be ranked by the binary_heap without computing it, /// the next() method should be called when the real interval is needed. fn lazy_next(&mut self) { - let u8_level = Into::::into(self.tree_level.clone()); + let u8_level = Into::::into(self.tree_level); let interval_size = LEVEL_EXPONENTIATION_BASE.pow(u8_level as u32); let (left, right, _) = self.last_result; @@ -679,7 +679,7 @@ fn flatten_query_tree(query_tree: &Operation) -> FlattenedQueryTree { Or(_, ops) => if ops.iter().all(|op| op.query().is_some()) { vec![vec![ops.iter().flat_map(|op| op.query()).cloned().collect()]] } else { - ops.into_iter().map(recurse).flatten().collect() + ops.iter().map(recurse).flatten().collect() }, Operation::Query(query) => vec![vec![vec![query.clone()]]], } diff --git a/milli/src/search/criteria/final.rs b/milli/src/search/criteria/final.rs index 0dbf3ee1a..e2fb81aaf 100644 --- a/milli/src/search/criteria/final.rs +++ b/milli/src/search/criteria/final.rs @@ -30,30 +30,28 @@ impl<'t> Final<'t> { #[logging_timer::time("Final::{}")] pub fn next(&mut self, excluded_candidates: &RoaringBitmap) -> anyhow::Result> { - loop { - debug!("Final iteration"); - let mut criterion_parameters = CriterionParameters { - wdcache: &mut self.wdcache, - // returned_candidates is merged with excluded_candidates to avoid duplicas - excluded_candidates: &(&self.returned_candidates | excluded_candidates), - }; + debug!("Final iteration"); + let mut criterion_parameters = CriterionParameters { + wdcache: &mut self.wdcache, + // returned_candidates is merged with excluded_candidates to avoid duplicas + excluded_candidates: &(&self.returned_candidates | excluded_candidates), + }; - match self.parent.next(&mut criterion_parameters)? { - Some(CriterionResult { query_tree, candidates, bucket_candidates }) => { - let candidates = match (candidates, query_tree.as_ref()) { - (Some(candidates), _) => candidates, - (None, Some(qt)) => resolve_query_tree(self.ctx, qt, &mut self.wdcache)?, - (None, None) => self.ctx.documents_ids()?, - }; + match self.parent.next(&mut criterion_parameters)? { + Some(CriterionResult { query_tree, candidates, bucket_candidates }) => { + let candidates = match (candidates, query_tree.as_ref()) { + (Some(candidates), _) => candidates, + (None, Some(qt)) => resolve_query_tree(self.ctx, qt, &mut self.wdcache)?, + (None, None) => self.ctx.documents_ids()?, + }; - let bucket_candidates = bucket_candidates.unwrap_or_else(|| candidates.clone()); + let bucket_candidates = bucket_candidates.unwrap_or_else(|| candidates.clone()); - self.returned_candidates |= &candidates; + self.returned_candidates |= &candidates; - return Ok(Some(FinalResult { query_tree, candidates, bucket_candidates })); - }, - None => return Ok(None), - } + return Ok(Some(FinalResult { query_tree, candidates, bucket_candidates })); + }, + None => return Ok(None), } } } diff --git a/milli/src/search/criteria/typo.rs b/milli/src/search/criteria/typo.rs index 288a92f65..059d52e48 100644 --- a/milli/src/search/criteria/typo.rs +++ b/milli/src/search/criteria/typo.rs @@ -70,22 +70,24 @@ impl<'t> Criterion for Typo<'t> { }, Some((_, query_tree, candidates_authorization)) => { let fst = self.ctx.words_fst(); - let new_query_tree = if self.typos < MAX_TYPOS_PER_WORD { - alterate_query_tree(&fst, query_tree.clone(), self.typos, params.wdcache)? - } else if self.typos == MAX_TYPOS_PER_WORD { - // When typos >= MAX_TYPOS_PER_WORD, no more alteration of the query tree is possible, - // we keep the altered query tree - *query_tree = alterate_query_tree(&fst, query_tree.clone(), self.typos, params.wdcache)?; - // we compute the allowed candidates - let query_tree_allowed_candidates = resolve_query_tree(self.ctx, query_tree, params.wdcache)?; - // we assign the allowed candidates to the candidates authorization. - *candidates_authorization = match take(candidates_authorization) { - Allowed(allowed_candidates) => Allowed(query_tree_allowed_candidates & allowed_candidates), - Forbidden(forbidden_candidates) => Allowed(query_tree_allowed_candidates - forbidden_candidates), - }; - query_tree.clone() - } else { - query_tree.clone() + let new_query_tree = match self.typos { + typos if typos < MAX_TYPOS_PER_WORD => { + alterate_query_tree(&fst, query_tree.clone(), self.typos, params.wdcache)? + }, + MAX_TYPOS_PER_WORD => { + // When typos >= MAX_TYPOS_PER_WORD, no more alteration of the query tree is possible, + // we keep the altered query tree + *query_tree = alterate_query_tree(&fst, query_tree.clone(), self.typos, params.wdcache)?; + // we compute the allowed candidates + let query_tree_allowed_candidates = resolve_query_tree(self.ctx, query_tree, params.wdcache)?; + // we assign the allowed candidates to the candidates authorization. + *candidates_authorization = match take(candidates_authorization) { + Allowed(allowed_candidates) => Allowed(query_tree_allowed_candidates & allowed_candidates), + Forbidden(forbidden_candidates) => Allowed(query_tree_allowed_candidates - forbidden_candidates), + }; + query_tree.clone() + }, + _otherwise => query_tree.clone(), }; let mut candidates = resolve_candidates( @@ -187,7 +189,7 @@ fn alterate_query_tree( } else { let typo = *typo.min(&number_typos); let words = word_derivations(word, q.prefix, typo, words_fst, wdcache)?; - let queries = words.into_iter().map(|(word, typo)| { + let queries = words.iter().map(|(word, typo)| { Operation::Query(Query { prefix: false, kind: QueryKind::Exact { original_typo: *typo, word: word.to_string() }, diff --git a/milli/src/search/query_tree.rs b/milli/src/search/query_tree.rs index b74b8af58..4876e37c8 100644 --- a/milli/src/search/query_tree.rs +++ b/milli/src/search/query_tree.rs @@ -241,7 +241,7 @@ impl<'a> QueryTreeBuilder<'a> { } /// Split the word depending on the frequency of subwords in the database documents. -fn split_best_frequency<'a>(ctx: &impl Context, word: &'a str) -> heed::Result> { +fn split_best_frequency(ctx: &impl Context, word: &str) -> heed::Result> { let chars = word.char_indices().skip(1); let mut best = None; @@ -438,14 +438,14 @@ fn create_query_tree( let start = number_phrases + (number_phrases == 0) as usize; for len in start..=query.len() { let mut word_count = len - number_phrases; - let query: Vec<_> = query.iter().filter_map(|p| { + let query: Vec<_> = query.iter().filter(|p| { if p.is_phrase() { - Some(p) + true } else if word_count != 0 { word_count -= 1; - Some(p) + true } else { - None + false } }) .cloned()