mirror of
https://github.com/quickwit-oss/tantivy.git
synced 2026-01-04 16:22:55 +00:00
Compare commits
3 Commits
githubacti
...
perf/exper
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7a98b11d7 | ||
|
|
a18932165f | ||
|
|
8f82d0b773 |
@@ -142,6 +142,11 @@ impl<TDocSet: DocSet + ?Sized> DocSet for Box<TDocSet> {
|
|||||||
unboxed.size_hint()
|
unboxed.size_hint()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn append_to_bitset(&mut self, bitset: &mut BitSet) {
|
||||||
|
let unboxed: &mut TDocSet = self.borrow_mut();
|
||||||
|
unboxed.append_to_bitset(bitset);
|
||||||
|
}
|
||||||
|
|
||||||
fn count(&mut self, delete_bitset: &DeleteBitSet) -> u32 {
|
fn count(&mut self, delete_bitset: &DeleteBitSet) -> u32 {
|
||||||
let unboxed: &mut TDocSet = self.borrow_mut();
|
let unboxed: &mut TDocSet = self.borrow_mut();
|
||||||
unboxed.count(delete_bitset)
|
unboxed.count(delete_bitset)
|
||||||
@@ -151,9 +156,4 @@ impl<TDocSet: DocSet + ?Sized> DocSet for Box<TDocSet> {
|
|||||||
let unboxed: &mut TDocSet = self.borrow_mut();
|
let unboxed: &mut TDocSet = self.borrow_mut();
|
||||||
unboxed.count_including_deleted()
|
unboxed.count_including_deleted()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn append_to_bitset(&mut self, bitset: &mut BitSet) {
|
|
||||||
let unboxed: &mut TDocSet = self.borrow_mut();
|
|
||||||
unboxed.append_to_bitset(bitset);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -214,6 +214,102 @@ impl<TDocSet: DocSet, TOtherDocSet: DocSet> DocSet for Intersection<TDocSet, TOt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// `ahead` is assumed to be initialized (ahead.advance() has been called at least once,
|
||||||
|
// and this returned true).
|
||||||
|
//
|
||||||
|
// If behind is either uninitialized or `ahead.doc() > behind.doc()`.
|
||||||
|
fn next_in_intersection<'a, TScorer: Scorer>(
|
||||||
|
ahead: &'a mut TScorer,
|
||||||
|
behind: &'a mut TScorer,
|
||||||
|
) -> Option<DocId> {
|
||||||
|
let candidate = ahead.doc();
|
||||||
|
match behind.skip_next(candidate) {
|
||||||
|
SkipResult::Reached => Some(candidate),
|
||||||
|
SkipResult::OverStep => {
|
||||||
|
// yeah for tail-recursion
|
||||||
|
next_in_intersection(behind, ahead)
|
||||||
|
}
|
||||||
|
SkipResult::End => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SkipResultComplex {
|
||||||
|
Reached,
|
||||||
|
Overstep { other_ord: usize, candidate: DocId },
|
||||||
|
End,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn skip_several_scorers<TDocSet: DocSet>(
|
||||||
|
others: &mut [TDocSet],
|
||||||
|
except_candidate_ord: usize,
|
||||||
|
target: DocId,
|
||||||
|
) -> SkipResultComplex {
|
||||||
|
for (ord, docset) in others.iter_mut().enumerate() {
|
||||||
|
// `candidate_ord` is already at the
|
||||||
|
// right position.
|
||||||
|
//
|
||||||
|
// Calling `skip_next` would advance this docset
|
||||||
|
// and miss it.
|
||||||
|
if ord == except_candidate_ord {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
match docset.skip_next(target) {
|
||||||
|
SkipResult::Reached => {}
|
||||||
|
SkipResult::OverStep => {
|
||||||
|
return SkipResultComplex::Overstep {
|
||||||
|
other_ord: ord,
|
||||||
|
candidate: docset.doc(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
SkipResult::End => {
|
||||||
|
return SkipResultComplex::End;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SkipResultComplex::Reached
|
||||||
|
}
|
||||||
|
|
||||||
|
fn for_each<'a, TScorer: Scorer, TOtherscorer: Scorer>(
|
||||||
|
left: &'a mut TScorer,
|
||||||
|
right: &'a mut TScorer,
|
||||||
|
others: &'a mut [TOtherscorer],
|
||||||
|
callback: &mut FnMut(DocId, Score),
|
||||||
|
) {
|
||||||
|
let mut other_candidate_ord: usize = usize::max_value();
|
||||||
|
if !left.advance() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while let Some(candidate) = next_in_intersection(left, right) {
|
||||||
|
// test the remaining scorers
|
||||||
|
match skip_several_scorers(others, other_candidate_ord, candidate) {
|
||||||
|
SkipResultComplex::Reached => {
|
||||||
|
let intersection_score: Score = left.score()
|
||||||
|
+ right.score()
|
||||||
|
+ others.iter_mut().map(|other| other.score()).sum::<Score>();
|
||||||
|
callback(candidate, intersection_score);
|
||||||
|
if !left.advance() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SkipResultComplex::Overstep {
|
||||||
|
other_ord,
|
||||||
|
candidate,
|
||||||
|
} => match left.skip_next(candidate) {
|
||||||
|
SkipResult::End => {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SkipResult::Reached => {
|
||||||
|
other_candidate_ord = other_ord;
|
||||||
|
}
|
||||||
|
SkipResult::OverStep => other_candidate_ord = usize::max_value(),
|
||||||
|
},
|
||||||
|
SkipResultComplex::End => {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<TScorer, TOtherScorer> Scorer for Intersection<TScorer, TOtherScorer>
|
impl<TScorer, TOtherScorer> Scorer for Intersection<TScorer, TOtherScorer>
|
||||||
where
|
where
|
||||||
TScorer: Scorer,
|
TScorer: Scorer,
|
||||||
@@ -224,6 +320,10 @@ where
|
|||||||
+ self.right.score()
|
+ self.right.score()
|
||||||
+ self.others.iter_mut().map(Scorer::score).sum::<Score>()
|
+ self.others.iter_mut().map(Scorer::score).sum::<Score>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn for_each(&mut self, callback: &mut FnMut(DocId, Score)) {
|
||||||
|
for_each(&mut self.left, &mut self.right, &mut self.others, callback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ pub trait Scorer: downcast_rs::Downcast + DocSet + 'static {
|
|||||||
|
|
||||||
/// Iterates through all of the document matched by the DocSet
|
/// Iterates through all of the document matched by the DocSet
|
||||||
/// `DocSet` and push the scored documents to the collector.
|
/// `DocSet` and push the scored documents to the collector.
|
||||||
|
///
|
||||||
|
/// This method assumes that the Scorer is brand new, and `.advance()`
|
||||||
|
/// and `.skip()` haven't been called yet.
|
||||||
fn for_each(&mut self, callback: &mut FnMut(DocId, Score)) {
|
fn for_each(&mut self, callback: &mut FnMut(DocId, Score)) {
|
||||||
while self.advance() {
|
while self.advance() {
|
||||||
callback(self.doc(), self.score());
|
callback(self.doc(), self.score());
|
||||||
|
|||||||
@@ -260,6 +260,23 @@ where
|
|||||||
fn score(&mut self) -> Score {
|
fn score(&mut self) -> Score {
|
||||||
self.score
|
self.score
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn for_each(&mut self, callback: &mut FnMut(DocId, Score)) {
|
||||||
|
// TODO how do we deal with the fact that people may have called .advance() before.
|
||||||
|
while self.refill() {
|
||||||
|
let offset = self.offset;
|
||||||
|
for cursor in 0..HORIZON_NUM_TINYBITSETS {
|
||||||
|
while let Some(val) = self.bitsets[cursor].pop_lowest() {
|
||||||
|
let delta = val + (cursor as u32) * 64;
|
||||||
|
let doc = offset + delta;
|
||||||
|
let score_combiner = &mut self.scores[delta as usize];
|
||||||
|
let score = score_combiner.score();
|
||||||
|
callback(doc, score);
|
||||||
|
score_combiner.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
Reference in New Issue
Block a user