Introduce the Attribute criterion

This commit is contained in:
Kerollmops 2021-03-11 11:48:55 +01:00 committed by many
parent 3bcc1c0560
commit 0f4c0beffd
No known key found for this signature in database
GPG Key ID: 2CEF23B75189EACA
4 changed files with 145 additions and 0 deletions

7
Cargo.lock generated
View File

@ -122,6 +122,12 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]]
name = "big_s"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "199edb7b90631283b10c2422e6a0bc8b7d987bf732995ba1de53b576c97e51a8"
[[package]] [[package]]
name = "bincode" name = "bincode"
version = "1.3.1" version = "1.3.1"
@ -1251,6 +1257,7 @@ name = "milli"
version = "0.1.1" version = "0.1.1"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"big_s",
"bstr", "bstr",
"byteorder", "byteorder",
"chrono", "chrono",

View File

@ -52,6 +52,7 @@ logging_timer = "1.0.0"
tinytemplate = "=1.1.0" tinytemplate = "=1.1.0"
[dev-dependencies] [dev-dependencies]
big_s = "1.0.2"
criterion = "0.3.4" criterion = "0.3.4"
maplit = "1.0.2" maplit = "1.0.2"
rand = "0.8.3" rand = "0.8.3"

View File

@ -0,0 +1,133 @@
use log::debug;
use roaring::RoaringBitmap;
use crate::search::criteria::Query;
use crate::search::query_tree::Operation;
use crate::search::WordDerivationsCache;
use super::{Criterion, CriterionResult, Context};
pub struct Attribute<'t> {
ctx: &'t dyn Context,
query_tree: Option<Operation>,
candidates: Option<RoaringBitmap>,
bucket_candidates: RoaringBitmap,
parent: Option<Box<dyn Criterion + 't>>,
}
impl<'t> Attribute<'t> {
pub fn initial(
ctx: &'t dyn Context,
query_tree: Option<Operation>,
candidates: Option<RoaringBitmap>,
) -> Self
{
Attribute {
ctx,
query_tree,
candidates,
bucket_candidates: RoaringBitmap::new(),
parent: None,
}
}
pub fn new(ctx: &'t dyn Context, parent: Box<dyn Criterion + 't>) -> Self {
Attribute {
ctx,
query_tree: None,
candidates: None,
bucket_candidates: RoaringBitmap::new(),
parent: Some(parent),
}
}
}
impl<'t> Criterion for Attribute<'t> {
#[logging_timer::time("Attribute::{}")]
fn next(&mut self, wdcache: &mut WordDerivationsCache) -> anyhow::Result<Option<CriterionResult>> {
todo!("Attribute")
}
}
// TODO can we keep refs of Query
fn explode_query_tree(query_tree: &Operation) -> Vec<Vec<Query>> {
use crate::search::criteria::Operation::{And, Or, Consecutive};
fn and_recurse(head: &Operation, tail: &[Operation]) -> Vec<Vec<Query>> {
match tail.split_first() {
Some((thead, tail)) => {
let tail = and_recurse(thead, tail);
let mut out = Vec::new();
for array in recurse(head) {
for tail_array in &tail {
let mut array = array.clone();
array.extend(tail_array.iter().cloned());
out.push(array);
}
}
out
},
None => recurse(head),
}
}
fn recurse(op: &Operation) -> Vec<Vec<Query>> {
match op {
And(ops) | Consecutive(ops) => {
ops.split_first().map_or_else(Vec::new, |(h, t)| and_recurse(h, t))
},
Or(_, ops) => ops.into_iter().map(recurse).flatten().collect(),
Operation::Query(query) => vec![vec![query.clone()]],
}
}
recurse(query_tree)
}
#[cfg(test)]
mod tests {
use big_s::S;
use crate::search::criteria::QueryKind;
use super::*;
#[test]
fn simple_explode_query_tree() {
let query_tree = Operation::Or(false, vec![
Operation::Query(Query { prefix: false, kind: QueryKind::exact(S("manythefish")) }),
Operation::And(vec![
Operation::Query(Query { prefix: false, kind: QueryKind::exact(S("manythe")) }),
Operation::Query(Query { prefix: false, kind: QueryKind::exact(S("fish")) }),
]),
Operation::And(vec![
Operation::Query(Query { prefix: false, kind: QueryKind::exact(S("many")) }),
Operation::Or(false, vec![
Operation::Query(Query { prefix: false, kind: QueryKind::exact(S("thefish")) }),
Operation::And(vec![
Operation::Query(Query { prefix: false, kind: QueryKind::exact(S("the")) }),
Operation::Query(Query { prefix: false, kind: QueryKind::exact(S("fish")) }),
]),
]),
]),
]);
let expected = vec![
vec![Query { prefix: false, kind: QueryKind::exact(S("manythefish")) }],
vec![
Query { prefix: false, kind: QueryKind::exact(S("manythe")) },
Query { prefix: false, kind: QueryKind::exact(S("fish")) },
],
vec![
Query { prefix: false, kind: QueryKind::exact(S("many")) },
Query { prefix: false, kind: QueryKind::exact(S("thefish")) },
],
vec![
Query { prefix: false, kind: QueryKind::exact(S("many")) },
Query { prefix: false, kind: QueryKind::exact(S("the")) },
Query { prefix: false, kind: QueryKind::exact(S("fish")) },
],
];
let result = explode_query_tree(&query_tree);
assert_eq!(expected, result);
}
}

