mirror of
https://github.com/quickwit-oss/tantivy.git
synced 2025-12-28 04:52:55 +00:00
Compare commits
1 Commits
bugfix-pos
...
issue/396
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4cbcc59e8f |
96
src/query/fastfield_filter/fastfield_filter_query.rs
Normal file
96
src/query/fastfield_filter/fastfield_filter_query.rs
Normal file
@@ -0,0 +1,96 @@
|
||||
use super::FastFieldFilterWeight;
|
||||
use query::Query;
|
||||
use query::Weight;
|
||||
use Result;
|
||||
use Searcher;
|
||||
use schema::Field;
|
||||
use super::RangeU64;
|
||||
use std::collections::Bound;
|
||||
use common::i64_to_u64;
|
||||
use schema::Schema;
|
||||
use schema::FieldEntry;
|
||||
use TantivyError;
|
||||
use schema::Type;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
enum TypeInt {
|
||||
U64, I64
|
||||
}
|
||||
|
||||
impl TypeInt {
|
||||
fn value_type(self) -> Type {
|
||||
match self {
|
||||
TypeInt::I64 => Type::I64,
|
||||
TypeInt::U64 => Type::U64
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//< TODO i64 range Debug string will not look good in the
|
||||
// current implementation. Defer conversion to the scorer, or
|
||||
// back convert values for Debug.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FastFieldFilterQuery {
|
||||
field: Field,
|
||||
range: RangeU64,
|
||||
int_type: TypeInt, //< just here to check the schema at runtime, as we call `.weight`
|
||||
}
|
||||
|
||||
fn convert_bound_to_u64(bound: Bound<i64>) -> Bound<u64> {
|
||||
match bound {
|
||||
Bound::Included(val) =>
|
||||
Bound::Excluded(i64_to_u64(val)),
|
||||
Bound::Excluded(val) =>
|
||||
Bound::Excluded(i64_to_u64(val)),
|
||||
Bound::Unbounded => Bound::Unbounded
|
||||
}
|
||||
}
|
||||
|
||||
impl FastFieldFilterQuery {
|
||||
|
||||
pub fn new_u64(field: Field, low: Bound<u64>, high: Bound<u64>) -> FastFieldFilterQuery {
|
||||
FastFieldFilterQuery {
|
||||
field: field,
|
||||
range: RangeU64 { low, high },
|
||||
int_type: TypeInt::U64
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_i64(field: Field, low: Bound<i64>, high: Bound<i64>) -> FastFieldFilterQuery {
|
||||
FastFieldFilterQuery {
|
||||
field: field,
|
||||
range: RangeU64 {
|
||||
low: convert_bound_to_u64(low),
|
||||
high: convert_bound_to_u64(high)
|
||||
},
|
||||
int_type: TypeInt::I64
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn validate_schema(&self, schema: &Schema) -> Result<()> {
|
||||
let field_entry: &FieldEntry = schema.get_field_entry(self.field);
|
||||
if !field_entry.is_int_fast() {
|
||||
return Err(TantivyError::SchemaError(format!(
|
||||
"Field {:?} is not an int fast field",
|
||||
field_entry.name()
|
||||
)));
|
||||
}
|
||||
let expected_value_type = self.int_type.value_type();
|
||||
if field_entry.field_type().value_type() != self.int_type.value_type() {
|
||||
return Err(TantivyError::SchemaError(format!(
|
||||
"Field {:?} is not a {:?}",
|
||||
field_entry.name(),
|
||||
expected_value_type
|
||||
)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Query for FastFieldFilterQuery {
|
||||
fn weight(&self, searcher: &Searcher, _scoring_enabled: bool) -> Result<Box<Weight>> {
|
||||
self.validate_schema(searcher.schema())?;
|
||||
Ok(Box::new(FastFieldFilterWeight::new(self.field, self.range.clone())))
|
||||
}
|
||||
}
|
||||
58
src/query/fastfield_filter/fastfield_filter_scorer.rs
Normal file
58
src/query/fastfield_filter/fastfield_filter_scorer.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
use query::Scorer;
|
||||
use fastfield::FastFieldReader;
|
||||
use DocId;
|
||||
use DocSet;
|
||||
use query::fastfield_filter::RangeU64;
|
||||
|
||||
pub(crate) struct FastFieldFilterScorer {
|
||||
fastfield_reader: FastFieldReader<u64>,
|
||||
range: RangeU64,
|
||||
max_doc: DocId,
|
||||
doc: DocId,
|
||||
}
|
||||
|
||||
impl FastFieldFilterScorer {
|
||||
pub fn new(fastfield_reader: FastFieldReader<u64>,
|
||||
range: RangeU64,
|
||||
max_doc: DocId) -> FastFieldFilterScorer {
|
||||
FastFieldFilterScorer {
|
||||
fastfield_reader,
|
||||
range,
|
||||
max_doc,
|
||||
doc: 0u32,
|
||||
}
|
||||
}
|
||||
|
||||
fn within_range(&self, doc: DocId) -> bool {
|
||||
let val = self.fastfield_reader.get(doc);
|
||||
self.range.contains(val)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl DocSet for FastFieldFilterScorer {
|
||||
fn advance(&mut self) -> bool {
|
||||
for doc in (self.doc + 1)..self.max_doc {
|
||||
if self.within_range(doc) {
|
||||
self.doc = doc;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
self.doc = self.max_doc;
|
||||
return false;
|
||||
}
|
||||
|
||||
fn doc(&self) -> u32 {
|
||||
self.doc
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> u32 {
|
||||
self.max_doc
|
||||
}
|
||||
}
|
||||
|
||||
impl Scorer for FastFieldFilterScorer {
|
||||
fn score(&mut self) -> f32 {
|
||||
1f32
|
||||
}
|
||||
}
|
||||
29
src/query/fastfield_filter/fastfield_filter_weight.rs
Normal file
29
src/query/fastfield_filter/fastfield_filter_weight.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
use query::Weight;
|
||||
use schema::Field;
|
||||
use query::fastfield_filter::RangeU64;
|
||||
use query::fastfield_filter::FastFieldFilterScorer;
|
||||
use SegmentReader;
|
||||
use query::Scorer;
|
||||
use TantivyError;
|
||||
use fastfield::FastFieldReader;
|
||||
|
||||
pub struct FastFieldFilterWeight {
|
||||
field: Field,
|
||||
range: RangeU64,
|
||||
}
|
||||
|
||||
impl FastFieldFilterWeight {
|
||||
pub(crate) fn new(field: Field, range: RangeU64) -> FastFieldFilterWeight {
|
||||
FastFieldFilterWeight {
|
||||
field,
|
||||
range
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Weight for FastFieldFilterWeight {
|
||||
fn scorer(&self, reader: &SegmentReader) -> Result<Box<Scorer>, TantivyError> {
|
||||
let fastfield_reader: FastFieldReader<u64> = reader.fast_field_reader(self.field )?;
|
||||
Ok(Box::new(FastFieldFilterScorer::new(fastfield_reader, self.range.clone(), reader.max_doc())))
|
||||
}
|
||||
}
|
||||
47
src/query/fastfield_filter/mod.rs
Normal file
47
src/query/fastfield_filter/mod.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
use std::collections::Bound;
|
||||
|
||||
mod fastfield_filter_query;
|
||||
mod fastfield_filter_weight;
|
||||
mod fastfield_filter_scorer;
|
||||
|
||||
|
||||
pub use self::fastfield_filter_query::FastFieldFilterQuery;
|
||||
use self::fastfield_filter_weight::FastFieldFilterWeight;
|
||||
use self::fastfield_filter_scorer::FastFieldFilterScorer;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct RangeU64 {
|
||||
pub low: Bound<u64>,
|
||||
pub high: Bound<u64>,
|
||||
}
|
||||
|
||||
|
||||
impl RangeU64 {
|
||||
|
||||
fn match_high(&self, val: u64) -> bool {
|
||||
match self.high {
|
||||
Bound::Excluded(bound) =>
|
||||
val < bound,
|
||||
Bound::Included(bound) =>
|
||||
val <= bound,
|
||||
Bound::Unbounded =>
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fn match_low(&self, val: u64) -> bool {
|
||||
match self.high {
|
||||
Bound::Excluded(bound) =>
|
||||
bound < val,
|
||||
Bound::Included(bound) =>
|
||||
bound <= val,
|
||||
Bound::Unbounded =>
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contains(&self, val: u64) -> bool {
|
||||
self.match_low(val) && self.match_high(val)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,6 +22,7 @@ mod scorer;
|
||||
mod term_query;
|
||||
mod union;
|
||||
mod weight;
|
||||
mod fastfield_filter;
|
||||
|
||||
#[cfg(test)]
|
||||
mod vec_docset;
|
||||
@@ -54,3 +55,4 @@ pub use self::scorer::ConstScorer;
|
||||
pub use self::scorer::Scorer;
|
||||
pub use self::term_query::TermQuery;
|
||||
pub use self::weight::Weight;
|
||||
pub use self::fastfield_filter::FastFieldFilterQuery;
|
||||
Reference in New Issue
Block a user