2019-12-12 00:02:10 +08:00
|
|
|
use std::cmp::{self, Ordering};
|
|
|
|
use slice_group_by::GroupBy;
|
2019-12-12 18:33:39 +08:00
|
|
|
use crate::bucket_sort::{SimpleMatch};
|
2019-12-13 18:14:12 +08:00
|
|
|
use crate::{RawDocument, MResult};
|
2019-12-13 19:38:54 +08:00
|
|
|
use super::{Criterion, Context, ContextMut, prepare_bare_matches};
|
2019-12-12 00:02:10 +08:00
|
|
|
|
2019-12-12 18:33:39 +08:00
|
|
|
const MAX_DISTANCE: u16 = 8;
|
2019-12-12 00:02:10 +08:00
|
|
|
|
|
|
|
pub struct Proximity;
|
|
|
|
|
|
|
|
impl Criterion for Proximity {
|
|
|
|
fn name(&self) -> &str { "proximity" }
|
|
|
|
|
2020-01-13 21:36:06 +08:00
|
|
|
fn prepare<'h, 'p, 'tag, 'txn, 'q, 'r>(
|
2019-12-12 00:02:10 +08:00
|
|
|
&self,
|
2020-01-13 21:36:06 +08:00
|
|
|
ctx: ContextMut<'h, 'p, 'tag, 'txn, 'q>,
|
2019-12-12 18:33:39 +08:00
|
|
|
documents: &mut [RawDocument<'r, 'tag>],
|
2019-12-13 18:14:12 +08:00
|
|
|
) -> MResult<()>
|
|
|
|
{
|
2020-01-13 21:36:06 +08:00
|
|
|
prepare_bare_matches(documents, ctx.postings_lists, ctx.query_mapping);
|
2019-12-13 18:14:12 +08:00
|
|
|
Ok(())
|
2019-12-12 00:02:10 +08:00
|
|
|
}
|
|
|
|
|
2019-12-12 18:33:39 +08:00
|
|
|
fn evaluate(&self, _ctx: &Context, lhs: &RawDocument, rhs: &RawDocument) -> Ordering {
|
2019-12-12 00:02:10 +08:00
|
|
|
fn index_proximity(lhs: u16, rhs: u16) -> u16 {
|
|
|
|
if lhs < rhs {
|
|
|
|
cmp::min(rhs - lhs, MAX_DISTANCE)
|
|
|
|
} else {
|
|
|
|
cmp::min(lhs - rhs, MAX_DISTANCE) + 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn attribute_proximity(lhs: SimpleMatch, rhs: SimpleMatch) -> u16 {
|
|
|
|
if lhs.attribute != rhs.attribute { MAX_DISTANCE }
|
|
|
|
else { index_proximity(lhs.word_index, rhs.word_index) }
|
|
|
|
}
|
|
|
|
|
|
|
|
fn min_proximity(lhs: &[SimpleMatch], rhs: &[SimpleMatch]) -> u16 {
|
|
|
|
let mut min_prox = u16::max_value();
|
|
|
|
for a in lhs {
|
|
|
|
for b in rhs {
|
|
|
|
let prox = attribute_proximity(*a, *b);
|
|
|
|
min_prox = cmp::min(min_prox, prox);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
min_prox
|
|
|
|
}
|
|
|
|
|
|
|
|
fn matches_proximity(matches: &[SimpleMatch],) -> u16 {
|
|
|
|
let mut proximity = 0;
|
|
|
|
let mut iter = matches.linear_group_by_key(|m| m.query_index);
|
|
|
|
|
|
|
|
// iterate over groups by windows of size 2
|
|
|
|
let mut last = iter.next();
|
|
|
|
while let (Some(lhs), Some(rhs)) = (last, iter.next()) {
|
|
|
|
proximity += min_proximity(lhs, rhs);
|
|
|
|
last = Some(rhs);
|
|
|
|
}
|
|
|
|
|
|
|
|
proximity
|
|
|
|
}
|
|
|
|
|
|
|
|
let lhs = matches_proximity(&lhs.processed_matches);
|
|
|
|
let rhs = matches_proximity(&rhs.processed_matches);
|
|
|
|
|
|
|
|
lhs.cmp(&rhs)
|
|
|
|
}
|
|
|
|
}
|