View File

@ -12,12 +12,14 @@ use self::typo::Typo;
use self::words::Words; use self::words::Words;
use self::asc_desc::AscDesc; use self::asc_desc::AscDesc;
use self::proximity::Proximity; use self::proximity::Proximity;
use self::attribute::Attribute;
use self::fetcher::Fetcher; use self::fetcher::Fetcher;
mod typo; mod typo;
mod words; mod words;
mod asc_desc; mod asc_desc;
mod proximity; mod proximity;
mod attribute;
pub mod fetcher; pub mod fetcher;
pub trait Criterion { pub trait Criterion {
@ -139,6 +141,7 @@ impl<'t> CriteriaBuilder<'t> {
Name::Typo => Box::new(Typo::new(self, father)), Name::Typo => Box::new(Typo::new(self, father)),
Name::Words => Box::new(Words::new(self, father)), Name::Words => Box::new(Words::new(self, father)),
Name::Proximity => Box::new(Proximity::new(self, father)), Name::Proximity => Box::new(Proximity::new(self, father)),
Name::Attribute => Box::new(Attribute::new(self, father)),
Name::Asc(field) => Box::new(AscDesc::asc(&self.index, &self.rtxn, father, field)?), Name::Asc(field) => Box::new(AscDesc::asc(&self.index, &self.rtxn, father, field)?),
Name::Desc(field) => Box::new(AscDesc::desc(&self.index, &self.rtxn, father, field)?), Name::Desc(field) => Box::new(AscDesc::desc(&self.index, &self.rtxn, father, field)?),
_otherwise => father, _otherwise => father,
@ -147,6 +150,7 @@ impl<'t> CriteriaBuilder<'t> {
Name::Typo => Box::new(Typo::initial(self, query_tree.take(), facet_candidates.take())), Name::Typo => Box::new(Typo::initial(self, query_tree.take(), facet_candidates.take())),
Name::Words => Box::new(Words::initial(self, query_tree.take(), facet_candidates.take())), Name::Words => Box::new(Words::initial(self, query_tree.take(), facet_candidates.take())),
Name::Proximity => Box::new(Proximity::initial(self, query_tree.take(), facet_candidates.take())), Name::Proximity => Box::new(Proximity::initial(self, query_tree.take(), facet_candidates.take())),
Name::Attribute => Box::new(Attribute::initial(self, query_tree.take(), facet_candidates.take())),
Name::Asc(field) => { Name::Asc(field) => {
Box::new(AscDesc::initial_asc(&self.index, &self.rtxn, query_tree.take(), facet_candidates.take(), field)?) Box::new(AscDesc::initial_asc(&self.index, &self.rtxn, query_tree.take(), facet_candidates.take(), field)?)
}, },