mirror of
https://github.com/quickwit-oss/tantivy.git
synced 2026-01-06 01:02:55 +00:00
Compare commits
12 Commits
refact-cod
...
col-trait-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
242f554cc6 | ||
|
|
ae7b72ad6f | ||
|
|
b977f763d7 | ||
|
|
5d436759b0 | ||
|
|
6f563b1606 | ||
|
|
095fb68fda | ||
|
|
6316eaefc6 | ||
|
|
5331be800b | ||
|
|
c73b425bc1 | ||
|
|
54cfd0d154 | ||
|
|
0dd62169c8 | ||
|
|
3984cafccc |
@@ -7,10 +7,11 @@
|
|||||||
// Of course, you can have a look at the tantivy's built-in collectors
|
// Of course, you can have a look at the tantivy's built-in collectors
|
||||||
// such as the `CountCollector` for more examples.
|
// such as the `CountCollector` for more examples.
|
||||||
|
|
||||||
|
use fastfield_codecs::Column;
|
||||||
// ---
|
// ---
|
||||||
// Importing tantivy...
|
// Importing tantivy...
|
||||||
use tantivy::collector::{Collector, SegmentCollector};
|
use tantivy::collector::{Collector, SegmentCollector};
|
||||||
use tantivy::fastfield::{DynamicFastFieldReader, FastFieldReader};
|
use tantivy::fastfield::DynamicFastFieldReader;
|
||||||
use tantivy::query::QueryParser;
|
use tantivy::query::QueryParser;
|
||||||
use tantivy::schema::{Field, Schema, FAST, INDEXED, TEXT};
|
use tantivy::schema::{Field, Schema, FAST, INDEXED, TEXT};
|
||||||
use tantivy::{doc, Index, Score, SegmentReader};
|
use tantivy::{doc, Index, Score, SegmentReader};
|
||||||
@@ -103,7 +104,7 @@ impl SegmentCollector for StatsSegmentCollector {
|
|||||||
type Fruit = Option<Stats>;
|
type Fruit = Option<Stats>;
|
||||||
|
|
||||||
fn collect(&mut self, doc: u32, _score: Score) {
|
fn collect(&mut self, doc: u32, _score: Score) {
|
||||||
let value = self.fast_field_reader.get(doc) as f64;
|
let value = self.fast_field_reader.get_val(doc as u64) as f64;
|
||||||
self.stats.count += 1;
|
self.stats.count += 1;
|
||||||
self.stats.sum += value;
|
self.stats.sum += value;
|
||||||
self.stats.squared_sum += value * value;
|
self.stats.squared_sum += value * value;
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ use std::cmp::Reverse;
|
|||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::sync::{Arc, RwLock, Weak};
|
use std::sync::{Arc, RwLock, Weak};
|
||||||
|
|
||||||
|
use fastfield_codecs::Column;
|
||||||
use tantivy::collector::TopDocs;
|
use tantivy::collector::TopDocs;
|
||||||
use tantivy::fastfield::FastFieldReader;
|
|
||||||
use tantivy::query::QueryParser;
|
use tantivy::query::QueryParser;
|
||||||
use tantivy::schema::{Field, Schema, FAST, TEXT};
|
use tantivy::schema::{Field, Schema, FAST, TEXT};
|
||||||
use tantivy::{
|
use tantivy::{
|
||||||
@@ -52,7 +52,7 @@ impl Warmer for DynamicPriceColumn {
|
|||||||
let product_id_reader = segment.fast_fields().u64(self.field)?;
|
let product_id_reader = segment.fast_fields().u64(self.field)?;
|
||||||
let product_ids: Vec<ProductId> = segment
|
let product_ids: Vec<ProductId> = segment
|
||||||
.doc_ids_alive()
|
.doc_ids_alive()
|
||||||
.map(|doc| product_id_reader.get(doc))
|
.map(|doc| product_id_reader.get_val(doc as u64))
|
||||||
.collect();
|
.collect();
|
||||||
let mut prices_it = self.price_fetcher.fetch_prices(&product_ids).into_iter();
|
let mut prices_it = self.price_fetcher.fetch_prices(&product_ids).into_iter();
|
||||||
let mut price_vals: Vec<Price> = Vec::new();
|
let mut price_vals: Vec<Price> = Vec::new();
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use common::BinarySerializable;
|
|||||||
use ownedbytes::OwnedBytes;
|
use ownedbytes::OwnedBytes;
|
||||||
use tantivy_bitpacker::{compute_num_bits, BitPacker, BitUnpacker};
|
use tantivy_bitpacker::{compute_num_bits, BitPacker, BitUnpacker};
|
||||||
|
|
||||||
use crate::{FastFieldCodec, FastFieldCodecType, FastFieldDataAccess};
|
use crate::{Column, FastFieldCodec, FastFieldCodecType};
|
||||||
|
|
||||||
/// Depending on the field type, a different
|
/// Depending on the field type, a different
|
||||||
/// fast field is required.
|
/// fast field is required.
|
||||||
@@ -17,7 +17,7 @@ pub struct BitpackedReader {
|
|||||||
num_vals: u64,
|
num_vals: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FastFieldDataAccess for BitpackedReader {
|
impl Column for BitpackedReader {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_val(&self, doc: u64) -> u64 {
|
fn get_val(&self, doc: u64) -> u64 {
|
||||||
self.min_value_u64 + self.bit_unpacker.get(doc, &self.data)
|
self.min_value_u64 + self.bit_unpacker.get(doc, &self.data)
|
||||||
@@ -124,10 +124,7 @@ impl FastFieldCodec for BitpackedCodec {
|
|||||||
/// It requires a `min_value` and a `max_value` to compute
|
/// It requires a `min_value` and a `max_value` to compute
|
||||||
/// compute the minimum number of bits required to encode
|
/// compute the minimum number of bits required to encode
|
||||||
/// values.
|
/// values.
|
||||||
fn serialize(
|
fn serialize(write: &mut impl Write, fastfield_accessor: &dyn Column) -> io::Result<()> {
|
||||||
write: &mut impl Write,
|
|
||||||
fastfield_accessor: &dyn FastFieldDataAccess,
|
|
||||||
) -> io::Result<()> {
|
|
||||||
let mut serializer = BitpackedSerializerLegacy::open(
|
let mut serializer = BitpackedSerializerLegacy::open(
|
||||||
write,
|
write,
|
||||||
fastfield_accessor.min_value(),
|
fastfield_accessor.min_value(),
|
||||||
@@ -141,21 +138,19 @@ impl FastFieldCodec for BitpackedCodec {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn is_applicable(_fastfield_accessor: &impl FastFieldDataAccess) -> bool {
|
|
||||||
true
|
fn estimate(fastfield_accessor: &impl Column) -> Option<f32> {
|
||||||
}
|
|
||||||
fn estimate(fastfield_accessor: &impl FastFieldDataAccess) -> f32 {
|
|
||||||
let amplitude = fastfield_accessor.max_value() - fastfield_accessor.min_value();
|
let amplitude = fastfield_accessor.max_value() - fastfield_accessor.min_value();
|
||||||
let num_bits = compute_num_bits(amplitude);
|
let num_bits = compute_num_bits(amplitude);
|
||||||
let num_bits_uncompressed = 64;
|
let num_bits_uncompressed = 64;
|
||||||
num_bits as f32 / num_bits_uncompressed as f32
|
Some(num_bits as f32 / num_bits_uncompressed as f32)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::tests::get_codec_test_data_sets;
|
use crate::tests::get_codec_test_datasets;
|
||||||
|
|
||||||
fn create_and_validate(data: &[u64], name: &str) {
|
fn create_and_validate(data: &[u64], name: &str) {
|
||||||
crate::tests::create_and_validate::<BitpackedCodec>(data, name);
|
crate::tests::create_and_validate::<BitpackedCodec>(data, name);
|
||||||
@@ -163,7 +158,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_with_codec_data_sets() {
|
fn test_with_codec_data_sets() {
|
||||||
let data_sets = get_codec_test_data_sets();
|
let data_sets = get_codec_test_datasets();
|
||||||
for (mut data, name) in data_sets {
|
for (mut data, name) in data_sets {
|
||||||
create_and_validate(&data, name);
|
create_and_validate(&data, name);
|
||||||
data.reverse();
|
data.reverse();
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ use ownedbytes::OwnedBytes;
|
|||||||
use tantivy_bitpacker::{compute_num_bits, BitPacker, BitUnpacker};
|
use tantivy_bitpacker::{compute_num_bits, BitPacker, BitUnpacker};
|
||||||
|
|
||||||
use crate::linear::{get_calculated_value, get_slope};
|
use crate::linear::{get_calculated_value, get_slope};
|
||||||
use crate::{FastFieldCodec, FastFieldCodecType, FastFieldDataAccess};
|
use crate::{Column, FastFieldCodec, FastFieldCodecType};
|
||||||
|
|
||||||
const CHUNK_SIZE: u64 = 512;
|
const CHUNK_SIZE: u64 = 512;
|
||||||
|
|
||||||
@@ -146,7 +146,7 @@ fn get_interpolation_function(doc: u64, interpolations: &[Function]) -> &Functio
|
|||||||
&interpolations[get_interpolation_position(doc)]
|
&interpolations[get_interpolation_position(doc)]
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FastFieldDataAccess for BlockwiseLinearReader {
|
impl Column for BlockwiseLinearReader {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_val(&self, idx: u64) -> u64 {
|
fn get_val(&self, idx: u64) -> u64 {
|
||||||
let interpolation = get_interpolation_function(idx, &self.footer.interpolations);
|
let interpolation = get_interpolation_function(idx, &self.footer.interpolations);
|
||||||
@@ -195,10 +195,7 @@ impl FastFieldCodec for BlockwiseLinearCodec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new fast field serializer.
|
/// Creates a new fast field serializer.
|
||||||
fn serialize(
|
fn serialize(write: &mut impl Write, fastfield_accessor: &dyn Column) -> io::Result<()> {
|
||||||
write: &mut impl Write,
|
|
||||||
fastfield_accessor: &dyn FastFieldDataAccess,
|
|
||||||
) -> io::Result<()> {
|
|
||||||
assert!(fastfield_accessor.min_value() <= fastfield_accessor.max_value());
|
assert!(fastfield_accessor.min_value() <= fastfield_accessor.max_value());
|
||||||
|
|
||||||
let first_val = fastfield_accessor.get_val(0);
|
let first_val = fastfield_accessor.get_val(0);
|
||||||
@@ -289,29 +286,24 @@ impl FastFieldCodec for BlockwiseLinearCodec {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_applicable(fastfield_accessor: &impl FastFieldDataAccess) -> bool {
|
/// estimation for linear interpolation is hard because, you don't know
|
||||||
if fastfield_accessor.num_vals() < 5_000 {
|
/// where the local maxima are for the deviation of the calculated value and
|
||||||
return false;
|
/// the offset is also unknown.
|
||||||
|
fn estimate(fastfield_accessor: &impl Column) -> Option<f32> {
|
||||||
|
if fastfield_accessor.num_vals() < 10 * CHUNK_SIZE {
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// On serialization the offset is added to the actual value.
|
// On serialization the offset is added to the actual value.
|
||||||
// We need to make sure this won't run into overflow calculation issues.
|
// We need to make sure this won't run into overflow calculation issues.
|
||||||
// For this we take the maximum theroretical offset and add this to the max value.
|
// For this we take the maximum theroretical offset and add this to the max value.
|
||||||
// If this doesn't overflow the algorithm should be fine
|
// If this doesn't overflow the algorithm should be fine
|
||||||
let theorethical_maximum_offset =
|
let theorethical_maximum_offset =
|
||||||
fastfield_accessor.max_value() - fastfield_accessor.min_value();
|
fastfield_accessor.max_value() - fastfield_accessor.min_value();
|
||||||
if fastfield_accessor
|
fastfield_accessor
|
||||||
.max_value()
|
.max_value()
|
||||||
.checked_add(theorethical_maximum_offset)
|
.checked_add(theorethical_maximum_offset)?;
|
||||||
.is_none()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
/// estimation for linear interpolation is hard because, you don't know
|
|
||||||
/// where the local maxima are for the deviation of the calculated value and
|
|
||||||
/// the offset is also unknown.
|
|
||||||
fn estimate(fastfield_accessor: &impl FastFieldDataAccess) -> f32 {
|
|
||||||
let first_val_in_first_block = fastfield_accessor.get_val(0);
|
let first_val_in_first_block = fastfield_accessor.get_val(0);
|
||||||
let last_elem_in_first_chunk = CHUNK_SIZE.min(fastfield_accessor.num_vals());
|
let last_elem_in_first_chunk = CHUNK_SIZE.min(fastfield_accessor.num_vals());
|
||||||
let last_val_in_first_block =
|
let last_val_in_first_block =
|
||||||
@@ -350,7 +342,7 @@ impl FastFieldCodec for BlockwiseLinearCodec {
|
|||||||
// function metadata per block
|
// function metadata per block
|
||||||
+ 29 * (fastfield_accessor.num_vals() / CHUNK_SIZE);
|
+ 29 * (fastfield_accessor.num_vals() / CHUNK_SIZE);
|
||||||
let num_bits_uncompressed = 64 * fastfield_accessor.num_vals();
|
let num_bits_uncompressed = 64 * fastfield_accessor.num_vals();
|
||||||
num_bits as f32 / num_bits_uncompressed as f32
|
Some(num_bits as f32 / num_bits_uncompressed as f32)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,10 +357,10 @@ fn distance<T: Sub<Output = T> + Ord>(x: T, y: T) -> T {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::tests::get_codec_test_data_sets;
|
use crate::tests::get_codec_test_datasets;
|
||||||
|
|
||||||
fn create_and_validate(data: &[u64], name: &str) -> (f32, f32) {
|
fn create_and_validate(data: &[u64], name: &str) -> Option<(f32, f32)> {
|
||||||
crate::tests::create_and_validate::<BlockwiseLinearCodec, BlockwiseLinearReader>(data, name)
|
crate::tests::create_and_validate::<BlockwiseLinearCodec>(data, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
const HIGHEST_BIT: u64 = 1 << 63;
|
const HIGHEST_BIT: u64 = 1 << 63;
|
||||||
@@ -382,7 +374,7 @@ mod tests {
|
|||||||
.map(i64_to_u64)
|
.map(i64_to_u64)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let (estimate, actual_compression) =
|
let (estimate, actual_compression) =
|
||||||
create_and_validate(&data, "simple monotonically large i64");
|
create_and_validate(&data, "simple monotonically large i64").unwrap();
|
||||||
assert!(actual_compression < 0.2);
|
assert!(actual_compression < 0.2);
|
||||||
assert!(estimate < 0.20);
|
assert!(estimate < 0.20);
|
||||||
assert!(estimate > 0.15);
|
assert!(estimate > 0.15);
|
||||||
@@ -393,7 +385,7 @@ mod tests {
|
|||||||
fn test_compression() {
|
fn test_compression() {
|
||||||
let data = (10..=6_000_u64).collect::<Vec<_>>();
|
let data = (10..=6_000_u64).collect::<Vec<_>>();
|
||||||
let (estimate, actual_compression) =
|
let (estimate, actual_compression) =
|
||||||
create_and_validate(&data, "simple monotonically large");
|
create_and_validate(&data, "simple monotonically large").unwrap();
|
||||||
assert!(actual_compression < 0.2);
|
assert!(actual_compression < 0.2);
|
||||||
assert!(estimate < 0.20);
|
assert!(estimate < 0.20);
|
||||||
assert!(estimate > 0.15);
|
assert!(estimate > 0.15);
|
||||||
@@ -402,7 +394,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_with_codec_data_sets() {
|
fn test_with_codec_data_sets() {
|
||||||
let data_sets = get_codec_test_data_sets();
|
let data_sets = get_codec_test_datasets();
|
||||||
for (mut data, name) in data_sets {
|
for (mut data, name) in data_sets {
|
||||||
create_and_validate(&data, name);
|
create_and_validate(&data, name);
|
||||||
data.reverse();
|
data.reverse();
|
||||||
|
|||||||
48
fastfield_codecs/src/column.rs
Normal file
48
fastfield_codecs/src/column.rs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
|
use crate::ColumnIter;
|
||||||
|
|
||||||
|
pub trait Column<T = u64> {
|
||||||
|
/// Return the value associated to the given idx.
|
||||||
|
///
|
||||||
|
/// This accessor should return as fast as possible.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// May panic if `idx` is greater than the column length.
|
||||||
|
fn get_val(&self, idx: u64) -> T;
|
||||||
|
|
||||||
|
/// Returns an iterator over given doc range.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// May panic if `range.end()` is greater than
|
||||||
|
/// the segment's `maxdoc`.
|
||||||
|
#[inline]
|
||||||
|
fn get_range(&self, range: Range<u64>) -> ColumnIter<'_, Self, T>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
ColumnIter::new(self, range)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the minimum value for this fast field.
|
||||||
|
///
|
||||||
|
/// The min value does not take in account of possible
|
||||||
|
/// deleted document, and should be considered as a lower bound
|
||||||
|
/// of the actual minimum value.
|
||||||
|
fn min_value(&self) -> T;
|
||||||
|
|
||||||
|
/// Returns the maximum value for this fast field.
|
||||||
|
///
|
||||||
|
/// The max value does not take in account of possible
|
||||||
|
/// deleted document, and should be considered as an upper bound
|
||||||
|
/// of the actual maximum value
|
||||||
|
fn max_value(&self) -> T;
|
||||||
|
|
||||||
|
fn num_vals(&self) -> u64;
|
||||||
|
/// Returns a iterator over the data
|
||||||
|
fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = T> + 'a> {
|
||||||
|
Box::new((0..self.num_vals()).map(|idx| self.get_val(idx)))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,9 @@ extern crate more_asserts;
|
|||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
use std::iter::FusedIterator;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
use common::BinarySerializable;
|
use common::BinarySerializable;
|
||||||
use ownedbytes::OwnedBytes;
|
use ownedbytes::OwnedBytes;
|
||||||
@@ -12,16 +15,9 @@ pub mod bitpacked;
|
|||||||
pub mod blockwise_linear;
|
pub mod blockwise_linear;
|
||||||
pub mod linear;
|
pub mod linear;
|
||||||
|
|
||||||
pub trait FastFieldDataAccess {
|
mod column;
|
||||||
fn get_val(&self, doc: u64) -> u64;
|
|
||||||
fn min_value(&self) -> u64;
|
pub use self::column::Column;
|
||||||
fn max_value(&self) -> u64;
|
|
||||||
fn num_vals(&self) -> u64;
|
|
||||||
/// Returns a iterator over the data
|
|
||||||
fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = u64> + 'a> {
|
|
||||||
Box::new((0..self.num_vals()).map(|idx| self.get_val(idx)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
|
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
@@ -68,7 +64,7 @@ pub trait FastFieldCodec {
|
|||||||
/// used for debugging and de/serialization.
|
/// used for debugging and de/serialization.
|
||||||
const CODEC_TYPE: FastFieldCodecType;
|
const CODEC_TYPE: FastFieldCodecType;
|
||||||
|
|
||||||
type Reader: FastFieldDataAccess;
|
type Reader: Column<u64>;
|
||||||
|
|
||||||
/// Reads the metadata and returns the CodecReader
|
/// Reads the metadata and returns the CodecReader
|
||||||
fn open_from_bytes(bytes: OwnedBytes) -> io::Result<Self::Reader>;
|
fn open_from_bytes(bytes: OwnedBytes) -> io::Result<Self::Reader>;
|
||||||
@@ -77,20 +73,16 @@ pub trait FastFieldCodec {
|
|||||||
///
|
///
|
||||||
/// The fastfield_accessor iterator should be preferred over using fastfield_accessor for
|
/// The fastfield_accessor iterator should be preferred over using fastfield_accessor for
|
||||||
/// performance reasons.
|
/// performance reasons.
|
||||||
fn serialize(
|
fn serialize(write: &mut impl Write, fastfield_accessor: &dyn Column<u64>) -> io::Result<()>;
|
||||||
write: &mut impl Write,
|
|
||||||
fastfield_accessor: &dyn FastFieldDataAccess,
|
|
||||||
) -> io::Result<()>;
|
|
||||||
|
|
||||||
/// Check if the Codec is able to compress the data
|
|
||||||
fn is_applicable(fastfield_accessor: &impl FastFieldDataAccess) -> bool;
|
|
||||||
|
|
||||||
/// Returns an estimate of the compression ratio.
|
/// Returns an estimate of the compression ratio.
|
||||||
|
/// If the codec is not applicable, returns `None`.
|
||||||
|
///
|
||||||
/// The baseline is uncompressed 64bit data.
|
/// The baseline is uncompressed 64bit data.
|
||||||
///
|
///
|
||||||
/// It could make sense to also return a value representing
|
/// It could make sense to also return a value representing
|
||||||
/// computational complexity.
|
/// computational complexity.
|
||||||
fn estimate(fastfield_accessor: &impl FastFieldDataAccess) -> f32;
|
fn estimate(fastfield_accessor: &impl Column) -> Option<f32>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -101,7 +93,7 @@ pub struct FastFieldStats {
|
|||||||
pub num_vals: u64,
|
pub num_vals: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FastFieldDataAccess for &'a [u64] {
|
impl<'a> Column for &'a [u64] {
|
||||||
fn get_val(&self, position: u64) -> u64 {
|
fn get_val(&self, position: u64) -> u64 {
|
||||||
self[position as usize]
|
self[position as usize]
|
||||||
}
|
}
|
||||||
@@ -123,7 +115,57 @@ impl<'a> FastFieldDataAccess for &'a [u64] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FastFieldDataAccess for Vec<u64> {
|
pub struct ColumnIter<'a, C: Column<I>, I> {
|
||||||
|
column: &'a C,
|
||||||
|
range: Range<u64>,
|
||||||
|
_phantom: PhantomData<I>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, C: Column<I>, I> ColumnIter<'a, C, I> {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(col: &'a C, range: Range<u64>) -> Self {
|
||||||
|
Self {
|
||||||
|
column: col,
|
||||||
|
range,
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, C: Column<I>, I> Iterator for ColumnIter<'a, C, I> {
|
||||||
|
type Item = I;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
Some(self.column.get_val(self.range.next()?))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn fold<Acc, G>(self, init: Acc, mut g: G) -> Acc
|
||||||
|
where
|
||||||
|
G: FnMut(Acc, Self::Item) -> Acc,
|
||||||
|
{
|
||||||
|
self.range
|
||||||
|
.fold(init, move |acc, idx| g(acc, self.column.get_val(idx)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
let size = (self.range.end - self.range.start) as usize;
|
||||||
|
(size, Some(size))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, C: Column<I>, I> ExactSizeIterator for ColumnIter<'a, C, I> {
|
||||||
|
#[inline]
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
let size = (self.range.end - self.range.start) as usize;
|
||||||
|
size as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a, C: Column<I>, I> FusedIterator for ColumnIter<'a, C, I> {}
|
||||||
|
|
||||||
|
impl Column for Vec<u64> {
|
||||||
fn get_val(&self, position: u64) -> u64 {
|
fn get_val(&self, position: u64) -> u64 {
|
||||||
self[position as usize]
|
self[position as usize]
|
||||||
}
|
}
|
||||||
@@ -152,11 +194,12 @@ mod tests {
|
|||||||
use crate::blockwise_linear::BlockwiseLinearCodec;
|
use crate::blockwise_linear::BlockwiseLinearCodec;
|
||||||
use crate::linear::LinearCodec;
|
use crate::linear::LinearCodec;
|
||||||
|
|
||||||
pub fn create_and_validate<Codec: FastFieldCodec>(data: &[u64], name: &str) -> (f32, f32) {
|
pub fn create_and_validate<Codec: FastFieldCodec>(
|
||||||
if !Codec::is_applicable(&data) {
|
data: &[u64],
|
||||||
return (f32::MAX, 0.0);
|
name: &str,
|
||||||
}
|
) -> Option<(f32, f32)> {
|
||||||
let estimation = Codec::estimate(&data);
|
let estimation = Codec::estimate(&data)?;
|
||||||
|
|
||||||
let mut out: Vec<u8> = Vec::new();
|
let mut out: Vec<u8> = Vec::new();
|
||||||
Codec::serialize(&mut out, &data).unwrap();
|
Codec::serialize(&mut out, &data).unwrap();
|
||||||
|
|
||||||
@@ -164,16 +207,15 @@ mod tests {
|
|||||||
|
|
||||||
let reader = Codec::open_from_bytes(OwnedBytes::new(out)).unwrap();
|
let reader = Codec::open_from_bytes(OwnedBytes::new(out)).unwrap();
|
||||||
assert_eq!(reader.num_vals(), data.len() as u64);
|
assert_eq!(reader.num_vals(), data.len() as u64);
|
||||||
for (doc, orig_val) in data.iter().enumerate() {
|
for (doc, orig_val) in data.iter().copied().enumerate() {
|
||||||
let val = reader.get_val(doc as u64);
|
let val = reader.get_val(doc as u64);
|
||||||
if val != *orig_val {
|
assert_eq!(
|
||||||
panic!(
|
val, orig_val,
|
||||||
"val {val:?} does not match orig_val {orig_val:?}, in data set {name}, data \
|
"val `{val}` does not match orig_val {orig_val:?}, in data set {name}, data \
|
||||||
{data:?}",
|
`{data:?}`",
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
(estimation, actual_compression)
|
Some((estimation, actual_compression))
|
||||||
}
|
}
|
||||||
|
|
||||||
proptest! {
|
proptest! {
|
||||||
@@ -193,10 +235,10 @@ mod tests {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_codec_test_data_sets() -> Vec<(Vec<u64>, &'static str)> {
|
pub fn get_codec_test_datasets() -> Vec<(Vec<u64>, &'static str)> {
|
||||||
let mut data_and_names = vec![];
|
let mut data_and_names = vec![];
|
||||||
|
|
||||||
let data = (10..=20_u64).collect::<Vec<_>>();
|
let data = (10..=10_000_u64).collect::<Vec<_>>();
|
||||||
data_and_names.push((data, "simple monotonically increasing"));
|
data_and_names.push((data, "simple monotonically increasing"));
|
||||||
|
|
||||||
data_and_names.push((
|
data_and_names.push((
|
||||||
@@ -206,17 +248,23 @@ mod tests {
|
|||||||
data_and_names.push((vec![5, 50, 3, 13, 1, 1000, 35], "rand small"));
|
data_and_names.push((vec![5, 50, 3, 13, 1, 1000, 35], "rand small"));
|
||||||
data_and_names.push((vec![10], "single value"));
|
data_and_names.push((vec![10], "single value"));
|
||||||
|
|
||||||
|
data_and_names.push((
|
||||||
|
vec![1572656989877777, 1170935903116329, 720575940379279, 0],
|
||||||
|
"overflow error",
|
||||||
|
));
|
||||||
|
|
||||||
data_and_names
|
data_and_names
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_codec<C: FastFieldCodec>() {
|
fn test_codec<C: FastFieldCodec>() {
|
||||||
let codec_name = format!("{:?}", C::CODEC_TYPE);
|
let codec_name = format!("{:?}", C::CODEC_TYPE);
|
||||||
for (data, dataset_name) in get_codec_test_data_sets() {
|
for (data, dataset_name) in get_codec_test_datasets() {
|
||||||
let (estimate, actual) = crate::tests::create_and_validate::<C>(&data, dataset_name);
|
let estimate_actual_opt: Option<(f32, f32)> =
|
||||||
let result = if estimate == f32::MAX {
|
crate::tests::create_and_validate::<C>(&data, dataset_name);
|
||||||
"Disabled".to_string()
|
let result = if let Some((estimate, actual)) = estimate_actual_opt {
|
||||||
} else {
|
|
||||||
format!("Estimate `{estimate}` Actual `{actual}`")
|
format!("Estimate `{estimate}` Actual `{actual}`")
|
||||||
|
} else {
|
||||||
|
"Disabled".to_string()
|
||||||
};
|
};
|
||||||
println!("Codec {codec_name}, DataSet {dataset_name}, {result}");
|
println!("Codec {codec_name}, DataSet {dataset_name}, {result}");
|
||||||
}
|
}
|
||||||
@@ -240,37 +288,37 @@ mod tests {
|
|||||||
fn estimation_good_interpolation_case() {
|
fn estimation_good_interpolation_case() {
|
||||||
let data = (10..=20000_u64).collect::<Vec<_>>();
|
let data = (10..=20000_u64).collect::<Vec<_>>();
|
||||||
|
|
||||||
let linear_interpol_estimation = LinearCodec::estimate(&data);
|
let linear_interpol_estimation = LinearCodec::estimate(&data).unwrap();
|
||||||
assert_le!(linear_interpol_estimation, 0.01);
|
assert_le!(linear_interpol_estimation, 0.01);
|
||||||
|
|
||||||
let multi_linear_interpol_estimation = BlockwiseLinearCodec::estimate(&data);
|
let multi_linear_interpol_estimation = BlockwiseLinearCodec::estimate(&data).unwrap();
|
||||||
assert_le!(multi_linear_interpol_estimation, 0.2);
|
assert_le!(multi_linear_interpol_estimation, 0.2);
|
||||||
assert_le!(linear_interpol_estimation, multi_linear_interpol_estimation);
|
assert_le!(linear_interpol_estimation, multi_linear_interpol_estimation);
|
||||||
|
|
||||||
let bitpacked_estimation = BitpackedCodec::estimate(&data);
|
let bitpacked_estimation = BitpackedCodec::estimate(&data).unwrap();
|
||||||
assert_le!(linear_interpol_estimation, bitpacked_estimation);
|
assert_le!(linear_interpol_estimation, bitpacked_estimation);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn estimation_test_bad_interpolation_case() {
|
fn estimation_test_bad_interpolation_case() {
|
||||||
let data = vec![200, 10, 10, 10, 10, 1000, 20];
|
let data = vec![200, 10, 10, 10, 10, 1000, 20];
|
||||||
|
|
||||||
let linear_interpol_estimation = LinearCodec::estimate(&data);
|
let linear_interpol_estimation = LinearCodec::estimate(&data).unwrap();
|
||||||
assert_le!(linear_interpol_estimation, 0.32);
|
assert_le!(linear_interpol_estimation, 0.32);
|
||||||
|
|
||||||
let bitpacked_estimation = BitpackedCodec::estimate(&data);
|
let bitpacked_estimation = BitpackedCodec::estimate(&data).unwrap();
|
||||||
assert_le!(bitpacked_estimation, linear_interpol_estimation);
|
assert_le!(bitpacked_estimation, linear_interpol_estimation);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn estimation_test_bad_interpolation_case_monotonically_increasing() {
|
fn estimation_test_bad_interpolation_case_monotonically_increasing() {
|
||||||
let mut data = (200..=20000_u64).collect::<Vec<_>>();
|
let mut data: Vec<u64> = (200..=20000_u64).collect();
|
||||||
data.push(1_000_000);
|
data.push(1_000_000);
|
||||||
|
|
||||||
// in this case the linear interpolation can't in fact not be worse than bitpacking,
|
// in this case the linear interpolation can't in fact not be worse than bitpacking,
|
||||||
// but the estimator adds some threshold, which leads to estimated worse behavior
|
// but the estimator adds some threshold, which leads to estimated worse behavior
|
||||||
let linear_interpol_estimation = LinearCodec::estimate(&data);
|
let linear_interpol_estimation = LinearCodec::estimate(&data).unwrap();
|
||||||
assert_le!(linear_interpol_estimation, 0.35);
|
assert_le!(linear_interpol_estimation, 0.35);
|
||||||
|
|
||||||
let bitpacked_estimation = BitpackedCodec::estimate(&data);
|
let bitpacked_estimation = BitpackedCodec::estimate(&data).unwrap();
|
||||||
assert_le!(bitpacked_estimation, 0.32);
|
assert_le!(bitpacked_estimation, 0.32);
|
||||||
assert_le!(bitpacked_estimation, linear_interpol_estimation);
|
assert_le!(bitpacked_estimation, linear_interpol_estimation);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use common::{BinarySerializable, FixedSize};
|
|||||||
use ownedbytes::OwnedBytes;
|
use ownedbytes::OwnedBytes;
|
||||||
use tantivy_bitpacker::{compute_num_bits, BitPacker, BitUnpacker};
|
use tantivy_bitpacker::{compute_num_bits, BitPacker, BitUnpacker};
|
||||||
|
|
||||||
use crate::{FastFieldCodec, FastFieldCodecType, FastFieldDataAccess};
|
use crate::{Column, FastFieldCodec, FastFieldCodecType};
|
||||||
|
|
||||||
/// Depending on the field type, a different
|
/// Depending on the field type, a different
|
||||||
/// fast field is required.
|
/// fast field is required.
|
||||||
@@ -57,7 +57,7 @@ impl FixedSize for LinearFooter {
|
|||||||
const SIZE_IN_BYTES: usize = 56;
|
const SIZE_IN_BYTES: usize = 56;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FastFieldDataAccess for LinearReader {
|
impl Column for LinearReader {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_val(&self, doc: u64) -> u64 {
|
fn get_val(&self, doc: u64) -> u64 {
|
||||||
let calculated_value = get_calculated_value(self.footer.first_val, doc, self.slope);
|
let calculated_value = get_calculated_value(self.footer.first_val, doc, self.slope);
|
||||||
@@ -115,9 +115,9 @@ fn diff(val1: u64, val2: u64) -> f64 {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_calculated_value(first_val: u64, pos: u64, slope: f32) -> u64 {
|
pub fn get_calculated_value(first_val: u64, pos: u64, slope: f32) -> u64 {
|
||||||
if slope < 0.0 {
|
if slope < 0.0 {
|
||||||
first_val - (pos as f32 * -slope) as u64
|
first_val.saturating_sub((pos as f32 * -slope) as u64)
|
||||||
} else {
|
} else {
|
||||||
first_val + (pos as f32 * slope) as u64
|
first_val.saturating_add((pos as f32 * slope) as u64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,10 +143,7 @@ impl FastFieldCodec for LinearCodec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new fast field serializer.
|
/// Creates a new fast field serializer.
|
||||||
fn serialize(
|
fn serialize(write: &mut impl Write, fastfield_accessor: &dyn Column) -> io::Result<()> {
|
||||||
write: &mut impl Write,
|
|
||||||
fastfield_accessor: &dyn FastFieldDataAccess,
|
|
||||||
) -> io::Result<()> {
|
|
||||||
assert!(fastfield_accessor.min_value() <= fastfield_accessor.max_value());
|
assert!(fastfield_accessor.min_value() <= fastfield_accessor.max_value());
|
||||||
|
|
||||||
let first_val = fastfield_accessor.get_val(0);
|
let first_val = fastfield_accessor.get_val(0);
|
||||||
@@ -192,29 +189,25 @@ impl FastFieldCodec for LinearCodec {
|
|||||||
footer.serialize(write)?;
|
footer.serialize(write)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn is_applicable(fastfield_accessor: &impl FastFieldDataAccess) -> bool {
|
|
||||||
|
/// estimation for linear interpolation is hard because, you don't know
|
||||||
|
/// where the local maxima for the deviation of the calculated value are and
|
||||||
|
/// the offset to shift all values to >=0 is also unknown.
|
||||||
|
fn estimate(fastfield_accessor: &impl Column) -> Option<f32> {
|
||||||
if fastfield_accessor.num_vals() < 3 {
|
if fastfield_accessor.num_vals() < 3 {
|
||||||
return false; // disable compressor for this case
|
return None; // disable compressor for this case
|
||||||
}
|
}
|
||||||
|
|
||||||
// On serialisation the offset is added to the actual value.
|
// On serialisation the offset is added to the actual value.
|
||||||
// We need to make sure this won't run into overflow calculation issues.
|
// We need to make sure this won't run into overflow calculation issues.
|
||||||
// For this we take the maximum theroretical offset and add this to the max value.
|
// For this we take the maximum theroretical offset and add this to the max value.
|
||||||
// If this doesn't overflow the algorithm should be fine
|
// If this doesn't overflow the algorithm should be fine
|
||||||
let theorethical_maximum_offset =
|
let theorethical_maximum_offset =
|
||||||
fastfield_accessor.max_value() - fastfield_accessor.min_value();
|
fastfield_accessor.max_value() - fastfield_accessor.min_value();
|
||||||
if fastfield_accessor
|
fastfield_accessor
|
||||||
.max_value()
|
.max_value()
|
||||||
.checked_add(theorethical_maximum_offset)
|
.checked_add(theorethical_maximum_offset)?;
|
||||||
.is_none()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
/// estimation for linear interpolation is hard because, you don't know
|
|
||||||
/// where the local maxima for the deviation of the calculated value are and
|
|
||||||
/// the offset to shift all values to >=0 is also unknown.
|
|
||||||
fn estimate(fastfield_accessor: &impl FastFieldDataAccess) -> f32 {
|
|
||||||
let first_val = fastfield_accessor.get_val(0);
|
let first_val = fastfield_accessor.get_val(0);
|
||||||
let last_val = fastfield_accessor.get_val(fastfield_accessor.num_vals() as u64 - 1);
|
let last_val = fastfield_accessor.get_val(fastfield_accessor.num_vals() as u64 - 1);
|
||||||
let slope = get_slope(first_val, last_val, fastfield_accessor.num_vals());
|
let slope = get_slope(first_val, last_val, fastfield_accessor.num_vals());
|
||||||
@@ -246,7 +239,7 @@ impl FastFieldCodec for LinearCodec {
|
|||||||
* fastfield_accessor.num_vals()
|
* fastfield_accessor.num_vals()
|
||||||
+ LinearFooter::SIZE_IN_BYTES as u64;
|
+ LinearFooter::SIZE_IN_BYTES as u64;
|
||||||
let num_bits_uncompressed = 64 * fastfield_accessor.num_vals();
|
let num_bits_uncompressed = 64 * fastfield_accessor.num_vals();
|
||||||
num_bits as f32 / num_bits_uncompressed as f32
|
Some(num_bits as f32 / num_bits_uncompressed as f32)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,10 +255,10 @@ fn distance<T: Sub<Output = T> + Ord>(x: T, y: T) -> T {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::tests::get_codec_test_data_sets;
|
use crate::tests::get_codec_test_datasets;
|
||||||
|
|
||||||
fn create_and_validate(data: &[u64], name: &str) -> (f32, f32) {
|
fn create_and_validate(data: &[u64], name: &str) -> Option<(f32, f32)> {
|
||||||
crate::tests::create_and_validate::<LinearCodec, LinearReader>(data, name)
|
crate::tests::create_and_validate::<LinearCodec>(data, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -292,15 +285,15 @@ mod tests {
|
|||||||
fn test_compression() {
|
fn test_compression() {
|
||||||
let data = (10..=6_000_u64).collect::<Vec<_>>();
|
let data = (10..=6_000_u64).collect::<Vec<_>>();
|
||||||
let (estimate, actual_compression) =
|
let (estimate, actual_compression) =
|
||||||
create_and_validate(&data, "simple monotonically large");
|
create_and_validate(&data, "simple monotonically large").unwrap();
|
||||||
|
|
||||||
assert!(actual_compression < 0.01);
|
assert!(actual_compression < 0.01);
|
||||||
assert!(estimate < 0.01);
|
assert!(estimate < 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_with_codec_data_sets() {
|
fn test_with_codec_datasets() {
|
||||||
let data_sets = get_codec_test_data_sets();
|
let data_sets = get_codec_test_datasets();
|
||||||
for (mut data, name) in data_sets {
|
for (mut data, name) in data_sets {
|
||||||
create_and_validate(&data, name);
|
create_and_validate(&data, name);
|
||||||
data.reverse();
|
data.reverse();
|
||||||
@@ -317,6 +310,13 @@ mod tests {
|
|||||||
|
|
||||||
create_and_validate(&data, "large amplitude");
|
create_and_validate(&data, "large amplitude");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn overflow_error_test() {
|
||||||
|
let data = vec![1572656989877777, 1170935903116329, 720575940379279, 0];
|
||||||
|
create_and_validate(&data, "overflow test");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn linear_interpol_fast_concave_data() {
|
fn linear_interpol_fast_concave_data() {
|
||||||
let data = vec![0, 1, 2, 5, 8, 10, 20, 50];
|
let data = vec![0, 1, 2, 5, 8, 10, 20, 50];
|
||||||
@@ -337,9 +337,10 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn linear_interpol_fast_field_rand() {
|
fn linear_interpol_fast_field_rand() {
|
||||||
for _ in 0..5000 {
|
for _ in 0..5000 {
|
||||||
let mut data = (0..50).map(|_| rand::random::<u64>()).collect::<Vec<_>>();
|
let mut data = (0..10_000)
|
||||||
|
.map(|_| rand::random::<u64>())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
create_and_validate(&data, "random");
|
create_and_validate(&data, "random");
|
||||||
|
|
||||||
data.reverse();
|
data.reverse();
|
||||||
create_and_validate(&data, "random");
|
create_and_validate(&data, "random");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate prettytable;
|
extern crate prettytable;
|
||||||
|
use fastfield_codecs::bitpacked::BitpackedCodec;
|
||||||
use fastfield_codecs::blockwise_linear::BlockwiseLinearCodec;
|
use fastfield_codecs::blockwise_linear::BlockwiseLinearCodec;
|
||||||
use fastfield_codecs::linear::LinearCodec;
|
use fastfield_codecs::linear::LinearCodec;
|
||||||
use fastfield_codecs::{FastFieldCodec, FastFieldCodecType, FastFieldStats};
|
use fastfield_codecs::{FastFieldCodec, FastFieldCodecType, FastFieldStats};
|
||||||
@@ -12,37 +13,30 @@ fn main() {
|
|||||||
table.add_row(row!["", "Compression Ratio", "Compression Estimation"]);
|
table.add_row(row!["", "Compression Ratio", "Compression Estimation"]);
|
||||||
|
|
||||||
for (data, data_set_name) in get_codec_test_data_sets() {
|
for (data, data_set_name) in get_codec_test_data_sets() {
|
||||||
let mut results = vec![];
|
let results: Vec<(f32, f32, FastFieldCodecType)> = [
|
||||||
let res = serialize_with_codec::<LinearCodec>(&data);
|
serialize_with_codec::<LinearCodec>(&data),
|
||||||
results.push(res);
|
serialize_with_codec::<BlockwiseLinearCodec>(&data),
|
||||||
let res = serialize_with_codec::<BlockwiseLinearCodec>(&data);
|
serialize_with_codec::<BlockwiseLinearCodec>(&data),
|
||||||
results.push(res);
|
serialize_with_codec::<BitpackedCodec>(&data),
|
||||||
let res = serialize_with_codec::<fastfield_codecs::bitpacked::BitpackedCodec>(&data);
|
]
|
||||||
results.push(res);
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
// let best_estimation_codec = results
|
.collect();
|
||||||
//.iter()
|
|
||||||
//.min_by(|res1, res2| res1.partial_cmp(&res2).unwrap())
|
|
||||||
//.unwrap();
|
|
||||||
let best_compression_ratio_codec = results
|
let best_compression_ratio_codec = results
|
||||||
.iter()
|
.iter()
|
||||||
.min_by(|res1, res2| res1.partial_cmp(res2).unwrap())
|
.min_by(|&res1, &res2| res1.partial_cmp(res2).unwrap())
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
table.add_row(Row::new(vec![Cell::new(data_set_name).style_spec("Bbb")]));
|
table.add_row(Row::new(vec![Cell::new(data_set_name).style_spec("Bbb")]));
|
||||||
for (is_applicable, est, comp, codec_type) in results {
|
for (est, comp, codec_type) in results {
|
||||||
let (est_cell, ratio_cell) = if !is_applicable {
|
let est_cell = est.to_string();
|
||||||
("Codec Disabled".to_string(), "".to_string())
|
let ratio_cell = comp.to_string();
|
||||||
} else {
|
|
||||||
(est.to_string(), comp.to_string())
|
|
||||||
};
|
|
||||||
let style = if comp == best_compression_ratio_codec.1 {
|
let style = if comp == best_compression_ratio_codec.1 {
|
||||||
"Fb"
|
"Fb"
|
||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
};
|
};
|
||||||
|
|
||||||
table.add_row(Row::new(vec![
|
table.add_row(Row::new(vec![
|
||||||
Cell::new(&format!("{codec_type:?}")).style_spec("bFg"),
|
Cell::new(&format!("{codec_type:?}")).style_spec("bFg"),
|
||||||
Cell::new(&ratio_cell).style_spec(style),
|
Cell::new(&ratio_cell).style_spec(style),
|
||||||
@@ -91,17 +85,12 @@ pub fn get_codec_test_data_sets() -> Vec<(Vec<u64>, &'static str)> {
|
|||||||
|
|
||||||
pub fn serialize_with_codec<C: FastFieldCodec>(
|
pub fn serialize_with_codec<C: FastFieldCodec>(
|
||||||
data: &[u64],
|
data: &[u64],
|
||||||
) -> (bool, f32, f32, FastFieldCodecType) {
|
) -> Option<(f32, f32, FastFieldCodecType)> {
|
||||||
let is_applicable = C::is_applicable(&data);
|
let estimation = C::estimate(&data)?;
|
||||||
if !is_applicable {
|
let mut out = Vec::new();
|
||||||
return (false, 0.0, 0.0, C::CODEC_TYPE);
|
|
||||||
}
|
|
||||||
let estimation = C::estimate(&data);
|
|
||||||
let mut out = vec![];
|
|
||||||
C::serialize(&mut out, &data).unwrap();
|
C::serialize(&mut out, &data).unwrap();
|
||||||
|
|
||||||
let actual_compression = out.len() as f32 / (data.len() * 8) as f32;
|
let actual_compression = out.len() as f32 / (data.len() * 8) as f32;
|
||||||
(true, estimation, actual_compression, C::CODEC_TYPE)
|
Some((estimation, actual_compression, C::CODEC_TYPE))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stats_from_vec(data: &[u64]) -> FastFieldStats {
|
pub fn stats_from_vec(data: &[u64]) -> FastFieldStats {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
use fastfield_codecs::Column;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@@ -14,7 +15,7 @@ use crate::aggregation::intermediate_agg_result::{
|
|||||||
IntermediateAggregationResults, IntermediateBucketResult, IntermediateHistogramBucketEntry,
|
IntermediateAggregationResults, IntermediateBucketResult, IntermediateHistogramBucketEntry,
|
||||||
};
|
};
|
||||||
use crate::aggregation::segment_agg_result::SegmentAggregationResultsCollector;
|
use crate::aggregation::segment_agg_result::SegmentAggregationResultsCollector;
|
||||||
use crate::fastfield::{DynamicFastFieldReader, FastFieldReader};
|
use crate::fastfield::DynamicFastFieldReader;
|
||||||
use crate::schema::Type;
|
use crate::schema::Type;
|
||||||
use crate::{DocId, TantivyError};
|
use crate::{DocId, TantivyError};
|
||||||
|
|
||||||
@@ -331,10 +332,10 @@ impl SegmentHistogramCollector {
|
|||||||
.expect("unexpected fast field cardinatility");
|
.expect("unexpected fast field cardinatility");
|
||||||
let mut iter = doc.chunks_exact(4);
|
let mut iter = doc.chunks_exact(4);
|
||||||
for docs in iter.by_ref() {
|
for docs in iter.by_ref() {
|
||||||
let val0 = self.f64_from_fastfield_u64(accessor.get(docs[0]));
|
let val0 = self.f64_from_fastfield_u64(accessor.get_val(docs[0] as u64));
|
||||||
let val1 = self.f64_from_fastfield_u64(accessor.get(docs[1]));
|
let val1 = self.f64_from_fastfield_u64(accessor.get_val(docs[1] as u64));
|
||||||
let val2 = self.f64_from_fastfield_u64(accessor.get(docs[2]));
|
let val2 = self.f64_from_fastfield_u64(accessor.get_val(docs[2] as u64));
|
||||||
let val3 = self.f64_from_fastfield_u64(accessor.get(docs[3]));
|
let val3 = self.f64_from_fastfield_u64(accessor.get_val(docs[3] as u64));
|
||||||
|
|
||||||
let bucket_pos0 = get_bucket_num(val0);
|
let bucket_pos0 = get_bucket_num(val0);
|
||||||
let bucket_pos1 = get_bucket_num(val1);
|
let bucket_pos1 = get_bucket_num(val1);
|
||||||
@@ -370,8 +371,8 @@ impl SegmentHistogramCollector {
|
|||||||
&bucket_with_accessor.sub_aggregation,
|
&bucket_with_accessor.sub_aggregation,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
for doc in iter.remainder() {
|
for &doc in iter.remainder() {
|
||||||
let val = f64_from_fastfield_u64(accessor.get(*doc), &self.field_type);
|
let val = f64_from_fastfield_u64(accessor.get_val(doc as u64), &self.field_type);
|
||||||
if !bounds.contains(val) {
|
if !bounds.contains(val) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -382,7 +383,7 @@ impl SegmentHistogramCollector {
|
|||||||
self.buckets[bucket_pos].key,
|
self.buckets[bucket_pos].key,
|
||||||
get_bucket_val(val, self.interval, self.offset) as f64
|
get_bucket_val(val, self.interval, self.offset) as f64
|
||||||
);
|
);
|
||||||
self.increment_bucket(bucket_pos, *doc, &bucket_with_accessor.sub_aggregation)?;
|
self.increment_bucket(bucket_pos, doc, &bucket_with_accessor.sub_aggregation)?;
|
||||||
}
|
}
|
||||||
if force_flush {
|
if force_flush {
|
||||||
if let Some(sub_aggregations) = self.sub_aggregations.as_mut() {
|
if let Some(sub_aggregations) = self.sub_aggregations.as_mut() {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
|
use fastfield_codecs::Column;
|
||||||
use fnv::FnvHashMap;
|
use fnv::FnvHashMap;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@@ -12,7 +13,6 @@ use crate::aggregation::intermediate_agg_result::{
|
|||||||
};
|
};
|
||||||
use crate::aggregation::segment_agg_result::{BucketCount, SegmentAggregationResultsCollector};
|
use crate::aggregation::segment_agg_result::{BucketCount, SegmentAggregationResultsCollector};
|
||||||
use crate::aggregation::{f64_from_fastfield_u64, f64_to_fastfield_u64, Key, SerializedKey};
|
use crate::aggregation::{f64_from_fastfield_u64, f64_to_fastfield_u64, Key, SerializedKey};
|
||||||
use crate::fastfield::FastFieldReader;
|
|
||||||
use crate::schema::Type;
|
use crate::schema::Type;
|
||||||
use crate::{DocId, TantivyError};
|
use crate::{DocId, TantivyError};
|
||||||
|
|
||||||
@@ -264,10 +264,10 @@ impl SegmentRangeCollector {
|
|||||||
.as_single()
|
.as_single()
|
||||||
.expect("unexpected fast field cardinatility");
|
.expect("unexpected fast field cardinatility");
|
||||||
for docs in iter.by_ref() {
|
for docs in iter.by_ref() {
|
||||||
let val1 = accessor.get(docs[0]);
|
let val1 = accessor.get_val(docs[0] as u64);
|
||||||
let val2 = accessor.get(docs[1]);
|
let val2 = accessor.get_val(docs[1] as u64);
|
||||||
let val3 = accessor.get(docs[2]);
|
let val3 = accessor.get_val(docs[2] as u64);
|
||||||
let val4 = accessor.get(docs[3]);
|
let val4 = accessor.get_val(docs[3] as u64);
|
||||||
let bucket_pos1 = self.get_bucket_pos(val1);
|
let bucket_pos1 = self.get_bucket_pos(val1);
|
||||||
let bucket_pos2 = self.get_bucket_pos(val2);
|
let bucket_pos2 = self.get_bucket_pos(val2);
|
||||||
let bucket_pos3 = self.get_bucket_pos(val3);
|
let bucket_pos3 = self.get_bucket_pos(val3);
|
||||||
@@ -278,10 +278,10 @@ impl SegmentRangeCollector {
|
|||||||
self.increment_bucket(bucket_pos3, docs[2], &bucket_with_accessor.sub_aggregation)?;
|
self.increment_bucket(bucket_pos3, docs[2], &bucket_with_accessor.sub_aggregation)?;
|
||||||
self.increment_bucket(bucket_pos4, docs[3], &bucket_with_accessor.sub_aggregation)?;
|
self.increment_bucket(bucket_pos4, docs[3], &bucket_with_accessor.sub_aggregation)?;
|
||||||
}
|
}
|
||||||
for doc in iter.remainder() {
|
for &doc in iter.remainder() {
|
||||||
let val = accessor.get(*doc);
|
let val = accessor.get_val(doc as u64);
|
||||||
let bucket_pos = self.get_bucket_pos(val);
|
let bucket_pos = self.get_bucket_pos(val);
|
||||||
self.increment_bucket(bucket_pos, *doc, &bucket_with_accessor.sub_aggregation)?;
|
self.increment_bucket(bucket_pos, doc, &bucket_with_accessor.sub_aggregation)?;
|
||||||
}
|
}
|
||||||
if force_flush {
|
if force_flush {
|
||||||
for bucket in &mut self.buckets {
|
for bucket in &mut self.buckets {
|
||||||
|
|||||||
@@ -242,13 +242,13 @@ impl TermBuckets {
|
|||||||
|
|
||||||
fn increment_bucket(
|
fn increment_bucket(
|
||||||
&mut self,
|
&mut self,
|
||||||
term_ids: &[u64],
|
term_ids: impl Iterator<Item = u64>,
|
||||||
doc: DocId,
|
doc: DocId,
|
||||||
sub_aggregation: &AggregationsWithAccessor,
|
sub_aggregation: &AggregationsWithAccessor,
|
||||||
bucket_count: &BucketCount,
|
bucket_count: &BucketCount,
|
||||||
blueprint: &Option<SegmentAggregationResultsCollector>,
|
blueprint: &Option<SegmentAggregationResultsCollector>,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<()> {
|
||||||
for &term_id in term_ids {
|
for term_id in term_ids {
|
||||||
let entry = self.entries.entry(term_id as u32).or_insert_with(|| {
|
let entry = self.entries.entry(term_id as u32).or_insert_with(|| {
|
||||||
bucket_count.add_count(1);
|
bucket_count.add_count(1);
|
||||||
|
|
||||||
@@ -432,39 +432,30 @@ impl SegmentTermCollector {
|
|||||||
.as_multi()
|
.as_multi()
|
||||||
.expect("unexpected fast field cardinatility");
|
.expect("unexpected fast field cardinatility");
|
||||||
let mut iter = doc.chunks_exact(4);
|
let mut iter = doc.chunks_exact(4);
|
||||||
let mut vals1 = vec![];
|
|
||||||
let mut vals2 = vec![];
|
|
||||||
let mut vals3 = vec![];
|
|
||||||
let mut vals4 = vec![];
|
|
||||||
for docs in iter.by_ref() {
|
for docs in iter.by_ref() {
|
||||||
accessor.get_vals(docs[0], &mut vals1);
|
|
||||||
accessor.get_vals(docs[1], &mut vals2);
|
|
||||||
accessor.get_vals(docs[2], &mut vals3);
|
|
||||||
accessor.get_vals(docs[3], &mut vals4);
|
|
||||||
|
|
||||||
self.term_buckets.increment_bucket(
|
self.term_buckets.increment_bucket(
|
||||||
&vals1,
|
accessor.get_vals(docs[0]),
|
||||||
docs[0],
|
docs[0],
|
||||||
&bucket_with_accessor.sub_aggregation,
|
&bucket_with_accessor.sub_aggregation,
|
||||||
&bucket_with_accessor.bucket_count,
|
&bucket_with_accessor.bucket_count,
|
||||||
&self.blueprint,
|
&self.blueprint,
|
||||||
)?;
|
)?;
|
||||||
self.term_buckets.increment_bucket(
|
self.term_buckets.increment_bucket(
|
||||||
&vals2,
|
accessor.get_vals(docs[1]),
|
||||||
docs[1],
|
docs[1],
|
||||||
&bucket_with_accessor.sub_aggregation,
|
&bucket_with_accessor.sub_aggregation,
|
||||||
&bucket_with_accessor.bucket_count,
|
&bucket_with_accessor.bucket_count,
|
||||||
&self.blueprint,
|
&self.blueprint,
|
||||||
)?;
|
)?;
|
||||||
self.term_buckets.increment_bucket(
|
self.term_buckets.increment_bucket(
|
||||||
&vals3,
|
accessor.get_vals(docs[2]),
|
||||||
docs[2],
|
docs[2],
|
||||||
&bucket_with_accessor.sub_aggregation,
|
&bucket_with_accessor.sub_aggregation,
|
||||||
&bucket_with_accessor.bucket_count,
|
&bucket_with_accessor.bucket_count,
|
||||||
&self.blueprint,
|
&self.blueprint,
|
||||||
)?;
|
)?;
|
||||||
self.term_buckets.increment_bucket(
|
self.term_buckets.increment_bucket(
|
||||||
&vals4,
|
accessor.get_vals(docs[3]),
|
||||||
docs[3],
|
docs[3],
|
||||||
&bucket_with_accessor.sub_aggregation,
|
&bucket_with_accessor.sub_aggregation,
|
||||||
&bucket_with_accessor.bucket_count,
|
&bucket_with_accessor.bucket_count,
|
||||||
@@ -472,10 +463,8 @@ impl SegmentTermCollector {
|
|||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
for &doc in iter.remainder() {
|
for &doc in iter.remainder() {
|
||||||
accessor.get_vals(doc, &mut vals1);
|
|
||||||
|
|
||||||
self.term_buckets.increment_bucket(
|
self.term_buckets.increment_bucket(
|
||||||
&vals1,
|
accessor.get_vals(doc),
|
||||||
doc,
|
doc,
|
||||||
&bucket_with_accessor.sub_aggregation,
|
&bucket_with_accessor.sub_aggregation,
|
||||||
&bucket_with_accessor.bucket_count,
|
&bucket_with_accessor.bucket_count,
|
||||||
@@ -1334,11 +1323,15 @@ mod bench {
|
|||||||
max_bucket_count: 1_000_001u32,
|
max_bucket_count: 1_000_001u32,
|
||||||
};
|
};
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
for &val in &vals {
|
collector
|
||||||
collector
|
.increment_bucket(
|
||||||
.increment_bucket(&[val], 0, &aggregations_with_accessor, &bucket_count, &None)
|
vals.iter().cloned(),
|
||||||
.unwrap();
|
0,
|
||||||
}
|
&aggregations_with_accessor,
|
||||||
|
&bucket_count,
|
||||||
|
&None,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use fastfield_codecs::Column;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::aggregation::f64_from_fastfield_u64;
|
use crate::aggregation::f64_from_fastfield_u64;
|
||||||
use crate::fastfield::{DynamicFastFieldReader, FastFieldReader};
|
use crate::fastfield::DynamicFastFieldReader;
|
||||||
use crate::schema::Type;
|
use crate::schema::Type;
|
||||||
use crate::DocId;
|
use crate::DocId;
|
||||||
|
|
||||||
@@ -60,10 +61,10 @@ impl SegmentAverageCollector {
|
|||||||
pub(crate) fn collect_block(&mut self, doc: &[DocId], field: &DynamicFastFieldReader<u64>) {
|
pub(crate) fn collect_block(&mut self, doc: &[DocId], field: &DynamicFastFieldReader<u64>) {
|
||||||
let mut iter = doc.chunks_exact(4);
|
let mut iter = doc.chunks_exact(4);
|
||||||
for docs in iter.by_ref() {
|
for docs in iter.by_ref() {
|
||||||
let val1 = field.get(docs[0]);
|
let val1 = field.get_val(docs[0] as u64);
|
||||||
let val2 = field.get(docs[1]);
|
let val2 = field.get_val(docs[1] as u64);
|
||||||
let val3 = field.get(docs[2]);
|
let val3 = field.get_val(docs[2] as u64);
|
||||||
let val4 = field.get(docs[3]);
|
let val4 = field.get_val(docs[3] as u64);
|
||||||
let val1 = f64_from_fastfield_u64(val1, &self.field_type);
|
let val1 = f64_from_fastfield_u64(val1, &self.field_type);
|
||||||
let val2 = f64_from_fastfield_u64(val2, &self.field_type);
|
let val2 = f64_from_fastfield_u64(val2, &self.field_type);
|
||||||
let val3 = f64_from_fastfield_u64(val3, &self.field_type);
|
let val3 = f64_from_fastfield_u64(val3, &self.field_type);
|
||||||
@@ -73,8 +74,8 @@ impl SegmentAverageCollector {
|
|||||||
self.data.collect(val3);
|
self.data.collect(val3);
|
||||||
self.data.collect(val4);
|
self.data.collect(val4);
|
||||||
}
|
}
|
||||||
for doc in iter.remainder() {
|
for &doc in iter.remainder() {
|
||||||
let val = field.get(*doc);
|
let val = field.get_val(doc as u64);
|
||||||
let val = f64_from_fastfield_u64(val, &self.field_type);
|
let val = f64_from_fastfield_u64(val, &self.field_type);
|
||||||
self.data.collect(val);
|
self.data.collect(val);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
|
use fastfield_codecs::Column;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::aggregation::f64_from_fastfield_u64;
|
use crate::aggregation::f64_from_fastfield_u64;
|
||||||
use crate::fastfield::{DynamicFastFieldReader, FastFieldReader};
|
use crate::fastfield::DynamicFastFieldReader;
|
||||||
use crate::schema::Type;
|
use crate::schema::Type;
|
||||||
use crate::{DocId, TantivyError};
|
use crate::{DocId, TantivyError};
|
||||||
|
|
||||||
@@ -166,10 +167,10 @@ impl SegmentStatsCollector {
|
|||||||
pub(crate) fn collect_block(&mut self, doc: &[DocId], field: &DynamicFastFieldReader<u64>) {
|
pub(crate) fn collect_block(&mut self, doc: &[DocId], field: &DynamicFastFieldReader<u64>) {
|
||||||
let mut iter = doc.chunks_exact(4);
|
let mut iter = doc.chunks_exact(4);
|
||||||
for docs in iter.by_ref() {
|
for docs in iter.by_ref() {
|
||||||
let val1 = field.get(docs[0]);
|
let val1 = field.get_val(docs[0] as u64);
|
||||||
let val2 = field.get(docs[1]);
|
let val2 = field.get_val(docs[1] as u64);
|
||||||
let val3 = field.get(docs[2]);
|
let val3 = field.get_val(docs[2] as u64);
|
||||||
let val4 = field.get(docs[3]);
|
let val4 = field.get_val(docs[3] as u64);
|
||||||
let val1 = f64_from_fastfield_u64(val1, &self.field_type);
|
let val1 = f64_from_fastfield_u64(val1, &self.field_type);
|
||||||
let val2 = f64_from_fastfield_u64(val2, &self.field_type);
|
let val2 = f64_from_fastfield_u64(val2, &self.field_type);
|
||||||
let val3 = f64_from_fastfield_u64(val3, &self.field_type);
|
let val3 = f64_from_fastfield_u64(val3, &self.field_type);
|
||||||
@@ -179,8 +180,8 @@ impl SegmentStatsCollector {
|
|||||||
self.stats.collect(val3);
|
self.stats.collect(val3);
|
||||||
self.stats.collect(val4);
|
self.stats.collect(val4);
|
||||||
}
|
}
|
||||||
for doc in iter.remainder() {
|
for &doc in iter.remainder() {
|
||||||
let val = field.get(*doc);
|
let val = field.get_val(doc as u64);
|
||||||
let val = f64_from_fastfield_u64(val, &self.field_type);
|
let val = f64_from_fastfield_u64(val, &self.field_type);
|
||||||
self.stats.collect(val);
|
self.stats.collect(val);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,10 @@
|
|||||||
// Importing tantivy...
|
// Importing tantivy...
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use fastfield_codecs::Column;
|
||||||
|
|
||||||
use crate::collector::{Collector, SegmentCollector};
|
use crate::collector::{Collector, SegmentCollector};
|
||||||
use crate::fastfield::{DynamicFastFieldReader, FastFieldReader, FastValue};
|
use crate::fastfield::{DynamicFastFieldReader, FastValue};
|
||||||
use crate::schema::Field;
|
use crate::schema::Field;
|
||||||
use crate::{Score, SegmentReader, TantivyError};
|
use crate::{Score, SegmentReader, TantivyError};
|
||||||
|
|
||||||
@@ -174,7 +176,7 @@ where
|
|||||||
type Fruit = TSegmentCollector::Fruit;
|
type Fruit = TSegmentCollector::Fruit;
|
||||||
|
|
||||||
fn collect(&mut self, doc: u32, score: Score) {
|
fn collect(&mut self, doc: u32, score: Score) {
|
||||||
let value = self.fast_field_reader.get(doc);
|
let value = self.fast_field_reader.get_val(doc as u64);
|
||||||
if (self.predicate)(value) {
|
if (self.predicate)(value) {
|
||||||
self.segment_collector.collect(doc, score)
|
self.segment_collector.collect(doc, score)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
use fastdivide::DividerU64;
|
use fastdivide::DividerU64;
|
||||||
|
use fastfield_codecs::Column;
|
||||||
|
|
||||||
use crate::collector::{Collector, SegmentCollector};
|
use crate::collector::{Collector, SegmentCollector};
|
||||||
use crate::fastfield::{DynamicFastFieldReader, FastFieldReader, FastValue};
|
use crate::fastfield::{DynamicFastFieldReader, FastValue};
|
||||||
use crate::schema::{Field, Type};
|
use crate::schema::{Field, Type};
|
||||||
use crate::{DocId, Score};
|
use crate::{DocId, Score};
|
||||||
|
|
||||||
@@ -91,7 +92,7 @@ impl SegmentCollector for SegmentHistogramCollector {
|
|||||||
type Fruit = Vec<u64>;
|
type Fruit = Vec<u64>;
|
||||||
|
|
||||||
fn collect(&mut self, doc: DocId, _score: Score) {
|
fn collect(&mut self, doc: DocId, _score: Score) {
|
||||||
let value = self.ff_reader.get(doc);
|
let value = self.ff_reader.get_val(doc as u64);
|
||||||
self.histogram_computer.add_value(value);
|
self.histogram_computer.add_value(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
use fastfield_codecs::Column;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::collector::{Count, FilterCollector, TopDocs};
|
use crate::collector::{Count, FilterCollector, TopDocs};
|
||||||
use crate::core::SegmentReader;
|
use crate::core::SegmentReader;
|
||||||
use crate::fastfield::{BytesFastFieldReader, DynamicFastFieldReader, FastFieldReader};
|
use crate::fastfield::{BytesFastFieldReader, DynamicFastFieldReader};
|
||||||
use crate::query::{AllQuery, QueryParser};
|
use crate::query::{AllQuery, QueryParser};
|
||||||
use crate::schema::{Field, Schema, FAST, TEXT};
|
use crate::schema::{Field, Schema, FAST, TEXT};
|
||||||
use crate::time::format_description::well_known::Rfc3339;
|
use crate::time::format_description::well_known::Rfc3339;
|
||||||
@@ -197,7 +199,7 @@ impl SegmentCollector for FastFieldSegmentCollector {
|
|||||||
type Fruit = Vec<u64>;
|
type Fruit = Vec<u64>;
|
||||||
|
|
||||||
fn collect(&mut self, doc: DocId, _score: Score) {
|
fn collect(&mut self, doc: DocId, _score: Score) {
|
||||||
let val = self.reader.get(doc);
|
let val = self.reader.get_val(doc as u64);
|
||||||
self.vals.push(val);
|
self.vals.push(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ use std::collections::BinaryHeap;
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use fastfield_codecs::Column;
|
||||||
|
|
||||||
use super::Collector;
|
use super::Collector;
|
||||||
use crate::collector::custom_score_top_collector::CustomScoreTopCollector;
|
use crate::collector::custom_score_top_collector::CustomScoreTopCollector;
|
||||||
use crate::collector::top_collector::{ComparableDoc, TopCollector, TopSegmentCollector};
|
use crate::collector::top_collector::{ComparableDoc, TopCollector, TopSegmentCollector};
|
||||||
@@ -9,7 +11,7 @@ use crate::collector::tweak_score_top_collector::TweakedScoreTopCollector;
|
|||||||
use crate::collector::{
|
use crate::collector::{
|
||||||
CustomScorer, CustomSegmentScorer, ScoreSegmentTweaker, ScoreTweaker, SegmentCollector,
|
CustomScorer, CustomSegmentScorer, ScoreSegmentTweaker, ScoreTweaker, SegmentCollector,
|
||||||
};
|
};
|
||||||
use crate::fastfield::{DynamicFastFieldReader, FastFieldReader, FastValue};
|
use crate::fastfield::{DynamicFastFieldReader, FastValue};
|
||||||
use crate::query::Weight;
|
use crate::query::Weight;
|
||||||
use crate::schema::Field;
|
use crate::schema::Field;
|
||||||
use crate::{DocAddress, DocId, Score, SegmentOrdinal, SegmentReader, TantivyError};
|
use crate::{DocAddress, DocId, Score, SegmentOrdinal, SegmentReader, TantivyError};
|
||||||
@@ -134,7 +136,7 @@ struct ScorerByFastFieldReader {
|
|||||||
|
|
||||||
impl CustomSegmentScorer<u64> for ScorerByFastFieldReader {
|
impl CustomSegmentScorer<u64> for ScorerByFastFieldReader {
|
||||||
fn score(&mut self, doc: DocId) -> u64 {
|
fn score(&mut self, doc: DocId) -> u64 {
|
||||||
self.ff_reader.get(doc)
|
self.ff_reader.get_val(doc as u64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -407,7 +409,7 @@ impl TopDocs {
|
|||||||
/// # use tantivy::query::QueryParser;
|
/// # use tantivy::query::QueryParser;
|
||||||
/// use tantivy::SegmentReader;
|
/// use tantivy::SegmentReader;
|
||||||
/// use tantivy::collector::TopDocs;
|
/// use tantivy::collector::TopDocs;
|
||||||
/// use tantivy::fastfield::FastFieldReader;
|
/// use tantivy::fastfield::Column;
|
||||||
/// use tantivy::schema::Field;
|
/// use tantivy::schema::Field;
|
||||||
///
|
///
|
||||||
/// fn create_schema() -> Schema {
|
/// fn create_schema() -> Schema {
|
||||||
@@ -456,7 +458,7 @@ impl TopDocs {
|
|||||||
///
|
///
|
||||||
/// // We can now define our actual scoring function
|
/// // We can now define our actual scoring function
|
||||||
/// move |doc: DocId, original_score: Score| {
|
/// move |doc: DocId, original_score: Score| {
|
||||||
/// let popularity: u64 = popularity_reader.get(doc);
|
/// let popularity: u64 = popularity_reader.get_val(doc as u64);
|
||||||
/// // Well.. For the sake of the example we use a simple logarithm
|
/// // Well.. For the sake of the example we use a simple logarithm
|
||||||
/// // function.
|
/// // function.
|
||||||
/// let popularity_boost_score = ((2u64 + popularity) as Score).log2();
|
/// let popularity_boost_score = ((2u64 + popularity) as Score).log2();
|
||||||
@@ -515,7 +517,7 @@ impl TopDocs {
|
|||||||
/// use tantivy::SegmentReader;
|
/// use tantivy::SegmentReader;
|
||||||
/// use tantivy::collector::TopDocs;
|
/// use tantivy::collector::TopDocs;
|
||||||
/// use tantivy::schema::Field;
|
/// use tantivy::schema::Field;
|
||||||
/// use tantivy::fastfield::FastFieldReader;
|
/// use fastfield_codecs::Column;
|
||||||
///
|
///
|
||||||
/// # fn create_schema() -> Schema {
|
/// # fn create_schema() -> Schema {
|
||||||
/// # let mut schema_builder = Schema::builder();
|
/// # let mut schema_builder = Schema::builder();
|
||||||
@@ -567,8 +569,8 @@ impl TopDocs {
|
|||||||
///
|
///
|
||||||
/// // We can now define our actual scoring function
|
/// // We can now define our actual scoring function
|
||||||
/// move |doc: DocId| {
|
/// move |doc: DocId| {
|
||||||
/// let popularity: u64 = popularity_reader.get(doc);
|
/// let popularity: u64 = popularity_reader.get_val(doc as u64);
|
||||||
/// let boosted: u64 = boosted_reader.get(doc);
|
/// let boosted: u64 = boosted_reader.get_val(doc as u64);
|
||||||
/// // Score do not have to be `f64` in tantivy.
|
/// // Score do not have to be `f64` in tantivy.
|
||||||
/// // Here we return a couple to get lexicographical order
|
/// // Here we return a couple to get lexicographical order
|
||||||
/// // for free.
|
/// // for free.
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
use fastfield_codecs::Column;
|
||||||
|
|
||||||
use crate::directory::{FileSlice, OwnedBytes};
|
use crate::directory::{FileSlice, OwnedBytes};
|
||||||
use crate::fastfield::{DynamicFastFieldReader, FastFieldReader, MultiValueLength};
|
use crate::fastfield::{DynamicFastFieldReader, MultiValueLength};
|
||||||
use crate::DocId;
|
use crate::DocId;
|
||||||
|
|
||||||
/// Reader for byte array fast fields
|
/// Reader for byte array fast fields
|
||||||
@@ -28,8 +30,9 @@ impl BytesFastFieldReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn range(&self, doc: DocId) -> (usize, usize) {
|
fn range(&self, doc: DocId) -> (usize, usize) {
|
||||||
let start = self.idx_reader.get(doc) as usize;
|
let idx = doc as u64;
|
||||||
let stop = self.idx_reader.get(doc + 1) as usize;
|
let start = self.idx_reader.get_val(idx) as usize;
|
||||||
|
let stop = self.idx_reader.get_val(idx + 1) as usize;
|
||||||
(start, stop)
|
(start, stop)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,8 @@ impl FacetReader {
|
|||||||
|
|
||||||
/// Return the list of facet ordinals associated to a document.
|
/// Return the list of facet ordinals associated to a document.
|
||||||
pub fn facet_ords(&self, doc: DocId, output: &mut Vec<u64>) {
|
pub fn facet_ords(&self, doc: DocId, output: &mut Vec<u64>) {
|
||||||
self.term_ords.get_vals(doc, output);
|
output.clear();
|
||||||
|
output.extend(self.term_ords.get_vals(doc))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::num::NonZeroU64;
|
|||||||
|
|
||||||
use common::BinarySerializable;
|
use common::BinarySerializable;
|
||||||
use fastdivide::DividerU64;
|
use fastdivide::DividerU64;
|
||||||
use fastfield_codecs::{FastFieldCodec, FastFieldDataAccess};
|
use fastfield_codecs::{Column, FastFieldCodec};
|
||||||
use ownedbytes::OwnedBytes;
|
use ownedbytes::OwnedBytes;
|
||||||
|
|
||||||
pub const GCD_DEFAULT: u64 = 1;
|
pub const GCD_DEFAULT: u64 = 1;
|
||||||
@@ -12,7 +12,7 @@ pub const GCD_DEFAULT: u64 = 1;
|
|||||||
///
|
///
|
||||||
/// Holds the data and the codec to the read the data.
|
/// Holds the data and the codec to the read the data.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct GCDReader<CodecReader: FastFieldDataAccess> {
|
pub struct GCDReader<CodecReader: Column> {
|
||||||
gcd_params: GCDParams,
|
gcd_params: GCDParams,
|
||||||
reader: CodecReader,
|
reader: CodecReader,
|
||||||
}
|
}
|
||||||
@@ -60,7 +60,7 @@ pub fn open_gcd_from_bytes<WrappedCodec: FastFieldCodec>(
|
|||||||
Ok(GCDReader { gcd_params, reader })
|
Ok(GCDReader { gcd_params, reader })
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: FastFieldDataAccess + Clone> FastFieldDataAccess for GCDReader<C> {
|
impl<C: Column + Clone> Column for GCDReader<C> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_val(&self, doc: u64) -> u64 {
|
fn get_val(&self, doc: u64) -> u64 {
|
||||||
let val = self.reader.get_val(doc);
|
let val = self.reader.get_val(doc);
|
||||||
@@ -137,6 +137,7 @@ mod tests {
|
|||||||
use std::time::{Duration, SystemTime};
|
use std::time::{Duration, SystemTime};
|
||||||
|
|
||||||
use common::HasLen;
|
use common::HasLen;
|
||||||
|
use fastfield_codecs::Column;
|
||||||
|
|
||||||
use crate::directory::{CompositeFile, RamDirectory, WritePtr};
|
use crate::directory::{CompositeFile, RamDirectory, WritePtr};
|
||||||
use crate::fastfield::gcd::compute_gcd;
|
use crate::fastfield::gcd::compute_gcd;
|
||||||
@@ -144,7 +145,7 @@ mod tests {
|
|||||||
use crate::fastfield::tests::{FIELD, FIELDI64, SCHEMA, SCHEMAI64};
|
use crate::fastfield::tests::{FIELD, FIELDI64, SCHEMA, SCHEMAI64};
|
||||||
use crate::fastfield::{
|
use crate::fastfield::{
|
||||||
find_gcd, CompositeFastFieldSerializer, DynamicFastFieldReader, FastFieldCodecType,
|
find_gcd, CompositeFastFieldSerializer, DynamicFastFieldReader, FastFieldCodecType,
|
||||||
FastFieldReader, FastFieldsWriter, ALL_CODECS,
|
FastFieldsWriter, ALL_CODECS,
|
||||||
};
|
};
|
||||||
use crate::schema::{Cardinality, Schema};
|
use crate::schema::{Cardinality, Schema};
|
||||||
use crate::{DateOptions, DatePrecision, DateTime, Directory};
|
use crate::{DateOptions, DatePrecision, DateTime, Directory};
|
||||||
@@ -188,9 +189,9 @@ mod tests {
|
|||||||
let file = composite_file.open_read(*FIELD).unwrap();
|
let file = composite_file.open_read(*FIELD).unwrap();
|
||||||
let fast_field_reader = DynamicFastFieldReader::<i64>::open(file)?;
|
let fast_field_reader = DynamicFastFieldReader::<i64>::open(file)?;
|
||||||
|
|
||||||
assert_eq!(fast_field_reader.get(0), -4000i64);
|
assert_eq!(fast_field_reader.get_val(0), -4000i64);
|
||||||
assert_eq!(fast_field_reader.get(1), -3000i64);
|
assert_eq!(fast_field_reader.get_val(1), -3000i64);
|
||||||
assert_eq!(fast_field_reader.get(2), -2000i64);
|
assert_eq!(fast_field_reader.get_val(2), -2000i64);
|
||||||
assert_eq!(fast_field_reader.max_value(), (num_vals as i64 - 5) * 1000);
|
assert_eq!(fast_field_reader.max_value(), (num_vals as i64 - 5) * 1000);
|
||||||
assert_eq!(fast_field_reader.min_value(), -4000i64);
|
assert_eq!(fast_field_reader.min_value(), -4000i64);
|
||||||
let file = directory.open_read(path).unwrap();
|
let file = directory.open_read(path).unwrap();
|
||||||
@@ -209,7 +210,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_fastfield_gcd_i64() -> crate::Result<()> {
|
fn test_fastfield_gcd_i64() -> crate::Result<()> {
|
||||||
for &code_type in ALL_CODECS {
|
for &code_type in ALL_CODECS {
|
||||||
test_fastfield_gcd_i64_with_codec(code_type, 5005)?;
|
test_fastfield_gcd_i64_with_codec(code_type, 5500)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -229,9 +230,9 @@ mod tests {
|
|||||||
let composite_file = CompositeFile::open(&file)?;
|
let composite_file = CompositeFile::open(&file)?;
|
||||||
let file = composite_file.open_read(*FIELD).unwrap();
|
let file = composite_file.open_read(*FIELD).unwrap();
|
||||||
let fast_field_reader = DynamicFastFieldReader::<u64>::open(file)?;
|
let fast_field_reader = DynamicFastFieldReader::<u64>::open(file)?;
|
||||||
assert_eq!(fast_field_reader.get(0), 1000u64);
|
assert_eq!(fast_field_reader.get_val(0), 1000u64);
|
||||||
assert_eq!(fast_field_reader.get(1), 2000u64);
|
assert_eq!(fast_field_reader.get_val(1), 2000u64);
|
||||||
assert_eq!(fast_field_reader.get(2), 3000u64);
|
assert_eq!(fast_field_reader.get_val(2), 3000u64);
|
||||||
assert_eq!(fast_field_reader.max_value(), num_vals as u64 * 1000);
|
assert_eq!(fast_field_reader.max_value(), num_vals as u64 * 1000);
|
||||||
assert_eq!(fast_field_reader.min_value(), 1000u64);
|
assert_eq!(fast_field_reader.min_value(), 1000u64);
|
||||||
let file = directory.open_read(path).unwrap();
|
let file = directory.open_read(path).unwrap();
|
||||||
@@ -250,7 +251,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_fastfield_gcd_u64() -> crate::Result<()> {
|
fn test_fastfield_gcd_u64() -> crate::Result<()> {
|
||||||
for &code_type in ALL_CODECS {
|
for &code_type in ALL_CODECS {
|
||||||
test_fastfield_gcd_u64_with_codec(code_type, 5005)?;
|
test_fastfield_gcd_u64_with_codec(code_type, 5500)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -258,9 +259,9 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
pub fn test_fastfield2() {
|
pub fn test_fastfield2() {
|
||||||
let test_fastfield = DynamicFastFieldReader::<u64>::from(vec![100, 200, 300]);
|
let test_fastfield = DynamicFastFieldReader::<u64>::from(vec![100, 200, 300]);
|
||||||
assert_eq!(test_fastfield.get(0), 100);
|
assert_eq!(test_fastfield.get_val(0), 100);
|
||||||
assert_eq!(test_fastfield.get(1), 200);
|
assert_eq!(test_fastfield.get_val(1), 200);
|
||||||
assert_eq!(test_fastfield.get(2), 300);
|
assert_eq!(test_fastfield.get_val(2), 300);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -325,9 +326,9 @@ mod tests {
|
|||||||
let len = file.len();
|
let len = file.len();
|
||||||
let test_fastfield = DynamicFastFieldReader::<DateTime>::open(file)?;
|
let test_fastfield = DynamicFastFieldReader::<DateTime>::open(file)?;
|
||||||
|
|
||||||
assert_eq!(test_fastfield.get(0), time1.truncate(precision));
|
assert_eq!(test_fastfield.get_val(0), time1.truncate(precision));
|
||||||
assert_eq!(test_fastfield.get(1), time2.truncate(precision));
|
assert_eq!(test_fastfield.get_val(1), time2.truncate(precision));
|
||||||
assert_eq!(test_fastfield.get(2), time3.truncate(precision));
|
assert_eq!(test_fastfield.get_val(2), time3.truncate(precision));
|
||||||
Ok(len)
|
Ok(len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,10 +28,10 @@ pub use self::error::{FastFieldNotAvailableError, Result};
|
|||||||
pub use self::facet_reader::FacetReader;
|
pub use self::facet_reader::FacetReader;
|
||||||
pub(crate) use self::gcd::{find_gcd, GCDReader, GCD_DEFAULT};
|
pub(crate) use self::gcd::{find_gcd, GCDReader, GCD_DEFAULT};
|
||||||
pub use self::multivalued::{MultiValuedFastFieldReader, MultiValuedFastFieldWriter};
|
pub use self::multivalued::{MultiValuedFastFieldReader, MultiValuedFastFieldWriter};
|
||||||
pub use self::reader::{DynamicFastFieldReader, FastFieldReader};
|
pub use self::reader::DynamicFastFieldReader;
|
||||||
pub use self::readers::FastFieldReaders;
|
pub use self::readers::FastFieldReaders;
|
||||||
pub(crate) use self::readers::{type_and_cardinality, FastType};
|
pub(crate) use self::readers::{type_and_cardinality, FastType};
|
||||||
pub use self::serializer::{CompositeFastFieldSerializer, FastFieldDataAccess, FastFieldStats};
|
pub use self::serializer::{Column, CompositeFastFieldSerializer, FastFieldStats};
|
||||||
pub use self::writer::{FastFieldsWriter, IntFastFieldWriter};
|
pub use self::writer::{FastFieldsWriter, IntFastFieldWriter};
|
||||||
use crate::schema::{Cardinality, FieldType, Type, Value};
|
use crate::schema::{Cardinality, FieldType, Type, Value};
|
||||||
use crate::{DateTime, DocId};
|
use crate::{DateTime, DocId};
|
||||||
@@ -298,9 +298,9 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
pub fn test_fastfield() {
|
pub fn test_fastfield() {
|
||||||
let test_fastfield = DynamicFastFieldReader::<u64>::from(vec![100, 200, 300]);
|
let test_fastfield = DynamicFastFieldReader::<u64>::from(vec![100, 200, 300]);
|
||||||
assert_eq!(test_fastfield.get(0), 100);
|
assert_eq!(test_fastfield.get_val(0u64), 100);
|
||||||
assert_eq!(test_fastfield.get(1), 200);
|
assert_eq!(test_fastfield.get_val(1u64), 200);
|
||||||
assert_eq!(test_fastfield.get(2), 300);
|
assert_eq!(test_fastfield.get_val(2u64), 300);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -330,9 +330,9 @@ mod tests {
|
|||||||
let composite_file = CompositeFile::open(&file)?;
|
let composite_file = CompositeFile::open(&file)?;
|
||||||
let file = composite_file.open_read(*FIELD).unwrap();
|
let file = composite_file.open_read(*FIELD).unwrap();
|
||||||
let fast_field_reader = DynamicFastFieldReader::<u64>::open(file)?;
|
let fast_field_reader = DynamicFastFieldReader::<u64>::open(file)?;
|
||||||
assert_eq!(fast_field_reader.get(0), 13u64);
|
assert_eq!(fast_field_reader.get_val(0), 13u64);
|
||||||
assert_eq!(fast_field_reader.get(1), 14u64);
|
assert_eq!(fast_field_reader.get_val(1), 14u64);
|
||||||
assert_eq!(fast_field_reader.get(2), 2u64);
|
assert_eq!(fast_field_reader.get_val(2), 2u64);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,15 +362,15 @@ mod tests {
|
|||||||
let fast_fields_composite = CompositeFile::open(&file)?;
|
let fast_fields_composite = CompositeFile::open(&file)?;
|
||||||
let data = fast_fields_composite.open_read(*FIELD).unwrap();
|
let data = fast_fields_composite.open_read(*FIELD).unwrap();
|
||||||
let fast_field_reader = DynamicFastFieldReader::<u64>::open(data)?;
|
let fast_field_reader = DynamicFastFieldReader::<u64>::open(data)?;
|
||||||
assert_eq!(fast_field_reader.get(0), 4u64);
|
assert_eq!(fast_field_reader.get_val(0), 4u64);
|
||||||
assert_eq!(fast_field_reader.get(1), 14_082_001u64);
|
assert_eq!(fast_field_reader.get_val(1), 14_082_001u64);
|
||||||
assert_eq!(fast_field_reader.get(2), 3_052u64);
|
assert_eq!(fast_field_reader.get_val(2), 3_052u64);
|
||||||
assert_eq!(fast_field_reader.get(3), 9002u64);
|
assert_eq!(fast_field_reader.get_val(3), 9002u64);
|
||||||
assert_eq!(fast_field_reader.get(4), 15_001u64);
|
assert_eq!(fast_field_reader.get_val(4), 15_001u64);
|
||||||
assert_eq!(fast_field_reader.get(5), 777u64);
|
assert_eq!(fast_field_reader.get_val(5), 777u64);
|
||||||
assert_eq!(fast_field_reader.get(6), 1_002u64);
|
assert_eq!(fast_field_reader.get_val(6), 1_002u64);
|
||||||
assert_eq!(fast_field_reader.get(7), 1_501u64);
|
assert_eq!(fast_field_reader.get_val(7), 1_501u64);
|
||||||
assert_eq!(fast_field_reader.get(8), 215u64);
|
assert_eq!(fast_field_reader.get_val(8), 215u64);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -399,7 +399,7 @@ mod tests {
|
|||||||
let data = fast_fields_composite.open_read(*FIELD).unwrap();
|
let data = fast_fields_composite.open_read(*FIELD).unwrap();
|
||||||
let fast_field_reader = DynamicFastFieldReader::<u64>::open(data)?;
|
let fast_field_reader = DynamicFastFieldReader::<u64>::open(data)?;
|
||||||
for doc in 0..10_000 {
|
for doc in 0..10_000 {
|
||||||
assert_eq!(fast_field_reader.get(doc), 100_000u64);
|
assert_eq!(fast_field_reader.get_val(doc), 100_000u64);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -430,10 +430,10 @@ mod tests {
|
|||||||
let fast_fields_composite = CompositeFile::open(&file)?;
|
let fast_fields_composite = CompositeFile::open(&file)?;
|
||||||
let data = fast_fields_composite.open_read(*FIELD).unwrap();
|
let data = fast_fields_composite.open_read(*FIELD).unwrap();
|
||||||
let fast_field_reader = DynamicFastFieldReader::<u64>::open(data)?;
|
let fast_field_reader = DynamicFastFieldReader::<u64>::open(data)?;
|
||||||
assert_eq!(fast_field_reader.get(0), 0u64);
|
assert_eq!(fast_field_reader.get_val(0), 0u64);
|
||||||
for doc in 1..10_001 {
|
for doc in 1..10_001 {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
fast_field_reader.get(doc),
|
fast_field_reader.get_val(doc),
|
||||||
5_000_000_000_000_000_000u64 + doc as u64 - 1u64
|
5_000_000_000_000_000_000u64 + doc as u64 - 1u64
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -475,10 +475,9 @@ mod tests {
|
|||||||
assert_eq!(fast_field_reader.min_value(), -100i64);
|
assert_eq!(fast_field_reader.min_value(), -100i64);
|
||||||
assert_eq!(fast_field_reader.max_value(), 9_999i64);
|
assert_eq!(fast_field_reader.max_value(), 9_999i64);
|
||||||
for (doc, i) in (-100i64..10_000i64).enumerate() {
|
for (doc, i) in (-100i64..10_000i64).enumerate() {
|
||||||
assert_eq!(fast_field_reader.get(doc as u32), i);
|
assert_eq!(fast_field_reader.get_val(doc as u64), i);
|
||||||
}
|
}
|
||||||
let mut buffer = vec![0i64; 100];
|
let buffer: Vec<i64> = fast_field_reader.get_range(53..154).collect();
|
||||||
fast_field_reader.get_range(53, &mut buffer[..]);
|
|
||||||
for i in 0..100 {
|
for i in 0..100 {
|
||||||
assert_eq!(buffer[i], -100i64 + 53i64 + i as i64);
|
assert_eq!(buffer[i], -100i64 + 53i64 + i as i64);
|
||||||
}
|
}
|
||||||
@@ -511,7 +510,7 @@ mod tests {
|
|||||||
let fast_fields_composite = CompositeFile::open(&file).unwrap();
|
let fast_fields_composite = CompositeFile::open(&file).unwrap();
|
||||||
let data = fast_fields_composite.open_read(i64_field).unwrap();
|
let data = fast_fields_composite.open_read(i64_field).unwrap();
|
||||||
let fast_field_reader = DynamicFastFieldReader::<i64>::open(data)?;
|
let fast_field_reader = DynamicFastFieldReader::<i64>::open(data)?;
|
||||||
assert_eq!(fast_field_reader.get(0u32), 0i64);
|
assert_eq!(fast_field_reader.get_val(0), 0i64);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -551,7 +550,7 @@ mod tests {
|
|||||||
let fast_field_reader = DynamicFastFieldReader::<u64>::open(data)?;
|
let fast_field_reader = DynamicFastFieldReader::<u64>::open(data)?;
|
||||||
|
|
||||||
for a in 0..n {
|
for a in 0..n {
|
||||||
assert_eq!(fast_field_reader.get(a as u32), permutation[a as usize]);
|
assert_eq!(fast_field_reader.get_val(a as u64), permutation[a as usize]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -607,9 +606,7 @@ mod tests {
|
|||||||
let mut all = vec![];
|
let mut all = vec![];
|
||||||
|
|
||||||
for doc in docs {
|
for doc in docs {
|
||||||
let mut out = vec![];
|
all.extend(ff.get_vals(doc));
|
||||||
ff.get_vals(doc, &mut out);
|
|
||||||
all.extend(out);
|
|
||||||
}
|
}
|
||||||
all
|
all
|
||||||
}
|
}
|
||||||
@@ -654,8 +651,7 @@ mod tests {
|
|||||||
vec![1, 0, 0, 0, 1, 2]
|
vec![1, 0, 0, 0, 1, 2]
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut out = vec![];
|
let out = text_fast_field.get_vals(3u32).collect::<Vec<_>>();
|
||||||
text_fast_field.get_vals(3, &mut out);
|
|
||||||
assert_eq!(out, vec![0, 1]);
|
assert_eq!(out, vec![0, 1]);
|
||||||
|
|
||||||
let inverted_index = segment_reader.inverted_index(text_field)?;
|
let inverted_index = segment_reader.inverted_index(text_field)?;
|
||||||
@@ -840,22 +836,20 @@ mod tests {
|
|||||||
let fast_fields = segment_reader.fast_fields();
|
let fast_fields = segment_reader.fast_fields();
|
||||||
let date_fast_field = fast_fields.date(date_field).unwrap();
|
let date_fast_field = fast_fields.date(date_field).unwrap();
|
||||||
let dates_fast_field = fast_fields.dates(multi_date_field).unwrap();
|
let dates_fast_field = fast_fields.dates(multi_date_field).unwrap();
|
||||||
let mut dates = vec![];
|
|
||||||
{
|
{
|
||||||
assert_eq!(date_fast_field.get(0u32).into_timestamp_micros(), 1i64);
|
assert_eq!(date_fast_field.get_val(0).into_timestamp_micros(), 1i64);
|
||||||
dates_fast_field.get_vals(0u32, &mut dates);
|
let dates = dates_fast_field.get_vals(0u32).collect::<Vec<_>>();
|
||||||
assert_eq!(dates.len(), 2);
|
assert_eq!(dates.len(), 2);
|
||||||
assert_eq!(dates[0].into_timestamp_micros(), 2i64);
|
assert_eq!(dates[0].into_timestamp_micros(), 2i64);
|
||||||
assert_eq!(dates[1].into_timestamp_micros(), 3i64);
|
assert_eq!(dates[1].into_timestamp_micros(), 3i64);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
assert_eq!(date_fast_field.get(1u32).into_timestamp_micros(), 4i64);
|
assert_eq!(date_fast_field.get_val(1).into_timestamp_micros(), 4i64);
|
||||||
dates_fast_field.get_vals(1u32, &mut dates);
|
assert!(dates_fast_field.get_vals(1u32).next().is_none());
|
||||||
assert!(dates.is_empty());
|
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
assert_eq!(date_fast_field.get(2u32).into_timestamp_micros(), 0i64);
|
assert_eq!(date_fast_field.get_val(2).into_timestamp_micros(), 0i64);
|
||||||
dates_fast_field.get_vals(2u32, &mut dates);
|
let dates = dates_fast_field.get_vals(2u32).collect::<Vec<_>>();
|
||||||
assert_eq!(dates.len(), 2);
|
assert_eq!(dates.len(), 2);
|
||||||
assert_eq!(dates[0].into_timestamp_micros(), 5i64);
|
assert_eq!(dates[0].into_timestamp_micros(), 5i64);
|
||||||
assert_eq!(dates[1].into_timestamp_micros(), 6i64);
|
assert_eq!(dates[1].into_timestamp_micros(), 6i64);
|
||||||
@@ -866,10 +860,10 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
pub fn test_fastfield_bool() {
|
pub fn test_fastfield_bool() {
|
||||||
let test_fastfield = DynamicFastFieldReader::<bool>::from(vec![true, false, true, false]);
|
let test_fastfield = DynamicFastFieldReader::<bool>::from(vec![true, false, true, false]);
|
||||||
assert_eq!(test_fastfield.get(0), true);
|
assert_eq!(test_fastfield.get_val(0), true);
|
||||||
assert_eq!(test_fastfield.get(1), false);
|
assert_eq!(test_fastfield.get_val(1), false);
|
||||||
assert_eq!(test_fastfield.get(2), true);
|
assert_eq!(test_fastfield.get_val(2), true);
|
||||||
assert_eq!(test_fastfield.get(3), false);
|
assert_eq!(test_fastfield.get_val(3), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -900,10 +894,10 @@ mod tests {
|
|||||||
let composite_file = CompositeFile::open(&file)?;
|
let composite_file = CompositeFile::open(&file)?;
|
||||||
let file = composite_file.open_read(field).unwrap();
|
let file = composite_file.open_read(field).unwrap();
|
||||||
let fast_field_reader = DynamicFastFieldReader::<bool>::open(file)?;
|
let fast_field_reader = DynamicFastFieldReader::<bool>::open(file)?;
|
||||||
assert_eq!(fast_field_reader.get(0), true);
|
assert_eq!(fast_field_reader.get_val(0), true);
|
||||||
assert_eq!(fast_field_reader.get(1), false);
|
assert_eq!(fast_field_reader.get_val(1), false);
|
||||||
assert_eq!(fast_field_reader.get(2), true);
|
assert_eq!(fast_field_reader.get_val(2), true);
|
||||||
assert_eq!(fast_field_reader.get(3), false);
|
assert_eq!(fast_field_reader.get_val(3), false);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -937,8 +931,8 @@ mod tests {
|
|||||||
let file = composite_file.open_read(field).unwrap();
|
let file = composite_file.open_read(field).unwrap();
|
||||||
let fast_field_reader = DynamicFastFieldReader::<bool>::open(file)?;
|
let fast_field_reader = DynamicFastFieldReader::<bool>::open(file)?;
|
||||||
for i in 0..25 {
|
for i in 0..25 {
|
||||||
assert_eq!(fast_field_reader.get(i * 2), true);
|
assert_eq!(fast_field_reader.get_val(i * 2), true);
|
||||||
assert_eq!(fast_field_reader.get(i * 2 + 1), false);
|
assert_eq!(fast_field_reader.get_val(i * 2 + 1), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -970,7 +964,7 @@ mod tests {
|
|||||||
let composite_file = CompositeFile::open(&file)?;
|
let composite_file = CompositeFile::open(&file)?;
|
||||||
let file = composite_file.open_read(field).unwrap();
|
let file = composite_file.open_read(field).unwrap();
|
||||||
let fast_field_reader = DynamicFastFieldReader::<bool>::open(file)?;
|
let fast_field_reader = DynamicFastFieldReader::<bool>::open(file)?;
|
||||||
assert_eq!(fast_field_reader.get(0), false);
|
assert_eq!(fast_field_reader.get_val(0), false);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -981,13 +975,74 @@ mod bench {
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
|
use fastfield_codecs::Column;
|
||||||
use test::{self, Bencher};
|
use test::{self, Bencher};
|
||||||
|
|
||||||
use super::tests::{generate_permutation, FIELD, SCHEMA};
|
use super::tests::{generate_permutation, FIELD, SCHEMA};
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::directory::{CompositeFile, Directory, RamDirectory, WritePtr};
|
use crate::directory::{CompositeFile, Directory, RamDirectory, WritePtr};
|
||||||
use crate::fastfield::tests::generate_permutation_gcd;
|
use crate::fastfield::tests::generate_permutation_gcd;
|
||||||
use crate::fastfield::FastFieldReader;
|
use crate::schema::{NumericOptions, Schema};
|
||||||
|
use crate::Document;
|
||||||
|
|
||||||
|
fn multi_values(num_docs: usize, vals_per_doc: usize) -> Vec<Vec<u64>> {
|
||||||
|
let mut vals = vec![];
|
||||||
|
for _i in 0..num_docs {
|
||||||
|
let mut block = vec![];
|
||||||
|
for j in 0..vals_per_doc {
|
||||||
|
block.push(j as u64);
|
||||||
|
}
|
||||||
|
vals.push(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
vals
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_multi_value_fflookup(b: &mut Bencher) {
|
||||||
|
let num_docs = 100_000;
|
||||||
|
|
||||||
|
let path = Path::new("test");
|
||||||
|
let directory: RamDirectory = RamDirectory::create();
|
||||||
|
{
|
||||||
|
let options = NumericOptions::default().set_fast(Cardinality::MultiValues);
|
||||||
|
let mut schema_builder = Schema::builder();
|
||||||
|
let field = schema_builder.add_u64_field("field", options);
|
||||||
|
let schema = schema_builder.build();
|
||||||
|
|
||||||
|
let write: WritePtr = directory.open_write(Path::new("test")).unwrap();
|
||||||
|
let mut serializer = CompositeFastFieldSerializer::from_write(write).unwrap();
|
||||||
|
let mut fast_field_writers = FastFieldsWriter::from_schema(&schema);
|
||||||
|
for block in &multi_values(num_docs, 3) {
|
||||||
|
let mut doc = Document::new();
|
||||||
|
for val in block {
|
||||||
|
doc.add_u64(field, *val);
|
||||||
|
}
|
||||||
|
fast_field_writers.add_document(&doc);
|
||||||
|
}
|
||||||
|
fast_field_writers
|
||||||
|
.serialize(&mut serializer, &HashMap::new(), None)
|
||||||
|
.unwrap();
|
||||||
|
serializer.close().unwrap();
|
||||||
|
}
|
||||||
|
let file = directory.open_read(&path).unwrap();
|
||||||
|
{
|
||||||
|
let fast_fields_composite = CompositeFile::open(&file).unwrap();
|
||||||
|
let data_idx = fast_fields_composite.open_read_with_idx(*FIELD, 0).unwrap();
|
||||||
|
let idx_reader = DynamicFastFieldReader::<u64>::open(data_idx).unwrap();
|
||||||
|
|
||||||
|
let data_vals = fast_fields_composite.open_read_with_idx(*FIELD, 1).unwrap();
|
||||||
|
let vals_reader = DynamicFastFieldReader::<u64>::open(data_vals).unwrap();
|
||||||
|
let fast_field_reader = MultiValuedFastFieldReader::open(idx_reader, vals_reader);
|
||||||
|
b.iter(|| {
|
||||||
|
let mut sum = 0u64;
|
||||||
|
for i in 0u32..num_docs as u32 {
|
||||||
|
sum += fast_field_reader.get_vals(i).sum::<u64>();
|
||||||
|
}
|
||||||
|
sum
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_intfastfield_linear_veclookup(b: &mut Bencher) {
|
fn bench_intfastfield_linear_veclookup(b: &mut Bencher) {
|
||||||
@@ -1042,7 +1097,7 @@ mod bench {
|
|||||||
let n = test::black_box(7000u32);
|
let n = test::black_box(7000u32);
|
||||||
let mut a = 0u64;
|
let mut a = 0u64;
|
||||||
for i in (0u32..n / 7).map(|val| val * 7) {
|
for i in (0u32..n / 7).map(|val| val * 7) {
|
||||||
a ^= fast_field_reader.get(i);
|
a ^= fast_field_reader.get_val(i as u64);
|
||||||
}
|
}
|
||||||
a
|
a
|
||||||
});
|
});
|
||||||
@@ -1074,8 +1129,8 @@ mod bench {
|
|||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut a = 0u32;
|
let mut a = 0u32;
|
||||||
for i in 0u32..permutation.len() as u32 {
|
for i in 0u64..permutation.len() as u64 {
|
||||||
a = fast_field_reader.get(i) as u32;
|
a = fast_field_reader.get_val(i) as u32;
|
||||||
}
|
}
|
||||||
a
|
a
|
||||||
});
|
});
|
||||||
@@ -1108,7 +1163,7 @@ mod bench {
|
|||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let mut a = 0u32;
|
let mut a = 0u32;
|
||||||
for i in 0u32..permutation.len() as u32 {
|
for i in 0u32..permutation.len() as u32 {
|
||||||
a = fast_field_reader.get(i) as u32;
|
a = fast_field_reader.get_val(i as u64) as u32;
|
||||||
}
|
}
|
||||||
a
|
a
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -36,19 +36,17 @@ mod tests {
|
|||||||
|
|
||||||
let searcher = index.reader()?.searcher();
|
let searcher = index.reader()?.searcher();
|
||||||
let segment_reader = searcher.segment_reader(0);
|
let segment_reader = searcher.segment_reader(0);
|
||||||
let mut vals = Vec::new();
|
|
||||||
let multi_value_reader = segment_reader.fast_fields().u64s(field)?;
|
let multi_value_reader = segment_reader.fast_fields().u64s(field)?;
|
||||||
{
|
{
|
||||||
multi_value_reader.get_vals(2, &mut vals);
|
let vals = multi_value_reader.get_vals(2u32).collect::<Vec<_>>();
|
||||||
assert_eq!(&vals, &[4u64]);
|
assert_eq!(&vals, &[4u64]);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
multi_value_reader.get_vals(0, &mut vals);
|
let vals = multi_value_reader.get_vals(0u32).collect::<Vec<_>>();
|
||||||
assert_eq!(&vals, &[1u64, 3u64]);
|
assert_eq!(&vals, &[1u64, 3u64]);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
multi_value_reader.get_vals(1, &mut vals);
|
assert!(multi_value_reader.get_vals(1u32).next().is_none());
|
||||||
assert!(vals.is_empty());
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -213,15 +211,13 @@ mod tests {
|
|||||||
|
|
||||||
let searcher = index.reader()?.searcher();
|
let searcher = index.reader()?.searcher();
|
||||||
let segment_reader = searcher.segment_reader(0);
|
let segment_reader = searcher.segment_reader(0);
|
||||||
let mut vals = Vec::new();
|
|
||||||
let multi_value_reader = segment_reader.fast_fields().i64s(field).unwrap();
|
let multi_value_reader = segment_reader.fast_fields().i64s(field).unwrap();
|
||||||
multi_value_reader.get_vals(2, &mut vals);
|
let vals = multi_value_reader.get_vals(2u32).collect::<Vec<_>>();
|
||||||
assert_eq!(&vals, &[-4i64]);
|
assert_eq!(&vals, &[-4i64]);
|
||||||
multi_value_reader.get_vals(0, &mut vals);
|
let vals = multi_value_reader.get_vals(0u32).collect::<Vec<_>>();
|
||||||
assert_eq!(&vals, &[1i64, 3i64]);
|
assert_eq!(&vals, &[1i64, 3i64]);
|
||||||
multi_value_reader.get_vals(1, &mut vals);
|
assert!(multi_value_reader.get_vals(1u32).next().is_none());
|
||||||
assert!(vals.is_empty());
|
let vals = multi_value_reader.get_vals(3u32).collect::<Vec<_>>();
|
||||||
multi_value_reader.get_vals(3, &mut vals);
|
|
||||||
assert_eq!(&vals, &[-5i64, -20i64, 1i64]);
|
assert_eq!(&vals, &[-5i64, -20i64, 1i64]);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -245,15 +241,13 @@ mod tests {
|
|||||||
|
|
||||||
let searcher = index.reader()?.searcher();
|
let searcher = index.reader()?.searcher();
|
||||||
let segment_reader = searcher.segment_reader(0);
|
let segment_reader = searcher.segment_reader(0);
|
||||||
let mut vals = Vec::new();
|
|
||||||
let multi_value_reader = segment_reader.fast_fields().bools(bool_field).unwrap();
|
let multi_value_reader = segment_reader.fast_fields().bools(bool_field).unwrap();
|
||||||
multi_value_reader.get_vals(2, &mut vals);
|
let vals = multi_value_reader.get_vals(2u32).collect::<Vec<_>>();
|
||||||
assert_eq!(&vals, &[false]);
|
assert_eq!(&vals, &[false]);
|
||||||
multi_value_reader.get_vals(0, &mut vals);
|
let vals = multi_value_reader.get_vals(0u32).collect::<Vec<_>>();
|
||||||
assert_eq!(&vals, &[true, false]);
|
assert_eq!(&vals, &[true, false]);
|
||||||
multi_value_reader.get_vals(1, &mut vals);
|
assert!(multi_value_reader.get_vals(1u32).next().is_none());
|
||||||
assert!(vals.is_empty());
|
let vals = multi_value_reader.get_vals(3u32).collect::<Vec<_>>();
|
||||||
multi_value_reader.get_vals(3, &mut vals);
|
|
||||||
assert_eq!(&vals, &[true, true, false]);
|
assert_eq!(&vals, &[true, true, false]);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
use crate::fastfield::{DynamicFastFieldReader, FastFieldReader, FastValue, MultiValueLength};
|
use fastfield_codecs::Column;
|
||||||
|
|
||||||
|
use crate::fastfield::{DynamicFastFieldReader, FastValue, MultiValueLength};
|
||||||
use crate::DocId;
|
use crate::DocId;
|
||||||
|
|
||||||
/// Reader for a multivalued `u64` fast field.
|
/// Reader for a multivalued `u64` fast field.
|
||||||
@@ -16,7 +18,9 @@ pub struct MultiValuedFastFieldReader<Item: FastValue> {
|
|||||||
vals_reader: DynamicFastFieldReader<Item>,
|
vals_reader: DynamicFastFieldReader<Item>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Item: FastValue> MultiValuedFastFieldReader<Item> {
|
impl<Item: FastValue> MultiValuedFastFieldReader<Item>
|
||||||
|
where DynamicFastFieldReader<Item>: Column<Item>
|
||||||
|
{
|
||||||
pub(crate) fn open(
|
pub(crate) fn open(
|
||||||
idx_reader: DynamicFastFieldReader<u64>,
|
idx_reader: DynamicFastFieldReader<u64>,
|
||||||
vals_reader: DynamicFastFieldReader<Item>,
|
vals_reader: DynamicFastFieldReader<Item>,
|
||||||
@@ -31,24 +35,17 @@ impl<Item: FastValue> MultiValuedFastFieldReader<Item> {
|
|||||||
/// to the given document are `start..end`.
|
/// to the given document are `start..end`.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn range(&self, doc: DocId) -> Range<u64> {
|
fn range(&self, doc: DocId) -> Range<u64> {
|
||||||
let start = self.idx_reader.get(doc);
|
let idx = doc as u64;
|
||||||
let end = self.idx_reader.get(doc + 1);
|
let start = self.idx_reader.get_val(idx);
|
||||||
|
let end = self.idx_reader.get_val(idx + 1);
|
||||||
start..end
|
start..end
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the array of values associated to the given `doc`.
|
/// Returns the array of values associated to the given `doc`.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_vals_for_range(&self, range: Range<u64>, vals: &mut Vec<Item>) {
|
pub fn get_vals(&self, doc: DocId) -> impl Iterator<Item = Item> + '_ {
|
||||||
let len = (range.end - range.start) as usize;
|
|
||||||
vals.resize(len, Item::make_zero());
|
|
||||||
self.vals_reader.get_range(range.start, &mut vals[..]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the array of values associated to the given `doc`.
|
|
||||||
#[inline]
|
|
||||||
pub fn get_vals(&self, doc: DocId, vals: &mut Vec<Item>) {
|
|
||||||
let range = self.range(doc);
|
let range = self.range(doc);
|
||||||
self.get_vals_for_range(range, vals);
|
self.vals_reader.get_range(range)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the minimum value for this fast field.
|
/// Returns the minimum value for this fast field.
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use common::BinarySerializable;
|
|||||||
use fastfield_codecs::bitpacked::{BitpackedCodec, BitpackedReader};
|
use fastfield_codecs::bitpacked::{BitpackedCodec, BitpackedReader};
|
||||||
use fastfield_codecs::blockwise_linear::{BlockwiseLinearCodec, BlockwiseLinearReader};
|
use fastfield_codecs::blockwise_linear::{BlockwiseLinearCodec, BlockwiseLinearReader};
|
||||||
use fastfield_codecs::linear::{LinearCodec, LinearReader};
|
use fastfield_codecs::linear::{LinearCodec, LinearReader};
|
||||||
use fastfield_codecs::{FastFieldCodec, FastFieldCodecType, FastFieldDataAccess};
|
use fastfield_codecs::{Column, FastFieldCodec, FastFieldCodecType};
|
||||||
|
|
||||||
use super::gcd::open_gcd_from_bytes;
|
use super::gcd::open_gcd_from_bytes;
|
||||||
use super::FastValue;
|
use super::FastValue;
|
||||||
@@ -14,48 +14,6 @@ use crate::directory::{CompositeFile, Directory, FileSlice, OwnedBytes, RamDirec
|
|||||||
use crate::error::DataCorruption;
|
use crate::error::DataCorruption;
|
||||||
use crate::fastfield::{CompositeFastFieldSerializer, FastFieldsWriter, GCDReader};
|
use crate::fastfield::{CompositeFastFieldSerializer, FastFieldsWriter, GCDReader};
|
||||||
use crate::schema::{Schema, FAST};
|
use crate::schema::{Schema, FAST};
|
||||||
use crate::DocId;
|
|
||||||
|
|
||||||
/// FastFieldReader is the trait to access fast field data.
|
|
||||||
pub trait FastFieldReader<Item: FastValue>: Clone {
|
|
||||||
/// Return the value associated to the given document.
|
|
||||||
///
|
|
||||||
/// This accessor should return as fast as possible.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// May panic if `doc` is greater than the segment
|
|
||||||
fn get(&self, doc: DocId) -> Item;
|
|
||||||
|
|
||||||
/// Fills an output buffer with the fast field values
|
|
||||||
/// associated with the `DocId` going from
|
|
||||||
/// `start` to `start + output.len()`.
|
|
||||||
///
|
|
||||||
/// Regardless of the type of `Item`, this method works
|
|
||||||
/// - transmuting the output array
|
|
||||||
/// - extracting the `Item`s as if they were `u64`
|
|
||||||
/// - possibly converting the `u64` value to the right type.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// May panic if `start + output.len()` is greater than
|
|
||||||
/// the segment's `maxdoc`.
|
|
||||||
fn get_range(&self, start: u64, output: &mut [Item]);
|
|
||||||
|
|
||||||
/// Returns the minimum value for this fast field.
|
|
||||||
///
|
|
||||||
/// The min value does not take in account of possible
|
|
||||||
/// deleted document, and should be considered as a lower bound
|
|
||||||
/// of the actual minimum value.
|
|
||||||
fn min_value(&self) -> Item;
|
|
||||||
|
|
||||||
/// Returns the maximum value for this fast field.
|
|
||||||
///
|
|
||||||
/// The max value does not take in account of possible
|
|
||||||
/// deleted document, and should be considered as an upper bound
|
|
||||||
/// of the actual maximum value.
|
|
||||||
fn max_value(&self) -> Item;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
/// DynamicFastFieldReader wraps different readers to access
|
/// DynamicFastFieldReader wraps different readers to access
|
||||||
@@ -82,40 +40,39 @@ impl<Item: FastValue> DynamicFastFieldReader<Item> {
|
|||||||
mut bytes: OwnedBytes,
|
mut bytes: OwnedBytes,
|
||||||
codec_type: FastFieldCodecType,
|
codec_type: FastFieldCodecType,
|
||||||
) -> crate::Result<DynamicFastFieldReader<Item>> {
|
) -> crate::Result<DynamicFastFieldReader<Item>> {
|
||||||
let reader = match codec_type {
|
let reader =
|
||||||
FastFieldCodecType::Bitpacked => {
|
match codec_type {
|
||||||
DynamicFastFieldReader::Bitpacked(BitpackedCodec::open_from_bytes(bytes)?.into())
|
FastFieldCodecType::Bitpacked => DynamicFastFieldReader::Bitpacked(
|
||||||
}
|
BitpackedCodec::open_from_bytes(bytes)?.into(),
|
||||||
FastFieldCodecType::Linear => {
|
),
|
||||||
DynamicFastFieldReader::Linear(LinearCodec::open_from_bytes(bytes)?.into())
|
FastFieldCodecType::Linear => {
|
||||||
}
|
DynamicFastFieldReader::Linear(LinearCodec::open_from_bytes(bytes)?.into())
|
||||||
FastFieldCodecType::BlockwiseLinear => DynamicFastFieldReader::BlockwiseLinear(
|
}
|
||||||
BlockwiseLinearCodec::open_from_bytes(bytes)?.into(),
|
FastFieldCodecType::BlockwiseLinear => DynamicFastFieldReader::BlockwiseLinear(
|
||||||
),
|
BlockwiseLinearCodec::open_from_bytes(bytes)?.into(),
|
||||||
FastFieldCodecType::Gcd => {
|
),
|
||||||
let codec_type = FastFieldCodecType::deserialize(&mut bytes)?;
|
FastFieldCodecType::Gcd => {
|
||||||
match codec_type {
|
let codec_type = FastFieldCodecType::deserialize(&mut bytes)?;
|
||||||
FastFieldCodecType::Bitpacked => DynamicFastFieldReader::BitpackedGCD(
|
match codec_type {
|
||||||
open_gcd_from_bytes::<BitpackedCodec>(bytes)?.into(),
|
FastFieldCodecType::Bitpacked => DynamicFastFieldReader::BitpackedGCD(
|
||||||
),
|
open_gcd_from_bytes::<BitpackedCodec>(bytes)?.into(),
|
||||||
FastFieldCodecType::Linear => DynamicFastFieldReader::LinearGCD(
|
),
|
||||||
open_gcd_from_bytes::<LinearCodec>(bytes)?.into(),
|
FastFieldCodecType::Linear => DynamicFastFieldReader::LinearGCD(
|
||||||
),
|
open_gcd_from_bytes::<LinearCodec>(bytes)?.into(),
|
||||||
FastFieldCodecType::BlockwiseLinear => {
|
),
|
||||||
DynamicFastFieldReader::BlockwiseLinearGCD(
|
FastFieldCodecType::BlockwiseLinear => {
|
||||||
open_gcd_from_bytes::<BlockwiseLinearCodec>(bytes)?.into(),
|
DynamicFastFieldReader::BlockwiseLinearGCD(
|
||||||
)
|
open_gcd_from_bytes::<BlockwiseLinearCodec>(bytes)?.into(),
|
||||||
}
|
)
|
||||||
FastFieldCodecType::Gcd => {
|
}
|
||||||
return Err(DataCorruption::comment_only(
|
FastFieldCodecType::Gcd => return Err(DataCorruption::comment_only(
|
||||||
"Gcd codec wrapped into another gcd codec. This combination is not \
|
"Gcd codec wrapped into another gcd codec. This combination is not \
|
||||||
allowed.",
|
allowed.",
|
||||||
)
|
)
|
||||||
.into())
|
.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
Ok(reader)
|
Ok(reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,27 +84,16 @@ impl<Item: FastValue> DynamicFastFieldReader<Item> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Item: FastValue> FastFieldReader<Item> for DynamicFastFieldReader<Item> {
|
impl<Item: FastValue> Column<Item> for DynamicFastFieldReader<Item> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get(&self, doc: DocId) -> Item {
|
fn get_val(&self, idx: u64) -> Item {
|
||||||
match self {
|
match self {
|
||||||
Self::Bitpacked(reader) => reader.get(doc),
|
Self::Bitpacked(reader) => reader.get_val(idx),
|
||||||
Self::Linear(reader) => reader.get(doc),
|
Self::Linear(reader) => reader.get_val(idx),
|
||||||
Self::BlockwiseLinear(reader) => reader.get(doc),
|
Self::BlockwiseLinear(reader) => reader.get_val(idx),
|
||||||
Self::BitpackedGCD(reader) => reader.get(doc),
|
Self::BitpackedGCD(reader) => reader.get_val(idx),
|
||||||
Self::LinearGCD(reader) => reader.get(doc),
|
Self::LinearGCD(reader) => reader.get_val(idx),
|
||||||
Self::BlockwiseLinearGCD(reader) => reader.get(doc),
|
Self::BlockwiseLinearGCD(reader) => reader.get_val(idx),
|
||||||
}
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn get_range(&self, start: u64, output: &mut [Item]) {
|
|
||||||
match self {
|
|
||||||
Self::Bitpacked(reader) => reader.get_range(start, output),
|
|
||||||
Self::Linear(reader) => reader.get_range(start, output),
|
|
||||||
Self::BlockwiseLinear(reader) => reader.get_range(start, output),
|
|
||||||
Self::BitpackedGCD(reader) => reader.get_range(start, output),
|
|
||||||
Self::LinearGCD(reader) => reader.get_range(start, output),
|
|
||||||
Self::BlockwiseLinearGCD(reader) => reader.get_range(start, output),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn min_value(&self) -> Item {
|
fn min_value(&self) -> Item {
|
||||||
@@ -170,6 +116,17 @@ impl<Item: FastValue> FastFieldReader<Item> for DynamicFastFieldReader<Item> {
|
|||||||
Self::BlockwiseLinearGCD(reader) => reader.max_value(),
|
Self::BlockwiseLinearGCD(reader) => reader.max_value(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn num_vals(&self) -> u64 {
|
||||||
|
match self {
|
||||||
|
Self::Bitpacked(reader) => reader.num_vals(),
|
||||||
|
Self::Linear(reader) => reader.num_vals(),
|
||||||
|
Self::BlockwiseLinear(reader) => reader.num_vals(),
|
||||||
|
Self::BitpackedGCD(reader) => reader.num_vals(),
|
||||||
|
Self::LinearGCD(reader) => reader.num_vals(),
|
||||||
|
Self::BlockwiseLinearGCD(reader) => reader.num_vals(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrapper for accessing a fastfield.
|
/// Wrapper for accessing a fastfield.
|
||||||
@@ -192,35 +149,15 @@ impl<Item: FastValue, CodecReader> From<CodecReader>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Item: FastValue, D: FastFieldDataAccess> FastFieldReaderCodecWrapper<Item, D> {
|
impl<Item: FastValue, D: Column> FastFieldReaderCodecWrapper<Item, D> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn get_u64(&self, doc: u64) -> Item {
|
pub(crate) fn get_u64(&self, idx: u64) -> Item {
|
||||||
let data = self.reader.get_val(doc);
|
let data = self.reader.get_val(idx);
|
||||||
Item::from_u64(data)
|
Item::from_u64(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internally `multivalued` also use SingleValue Fast fields.
|
|
||||||
/// It works as follows... A first column contains the list of start index
|
|
||||||
/// for each document, a second column contains the actual values.
|
|
||||||
///
|
|
||||||
/// The values associated to a given doc, are then
|
|
||||||
/// `second_column[first_column.get(doc)..first_column.get(doc+1)]`.
|
|
||||||
///
|
|
||||||
/// Which means single value fast field reader can be indexed internally with
|
|
||||||
/// something different from a `DocId`. For this use case, we want to use `u64`
|
|
||||||
/// values.
|
|
||||||
///
|
|
||||||
/// See `get_range` for an actual documentation about this method.
|
|
||||||
pub(crate) fn get_range_u64(&self, start: u64, output: &mut [Item]) {
|
|
||||||
for (i, out) in output.iter_mut().enumerate() {
|
|
||||||
*out = self.get_u64(start + (i as u64));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Item: FastValue, C: FastFieldDataAccess + Clone> FastFieldReader<Item>
|
impl<Item: FastValue, C: Column + Clone> Column<Item> for FastFieldReaderCodecWrapper<Item, C> {
|
||||||
for FastFieldReaderCodecWrapper<Item, C>
|
|
||||||
{
|
|
||||||
/// Return the value associated to the given document.
|
/// Return the value associated to the given document.
|
||||||
///
|
///
|
||||||
/// This accessor should return as fast as possible.
|
/// This accessor should return as fast as possible.
|
||||||
@@ -229,25 +166,8 @@ impl<Item: FastValue, C: FastFieldDataAccess + Clone> FastFieldReader<Item>
|
|||||||
///
|
///
|
||||||
/// May panic if `doc` is greater than the segment
|
/// May panic if `doc` is greater than the segment
|
||||||
// `maxdoc`.
|
// `maxdoc`.
|
||||||
fn get(&self, doc: DocId) -> Item {
|
fn get_val(&self, idx: u64) -> Item {
|
||||||
self.get_u64(u64::from(doc))
|
self.get_u64(idx)
|
||||||
}
|
|
||||||
|
|
||||||
/// Fills an output buffer with the fast field values
|
|
||||||
/// associated with the `DocId` going from
|
|
||||||
/// `start` to `start + output.len()`.
|
|
||||||
///
|
|
||||||
/// Regardless of the type of `Item`, this method works
|
|
||||||
/// - transmuting the output array
|
|
||||||
/// - extracting the `Item`s as if they were `u64`
|
|
||||||
/// - possibly converting the `u64` value to the right type.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// May panic if `start + output.len()` is greater than
|
|
||||||
/// the segment's `maxdoc`.
|
|
||||||
fn get_range(&self, start: u64, output: &mut [Item]) {
|
|
||||||
self.get_range_u64(start, output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the minimum value for this fast field.
|
/// Returns the minimum value for this fast field.
|
||||||
@@ -267,6 +187,10 @@ impl<Item: FastValue, C: FastFieldDataAccess + Clone> FastFieldReader<Item>
|
|||||||
fn max_value(&self) -> Item {
|
fn max_value(&self) -> Item {
|
||||||
Item::from_u64(self.reader.max_value())
|
Item::from_u64(self.reader.max_value())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn num_vals(&self) -> u64 {
|
||||||
|
self.reader.num_vals()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Item: FastValue> From<Vec<Item>> for DynamicFastFieldReader<Item> {
|
impl<Item: FastValue> From<Vec<Item>> for DynamicFastFieldReader<Item> {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ pub use fastfield_codecs::bitpacked::{BitpackedCodec, BitpackedSerializerLegacy}
|
|||||||
use fastfield_codecs::blockwise_linear::BlockwiseLinearCodec;
|
use fastfield_codecs::blockwise_linear::BlockwiseLinearCodec;
|
||||||
use fastfield_codecs::linear::LinearCodec;
|
use fastfield_codecs::linear::LinearCodec;
|
||||||
use fastfield_codecs::FastFieldCodecType;
|
use fastfield_codecs::FastFieldCodecType;
|
||||||
pub use fastfield_codecs::{FastFieldCodec, FastFieldDataAccess, FastFieldStats};
|
pub use fastfield_codecs::{Column, FastFieldCodec, FastFieldStats};
|
||||||
|
|
||||||
use super::{find_gcd, ALL_CODECS, GCD_DEFAULT};
|
use super::{find_gcd, ALL_CODECS, GCD_DEFAULT};
|
||||||
use crate::directory::{CompositeWrite, WritePtr};
|
use crate::directory::{CompositeWrite, WritePtr};
|
||||||
@@ -64,15 +64,13 @@ impl From<FastFieldCodecType> for FastFieldCodecEnableCheck {
|
|||||||
|
|
||||||
// use this, when this is merged and stabilized explicit_generic_args_with_impl_trait
|
// use this, when this is merged and stabilized explicit_generic_args_with_impl_trait
|
||||||
// https://github.com/rust-lang/rust/pull/86176
|
// https://github.com/rust-lang/rust/pull/86176
|
||||||
fn codec_estimation<C: FastFieldCodec, A: FastFieldDataAccess>(
|
fn codec_estimation<C: FastFieldCodec, D: Column>(
|
||||||
fastfield_accessor: &A,
|
fastfield_accessor: &D,
|
||||||
estimations: &mut Vec<(f32, FastFieldCodecType)>,
|
estimations: &mut Vec<(f32, FastFieldCodecType)>,
|
||||||
) {
|
) {
|
||||||
if !C::is_applicable(fastfield_accessor) {
|
if let Some(ratio) = C::estimate(fastfield_accessor) {
|
||||||
return;
|
estimations.push((ratio, C::CODEC_TYPE));
|
||||||
}
|
}
|
||||||
let ratio = C::estimate(fastfield_accessor);
|
|
||||||
estimations.push((ratio, C::CODEC_TYPE));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompositeFastFieldSerializer {
|
impl CompositeFastFieldSerializer {
|
||||||
@@ -99,7 +97,7 @@ impl CompositeFastFieldSerializer {
|
|||||||
pub fn create_auto_detect_u64_fast_field(
|
pub fn create_auto_detect_u64_fast_field(
|
||||||
&mut self,
|
&mut self,
|
||||||
field: Field,
|
field: Field,
|
||||||
fastfield_accessor: impl FastFieldDataAccess,
|
fastfield_accessor: impl Column,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
self.create_auto_detect_u64_fast_field_with_idx(field, fastfield_accessor, 0)
|
self.create_auto_detect_u64_fast_field_with_idx(field, fastfield_accessor, 0)
|
||||||
}
|
}
|
||||||
@@ -119,7 +117,7 @@ impl CompositeFastFieldSerializer {
|
|||||||
pub fn create_auto_detect_u64_fast_field_with_idx(
|
pub fn create_auto_detect_u64_fast_field_with_idx(
|
||||||
&mut self,
|
&mut self,
|
||||||
field: Field,
|
field: Field,
|
||||||
fastfield_accessor: impl FastFieldDataAccess,
|
fastfield_accessor: impl Column,
|
||||||
idx: usize,
|
idx: usize,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
let min_value = fastfield_accessor.min_value();
|
let min_value = fastfield_accessor.min_value();
|
||||||
@@ -138,7 +136,7 @@ impl CompositeFastFieldSerializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Self::write_header(field_write, FastFieldCodecType::Gcd)?;
|
Self::write_header(field_write, FastFieldCodecType::Gcd)?;
|
||||||
struct GCDWrappedFFAccess<T: FastFieldDataAccess> {
|
struct GCDWrappedFFAccess<T: Column> {
|
||||||
fastfield_accessor: T,
|
fastfield_accessor: T,
|
||||||
base_value: u64,
|
base_value: u64,
|
||||||
max_value: u64,
|
max_value: u64,
|
||||||
@@ -146,7 +144,7 @@ impl CompositeFastFieldSerializer {
|
|||||||
gcd: DividerU64,
|
gcd: DividerU64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: FastFieldDataAccess> FastFieldDataAccess for GCDWrappedFFAccess<T> {
|
impl<T: Column> Column for GCDWrappedFFAccess<T> {
|
||||||
fn get_val(&self, position: u64) -> u64 {
|
fn get_val(&self, position: u64) -> u64 {
|
||||||
self.gcd
|
self.gcd
|
||||||
.divide(self.fastfield_accessor.get_val(position) - self.base_value)
|
.divide(self.fastfield_accessor.get_val(position) - self.base_value)
|
||||||
@@ -199,7 +197,7 @@ impl CompositeFastFieldSerializer {
|
|||||||
codec_enable_checker: FastFieldCodecEnableCheck,
|
codec_enable_checker: FastFieldCodecEnableCheck,
|
||||||
field: Field,
|
field: Field,
|
||||||
field_write: &mut CountingWriter<W>,
|
field_write: &mut CountingWriter<W>,
|
||||||
fastfield_accessor: impl FastFieldDataAccess,
|
fastfield_accessor: impl Column,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
let mut estimations = vec![];
|
let mut estimations = vec![];
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use std::collections::HashMap;
|
|||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use common;
|
use common;
|
||||||
use fastfield_codecs::FastFieldDataAccess;
|
use fastfield_codecs::Column;
|
||||||
use fnv::FnvHashMap;
|
use fnv::FnvHashMap;
|
||||||
use tantivy_bitpacker::BlockedBitpacker;
|
use tantivy_bitpacker::BlockedBitpacker;
|
||||||
|
|
||||||
@@ -384,7 +384,7 @@ struct WriterFastFieldAccessProvider<'map, 'bitp> {
|
|||||||
vals: &'bitp BlockedBitpacker,
|
vals: &'bitp BlockedBitpacker,
|
||||||
stats: FastFieldStats,
|
stats: FastFieldStats,
|
||||||
}
|
}
|
||||||
impl<'map, 'bitp> FastFieldDataAccess for WriterFastFieldAccessProvider<'map, 'bitp> {
|
impl<'map, 'bitp> Column for WriterFastFieldAccessProvider<'map, 'bitp> {
|
||||||
/// Return the value associated to the given doc.
|
/// Return the value associated to the given doc.
|
||||||
///
|
///
|
||||||
/// Whenever possible use the Iterator passed to the fastfield creation instead, for performance
|
/// Whenever possible use the Iterator passed to the fastfield creation instead, for performance
|
||||||
|
|||||||
@@ -143,8 +143,9 @@ pub(crate) fn get_doc_id_mapping_from_field(
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests_indexsorting {
|
mod tests_indexsorting {
|
||||||
|
use fastfield_codecs::Column;
|
||||||
|
|
||||||
use crate::collector::TopDocs;
|
use crate::collector::TopDocs;
|
||||||
use crate::fastfield::FastFieldReader;
|
|
||||||
use crate::indexer::doc_id_mapping::DocIdMapping;
|
use crate::indexer::doc_id_mapping::DocIdMapping;
|
||||||
use crate::query::QueryParser;
|
use crate::query::QueryParser;
|
||||||
use crate::schema::{Schema, *};
|
use crate::schema::{Schema, *};
|
||||||
@@ -464,21 +465,19 @@ mod tests_indexsorting {
|
|||||||
let my_number = index.schema().get_field("my_number").unwrap();
|
let my_number = index.schema().get_field("my_number").unwrap();
|
||||||
|
|
||||||
let fast_field = fast_fields.u64(my_number).unwrap();
|
let fast_field = fast_fields.u64(my_number).unwrap();
|
||||||
assert_eq!(fast_field.get(0u32), 10u64);
|
assert_eq!(fast_field.get_val(0), 10u64);
|
||||||
assert_eq!(fast_field.get(1u32), 20u64);
|
assert_eq!(fast_field.get_val(1), 20u64);
|
||||||
assert_eq!(fast_field.get(2u32), 30u64);
|
assert_eq!(fast_field.get_val(2), 30u64);
|
||||||
|
|
||||||
let multi_numbers = index.schema().get_field("multi_numbers").unwrap();
|
let multi_numbers = index.schema().get_field("multi_numbers").unwrap();
|
||||||
let multifield = fast_fields.u64s(multi_numbers).unwrap();
|
let multifield = fast_fields.u64s(multi_numbers).unwrap();
|
||||||
let mut vals = vec![];
|
let vals = multifield.get_vals(0u32).collect::<Vec<_>>();
|
||||||
multifield.get_vals(0u32, &mut vals);
|
|
||||||
assert_eq!(vals, &[] as &[u64]);
|
assert_eq!(vals, &[] as &[u64]);
|
||||||
let mut vals = vec![];
|
|
||||||
multifield.get_vals(1u32, &mut vals);
|
let vals = multifield.get_vals(1u32).collect::<Vec<_>>();
|
||||||
assert_eq!(vals, &[5, 6]);
|
assert_eq!(vals, &[5, 6]);
|
||||||
|
|
||||||
let mut vals = vec![];
|
let vals = multifield.get_vals(2u32).collect::<Vec<_>>();
|
||||||
multifield.get_vals(2u32, &mut vals);
|
|
||||||
assert_eq!(vals, &[3]);
|
assert_eq!(vals, &[3]);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -777,6 +777,7 @@ impl Drop for IndexWriter {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
|
use fastfield_codecs::Column;
|
||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
use proptest::prop_oneof;
|
use proptest::prop_oneof;
|
||||||
use proptest::strategy::Strategy;
|
use proptest::strategy::Strategy;
|
||||||
@@ -785,7 +786,6 @@ mod tests {
|
|||||||
use crate::collector::TopDocs;
|
use crate::collector::TopDocs;
|
||||||
use crate::directory::error::LockError;
|
use crate::directory::error::LockError;
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
use crate::fastfield::FastFieldReader;
|
|
||||||
use crate::indexer::NoMergePolicy;
|
use crate::indexer::NoMergePolicy;
|
||||||
use crate::query::{QueryParser, TermQuery};
|
use crate::query::{QueryParser, TermQuery};
|
||||||
use crate::schema::{
|
use crate::schema::{
|
||||||
@@ -1327,7 +1327,7 @@ mod tests {
|
|||||||
let fast_field_reader = segment_reader.fast_fields().u64(id_field)?;
|
let fast_field_reader = segment_reader.fast_fields().u64(id_field)?;
|
||||||
let in_order_alive_ids: Vec<u64> = segment_reader
|
let in_order_alive_ids: Vec<u64> = segment_reader
|
||||||
.doc_ids_alive()
|
.doc_ids_alive()
|
||||||
.map(|doc| fast_field_reader.get(doc))
|
.map(|doc| fast_field_reader.get_val(doc as u64))
|
||||||
.collect();
|
.collect();
|
||||||
assert_eq!(&in_order_alive_ids[..], &[9, 8, 7, 6, 5, 4, 1, 0]);
|
assert_eq!(&in_order_alive_ids[..], &[9, 8, 7, 6, 5, 4, 1, 0]);
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -1493,7 +1493,7 @@ mod tests {
|
|||||||
let ff_reader = segment_reader.fast_fields().u64(id_field).unwrap();
|
let ff_reader = segment_reader.fast_fields().u64(id_field).unwrap();
|
||||||
segment_reader
|
segment_reader
|
||||||
.doc_ids_alive()
|
.doc_ids_alive()
|
||||||
.map(move |doc| ff_reader.get(doc))
|
.map(move |doc| ff_reader.get_val(doc as u64))
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
@@ -1504,7 +1504,7 @@ mod tests {
|
|||||||
let ff_reader = segment_reader.fast_fields().u64(id_field).unwrap();
|
let ff_reader = segment_reader.fast_fields().u64(id_field).unwrap();
|
||||||
segment_reader
|
segment_reader
|
||||||
.doc_ids_alive()
|
.doc_ids_alive()
|
||||||
.map(move |doc| ff_reader.get(doc))
|
.map(move |doc| ff_reader.get_val(doc as u64))
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
@@ -1535,13 +1535,11 @@ mod tests {
|
|||||||
let ff_reader = segment_reader.fast_fields().u64s(multi_numbers).unwrap();
|
let ff_reader = segment_reader.fast_fields().u64s(multi_numbers).unwrap();
|
||||||
let bool_ff_reader = segment_reader.fast_fields().bools(multi_bools).unwrap();
|
let bool_ff_reader = segment_reader.fast_fields().bools(multi_bools).unwrap();
|
||||||
for doc in segment_reader.doc_ids_alive() {
|
for doc in segment_reader.doc_ids_alive() {
|
||||||
let mut vals = vec![];
|
let vals = ff_reader.get_vals(doc).collect::<Vec<_>>();
|
||||||
ff_reader.get_vals(doc, &mut vals);
|
|
||||||
assert_eq!(vals.len(), 2);
|
assert_eq!(vals.len(), 2);
|
||||||
assert_eq!(vals[0], vals[1]);
|
assert_eq!(vals[0], vals[1]);
|
||||||
|
|
||||||
let mut bool_vals = vec![];
|
let bool_vals = bool_ff_reader.get_vals(doc).collect::<Vec<_>>();
|
||||||
bool_ff_reader.get_vals(doc, &mut bool_vals);
|
|
||||||
assert_eq!(bool_vals.len(), 2);
|
assert_eq!(bool_vals.len(), 2);
|
||||||
assert_ne!(bool_vals[0], bool_vals[1]);
|
assert_ne!(bool_vals[0], bool_vals[1]);
|
||||||
|
|
||||||
@@ -1622,7 +1620,7 @@ mod tests {
|
|||||||
facet_reader
|
facet_reader
|
||||||
.facet_from_ord(facet_ords[0], &mut facet)
|
.facet_from_ord(facet_ords[0], &mut facet)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let id = ff_reader.get(doc_id);
|
let id = ff_reader.get_val(doc_id as u64);
|
||||||
let facet_expected = Facet::from(&("/cola/".to_string() + &id.to_string()));
|
let facet_expected = Facet::from(&("/cola/".to_string() + &id.to_string()));
|
||||||
|
|
||||||
assert_eq!(facet, facet_expected);
|
assert_eq!(facet, facet_expected);
|
||||||
|
|||||||
@@ -4,14 +4,13 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use measure_time::debug_time;
|
use measure_time::debug_time;
|
||||||
use tantivy_bitpacker::minmax;
|
|
||||||
|
|
||||||
use crate::core::{Segment, SegmentReader};
|
use crate::core::{Segment, SegmentReader};
|
||||||
use crate::docset::{DocSet, TERMINATED};
|
use crate::docset::{DocSet, TERMINATED};
|
||||||
use crate::error::DataCorruption;
|
use crate::error::DataCorruption;
|
||||||
use crate::fastfield::{
|
use crate::fastfield::{
|
||||||
AliveBitSet, CompositeFastFieldSerializer, DynamicFastFieldReader, FastFieldDataAccess,
|
AliveBitSet, Column, CompositeFastFieldSerializer, DynamicFastFieldReader, FastFieldStats,
|
||||||
FastFieldReader, FastFieldStats, MultiValueLength, MultiValuedFastFieldReader,
|
MultiValueLength, MultiValuedFastFieldReader,
|
||||||
};
|
};
|
||||||
use crate::fieldnorm::{FieldNormReader, FieldNormReaders, FieldNormsSerializer, FieldNormsWriter};
|
use crate::fieldnorm::{FieldNormReader, FieldNormReaders, FieldNormsSerializer, FieldNormsWriter};
|
||||||
use crate::indexer::doc_id_mapping::{expect_field_id_for_sort_field, SegmentDocIdMapping};
|
use crate::indexer::doc_id_mapping::{expect_field_id_for_sort_field, SegmentDocIdMapping};
|
||||||
@@ -88,7 +87,7 @@ pub struct IndexMerger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn compute_min_max_val(
|
fn compute_min_max_val(
|
||||||
u64_reader: &impl FastFieldReader<u64>,
|
u64_reader: &impl Column<u64>,
|
||||||
segment_reader: &SegmentReader,
|
segment_reader: &SegmentReader,
|
||||||
) -> Option<(u64, u64)> {
|
) -> Option<(u64, u64)> {
|
||||||
if segment_reader.max_doc() == 0 {
|
if segment_reader.max_doc() == 0 {
|
||||||
@@ -102,11 +101,11 @@ fn compute_min_max_val(
|
|||||||
}
|
}
|
||||||
// some deleted documents,
|
// some deleted documents,
|
||||||
// we need to recompute the max / min
|
// we need to recompute the max / min
|
||||||
minmax(
|
segment_reader
|
||||||
segment_reader
|
.doc_ids_alive()
|
||||||
.doc_ids_alive()
|
.map(|doc_id| u64_reader.get_val(doc_id as u64))
|
||||||
.map(|doc_id| u64_reader.get(doc_id)),
|
.minmax()
|
||||||
)
|
.into_option()
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TermOrdinalMapping {
|
struct TermOrdinalMapping {
|
||||||
@@ -376,13 +375,13 @@ impl IndexMerger {
|
|||||||
fast_field_readers: &'a Vec<DynamicFastFieldReader<u64>>,
|
fast_field_readers: &'a Vec<DynamicFastFieldReader<u64>>,
|
||||||
stats: FastFieldStats,
|
stats: FastFieldStats,
|
||||||
}
|
}
|
||||||
impl<'a> FastFieldDataAccess for SortedDocIdFieldAccessProvider<'a> {
|
impl<'a> Column for SortedDocIdFieldAccessProvider<'a> {
|
||||||
fn get_val(&self, doc: u64) -> u64 {
|
fn get_val(&self, doc: u64) -> u64 {
|
||||||
let DocAddress {
|
let DocAddress {
|
||||||
doc_id,
|
doc_id,
|
||||||
segment_ord,
|
segment_ord,
|
||||||
} = self.doc_id_mapping.get_old_doc_addr(doc as u32);
|
} = self.doc_id_mapping.get_old_doc_addr(doc as u32);
|
||||||
self.fast_field_readers[segment_ord as usize].get(doc_id)
|
self.fast_field_readers[segment_ord as usize].get_val(doc_id as u64)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter(&self) -> Box<dyn Iterator<Item = u64> + '_> {
|
fn iter(&self) -> Box<dyn Iterator<Item = u64> + '_> {
|
||||||
@@ -392,7 +391,7 @@ impl IndexMerger {
|
|||||||
.map(|old_doc_addr| {
|
.map(|old_doc_addr| {
|
||||||
let fast_field_reader =
|
let fast_field_reader =
|
||||||
&self.fast_field_readers[old_doc_addr.segment_ord as usize];
|
&self.fast_field_readers[old_doc_addr.segment_ord as usize];
|
||||||
fast_field_reader.get(old_doc_addr.doc_id)
|
fast_field_reader.get_val(old_doc_addr.doc_id as u64)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -429,7 +428,7 @@ impl IndexMerger {
|
|||||||
|
|
||||||
let everything_is_in_order = reader_ordinal_and_field_accessors
|
let everything_is_in_order = reader_ordinal_and_field_accessors
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|reader| reader.1)
|
.map(|(_, col)| Arc::new(col))
|
||||||
.tuple_windows()
|
.tuple_windows()
|
||||||
.all(|(field_accessor1, field_accessor2)| {
|
.all(|(field_accessor1, field_accessor2)| {
|
||||||
if sort_by_field.order.is_asc() {
|
if sort_by_field.order.is_asc() {
|
||||||
@@ -444,7 +443,7 @@ impl IndexMerger {
|
|||||||
pub(crate) fn get_sort_field_accessor(
|
pub(crate) fn get_sort_field_accessor(
|
||||||
reader: &SegmentReader,
|
reader: &SegmentReader,
|
||||||
sort_by_field: &IndexSortByField,
|
sort_by_field: &IndexSortByField,
|
||||||
) -> crate::Result<impl FastFieldReader<u64>> {
|
) -> crate::Result<impl Column> {
|
||||||
let field_id = expect_field_id_for_sort_field(reader.schema(), sort_by_field)?; // for now expect fastfield, but not strictly required
|
let field_id = expect_field_id_for_sort_field(reader.schema(), sort_by_field)?; // for now expect fastfield, but not strictly required
|
||||||
let value_accessor = reader.fast_fields().u64_lenient(field_id)?;
|
let value_accessor = reader.fast_fields().u64_lenient(field_id)?;
|
||||||
Ok(value_accessor)
|
Ok(value_accessor)
|
||||||
@@ -453,7 +452,7 @@ impl IndexMerger {
|
|||||||
pub(crate) fn get_reader_with_sort_field_accessor(
|
pub(crate) fn get_reader_with_sort_field_accessor(
|
||||||
&self,
|
&self,
|
||||||
sort_by_field: &IndexSortByField,
|
sort_by_field: &IndexSortByField,
|
||||||
) -> crate::Result<Vec<(SegmentOrdinal, impl FastFieldReader<u64> + Clone)>> {
|
) -> crate::Result<Vec<(SegmentOrdinal, impl Column)>> {
|
||||||
let reader_ordinal_and_field_accessors = self
|
let reader_ordinal_and_field_accessors = self
|
||||||
.readers
|
.readers
|
||||||
.iter()
|
.iter()
|
||||||
@@ -506,8 +505,8 @@ impl IndexMerger {
|
|||||||
doc_id_reader_pair
|
doc_id_reader_pair
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.kmerge_by(|a, b| {
|
.kmerge_by(|a, b| {
|
||||||
let val1 = a.2.get(a.0);
|
let val1 = a.2.get_val(a.0 as u64);
|
||||||
let val2 = b.2.get(b.0);
|
let val2 = b.2.get_val(b.0 as u64);
|
||||||
if sort_by_field.order == Order::Asc {
|
if sort_by_field.order == Order::Asc {
|
||||||
val1 < val2
|
val1 < val2
|
||||||
} else {
|
} else {
|
||||||
@@ -578,7 +577,8 @@ impl IndexMerger {
|
|||||||
offsets: &'a [u64],
|
offsets: &'a [u64],
|
||||||
stats: FastFieldStats,
|
stats: FastFieldStats,
|
||||||
}
|
}
|
||||||
impl<'a> FastFieldDataAccess for FieldIndexAccessProvider<'a> {
|
impl<'a> Column for FieldIndexAccessProvider<'a> {
|
||||||
|
#[inline]
|
||||||
fn get_val(&self, doc: u64) -> u64 {
|
fn get_val(&self, doc: u64) -> u64 {
|
||||||
self.offsets[doc as usize]
|
self.offsets[doc as usize]
|
||||||
}
|
}
|
||||||
@@ -669,15 +669,13 @@ impl IndexMerger {
|
|||||||
{
|
{
|
||||||
let mut serialize_vals =
|
let mut serialize_vals =
|
||||||
fast_field_serializer.new_u64_fast_field_with_idx(field, 0u64, max_term_ord, 1)?;
|
fast_field_serializer.new_u64_fast_field_with_idx(field, 0u64, max_term_ord, 1)?;
|
||||||
let mut vals = Vec::with_capacity(100);
|
|
||||||
|
|
||||||
for old_doc_addr in doc_id_mapping.iter_old_doc_addrs() {
|
for old_doc_addr in doc_id_mapping.iter_old_doc_addrs() {
|
||||||
let term_ordinal_mapping: &[TermOrdinal] =
|
let term_ordinal_mapping: &[TermOrdinal] =
|
||||||
term_ordinal_mappings.get_segment(old_doc_addr.segment_ord as usize);
|
term_ordinal_mappings.get_segment(old_doc_addr.segment_ord as usize);
|
||||||
|
|
||||||
let ff_reader = &fast_field_reader[old_doc_addr.segment_ord as usize];
|
let ff_reader = &fast_field_reader[old_doc_addr.segment_ord as usize];
|
||||||
ff_reader.get_vals(old_doc_addr.doc_id, &mut vals);
|
for prev_term_ord in ff_reader.get_vals(old_doc_addr.doc_id) {
|
||||||
for &prev_term_ord in &vals {
|
|
||||||
let new_term_ord = term_ordinal_mapping[prev_term_ord as usize];
|
let new_term_ord = term_ordinal_mapping[prev_term_ord as usize];
|
||||||
serialize_vals.add_val(new_term_ord)?;
|
serialize_vals.add_val(new_term_ord)?;
|
||||||
}
|
}
|
||||||
@@ -730,8 +728,6 @@ impl IndexMerger {
|
|||||||
let mut max_value = u64::MIN;
|
let mut max_value = u64::MIN;
|
||||||
let mut num_vals = 0;
|
let mut num_vals = 0;
|
||||||
|
|
||||||
let mut vals = Vec::with_capacity(100);
|
|
||||||
|
|
||||||
let mut ff_readers = Vec::new();
|
let mut ff_readers = Vec::new();
|
||||||
|
|
||||||
// Our values are bitpacked and we need to know what should be
|
// Our values are bitpacked and we need to know what should be
|
||||||
@@ -749,12 +745,11 @@ impl IndexMerger {
|
|||||||
Please report.",
|
Please report.",
|
||||||
);
|
);
|
||||||
for doc in reader.doc_ids_alive() {
|
for doc in reader.doc_ids_alive() {
|
||||||
ff_reader.get_vals(doc, &mut vals);
|
for val in ff_reader.get_vals(doc) {
|
||||||
for &val in &vals {
|
|
||||||
min_value = cmp::min(val, min_value);
|
min_value = cmp::min(val, min_value);
|
||||||
max_value = cmp::max(val, max_value);
|
max_value = cmp::max(val, max_value);
|
||||||
|
num_vals += 1;
|
||||||
}
|
}
|
||||||
num_vals += vals.len();
|
|
||||||
}
|
}
|
||||||
ff_readers.push(ff_reader);
|
ff_readers.push(ff_reader);
|
||||||
// TODO optimize when no deletes
|
// TODO optimize when no deletes
|
||||||
@@ -778,7 +773,7 @@ impl IndexMerger {
|
|||||||
offsets: Vec<u64>,
|
offsets: Vec<u64>,
|
||||||
stats: FastFieldStats,
|
stats: FastFieldStats,
|
||||||
}
|
}
|
||||||
impl<'a> FastFieldDataAccess for SortedDocIdMultiValueAccessProvider<'a> {
|
impl<'a> Column for SortedDocIdMultiValueAccessProvider<'a> {
|
||||||
fn get_val(&self, pos: u64) -> u64 {
|
fn get_val(&self, pos: u64) -> u64 {
|
||||||
// use the offsets index to find the doc_id which will contain the position.
|
// use the offsets index to find the doc_id which will contain the position.
|
||||||
// the offsets are strictly increasing so we can do a simple search on it.
|
// the offsets are strictly increasing so we can do a simple search on it.
|
||||||
@@ -797,11 +792,10 @@ impl IndexMerger {
|
|||||||
let num_vals = self.fast_field_readers[old_doc_addr.segment_ord as usize]
|
let num_vals = self.fast_field_readers[old_doc_addr.segment_ord as usize]
|
||||||
.get_len(old_doc_addr.doc_id);
|
.get_len(old_doc_addr.doc_id);
|
||||||
assert!(num_vals >= pos_in_values);
|
assert!(num_vals >= pos_in_values);
|
||||||
let mut vals = Vec::new();
|
|
||||||
self.fast_field_readers[old_doc_addr.segment_ord as usize]
|
self.fast_field_readers[old_doc_addr.segment_ord as usize]
|
||||||
.get_vals(old_doc_addr.doc_id, &mut vals);
|
.get_vals(old_doc_addr.doc_id)
|
||||||
|
.nth(pos_in_values as usize)
|
||||||
vals[pos_in_values as usize]
|
.expect("computation error in SortedDocIdMultiValueAccessProvider")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter(&self) -> Box<dyn Iterator<Item = u64> + '_> {
|
fn iter(&self) -> Box<dyn Iterator<Item = u64> + '_> {
|
||||||
@@ -811,9 +805,7 @@ impl IndexMerger {
|
|||||||
.flat_map(|old_doc_addr| {
|
.flat_map(|old_doc_addr| {
|
||||||
let ff_reader =
|
let ff_reader =
|
||||||
&self.fast_field_readers[old_doc_addr.segment_ord as usize];
|
&self.fast_field_readers[old_doc_addr.segment_ord as usize];
|
||||||
let mut vals = Vec::new();
|
ff_reader.get_vals(old_doc_addr.doc_id)
|
||||||
ff_reader.get_vals(old_doc_addr.doc_id, &mut vals);
|
|
||||||
vals.into_iter()
|
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1200,6 +1192,7 @@ impl IndexMerger {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use byteorder::{BigEndian, ReadBytesExt};
|
use byteorder::{BigEndian, ReadBytesExt};
|
||||||
|
use fastfield_codecs::Column;
|
||||||
use schema::FAST;
|
use schema::FAST;
|
||||||
|
|
||||||
use crate::collector::tests::{
|
use crate::collector::tests::{
|
||||||
@@ -1207,7 +1200,6 @@ mod tests {
|
|||||||
};
|
};
|
||||||
use crate::collector::{Count, FacetCollector};
|
use crate::collector::{Count, FacetCollector};
|
||||||
use crate::core::Index;
|
use crate::core::Index;
|
||||||
use crate::fastfield::FastFieldReader;
|
|
||||||
use crate::query::{AllQuery, BooleanQuery, Scorer, TermQuery};
|
use crate::query::{AllQuery, BooleanQuery, Scorer, TermQuery};
|
||||||
use crate::schema::{
|
use crate::schema::{
|
||||||
Cardinality, Document, Facet, FacetOptions, IndexRecordOption, NumericOptions, Term,
|
Cardinality, Document, Facet, FacetOptions, IndexRecordOption, NumericOptions, Term,
|
||||||
@@ -1976,49 +1968,32 @@ mod tests {
|
|||||||
}
|
}
|
||||||
let reader = index.reader()?;
|
let reader = index.reader()?;
|
||||||
let searcher = reader.searcher();
|
let searcher = reader.searcher();
|
||||||
let mut vals: Vec<u64> = Vec::new();
|
|
||||||
|
|
||||||
{
|
{
|
||||||
let segment = searcher.segment_reader(0u32);
|
let segment = searcher.segment_reader(0u32);
|
||||||
let ff_reader = segment.fast_fields().u64s(int_field).unwrap();
|
let ff_reader = segment.fast_fields().u64s(int_field).unwrap();
|
||||||
|
|
||||||
ff_reader.get_vals(0, &mut vals);
|
assert_eq!(&ff_reader.get_vals(0).collect::<Vec<_>>(), &[1, 2]);
|
||||||
assert_eq!(&vals, &[1, 2]);
|
assert_eq!(&ff_reader.get_vals(1).collect::<Vec<_>>(), &[1, 2, 3]);
|
||||||
|
assert_eq!(&ff_reader.get_vals(2).collect::<Vec<_>>(), &[4, 5]);
|
||||||
ff_reader.get_vals(1, &mut vals);
|
assert_eq!(&ff_reader.get_vals(3).collect::<Vec<_>>(), &[1, 2]);
|
||||||
assert_eq!(&vals, &[1, 2, 3]);
|
assert_eq!(&ff_reader.get_vals(4).collect::<Vec<_>>(), &[1, 5]);
|
||||||
|
assert_eq!(&ff_reader.get_vals(5).collect::<Vec<_>>(), &[3]);
|
||||||
ff_reader.get_vals(2, &mut vals);
|
assert_eq!(&ff_reader.get_vals(6).collect::<Vec<_>>(), &[17]);
|
||||||
assert_eq!(&vals, &[4, 5]);
|
|
||||||
|
|
||||||
ff_reader.get_vals(3, &mut vals);
|
|
||||||
assert_eq!(&vals, &[1, 2]);
|
|
||||||
|
|
||||||
ff_reader.get_vals(4, &mut vals);
|
|
||||||
assert_eq!(&vals, &[1, 5]);
|
|
||||||
|
|
||||||
ff_reader.get_vals(5, &mut vals);
|
|
||||||
assert_eq!(&vals, &[3]);
|
|
||||||
|
|
||||||
ff_reader.get_vals(6, &mut vals);
|
|
||||||
assert_eq!(&vals, &[17]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let segment = searcher.segment_reader(1u32);
|
let segment = searcher.segment_reader(1u32);
|
||||||
let ff_reader = segment.fast_fields().u64s(int_field).unwrap();
|
let ff_reader = segment.fast_fields().u64s(int_field).unwrap();
|
||||||
ff_reader.get_vals(0, &mut vals);
|
assert_eq!(&ff_reader.get_vals(0).collect::<Vec<_>>(), &[28, 27]);
|
||||||
assert_eq!(&vals, &[28, 27]);
|
|
||||||
|
|
||||||
ff_reader.get_vals(1, &mut vals);
|
assert_eq!(&ff_reader.get_vals(1).collect::<Vec<_>>(), &[1000]);
|
||||||
assert_eq!(&vals, &[1_000]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let segment = searcher.segment_reader(2u32);
|
let segment = searcher.segment_reader(2u32);
|
||||||
let ff_reader = segment.fast_fields().u64s(int_field).unwrap();
|
let ff_reader = segment.fast_fields().u64s(int_field).unwrap();
|
||||||
ff_reader.get_vals(0, &mut vals);
|
assert_eq!(&ff_reader.get_vals(0).collect::<Vec<_>>(), &[20]);
|
||||||
assert_eq!(&vals, &[20]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merging the segments
|
// Merging the segments
|
||||||
@@ -2035,35 +2010,16 @@ mod tests {
|
|||||||
let segment = searcher.segment_reader(0u32);
|
let segment = searcher.segment_reader(0u32);
|
||||||
let ff_reader = segment.fast_fields().u64s(int_field).unwrap();
|
let ff_reader = segment.fast_fields().u64s(int_field).unwrap();
|
||||||
|
|
||||||
ff_reader.get_vals(0, &mut vals);
|
assert_eq!(&ff_reader.get_vals(0).collect::<Vec<_>>(), &[1, 2]);
|
||||||
assert_eq!(&vals, &[1, 2]);
|
assert_eq!(&ff_reader.get_vals(1).collect::<Vec<_>>(), &[1, 2, 3]);
|
||||||
|
assert_eq!(&ff_reader.get_vals(2).collect::<Vec<_>>(), &[4, 5]);
|
||||||
ff_reader.get_vals(1, &mut vals);
|
assert_eq!(&ff_reader.get_vals(3).collect::<Vec<_>>(), &[1, 2]);
|
||||||
assert_eq!(&vals, &[1, 2, 3]);
|
assert_eq!(&ff_reader.get_vals(4).collect::<Vec<_>>(), &[1, 5]);
|
||||||
|
assert_eq!(&ff_reader.get_vals(5).collect::<Vec<_>>(), &[3]);
|
||||||
ff_reader.get_vals(2, &mut vals);
|
assert_eq!(&ff_reader.get_vals(6).collect::<Vec<_>>(), &[17]);
|
||||||
assert_eq!(&vals, &[4, 5]);
|
assert_eq!(&ff_reader.get_vals(7).collect::<Vec<_>>(), &[28, 27]);
|
||||||
|
assert_eq!(&ff_reader.get_vals(8).collect::<Vec<_>>(), &[1_000]);
|
||||||
ff_reader.get_vals(3, &mut vals);
|
assert_eq!(&ff_reader.get_vals(9).collect::<Vec<_>>(), &[20]);
|
||||||
assert_eq!(&vals, &[1, 2]);
|
|
||||||
|
|
||||||
ff_reader.get_vals(4, &mut vals);
|
|
||||||
assert_eq!(&vals, &[1, 5]);
|
|
||||||
|
|
||||||
ff_reader.get_vals(5, &mut vals);
|
|
||||||
assert_eq!(&vals, &[3]);
|
|
||||||
|
|
||||||
ff_reader.get_vals(6, &mut vals);
|
|
||||||
assert_eq!(&vals, &[17]);
|
|
||||||
|
|
||||||
ff_reader.get_vals(7, &mut vals);
|
|
||||||
assert_eq!(&vals, &[28, 27]);
|
|
||||||
|
|
||||||
ff_reader.get_vals(8, &mut vals);
|
|
||||||
assert_eq!(&vals, &[1_000]);
|
|
||||||
|
|
||||||
ff_reader.get_vals(9, &mut vals);
|
|
||||||
assert_eq!(&vals, &[20]);
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use fastfield_codecs::Column;
|
||||||
|
|
||||||
use crate::collector::TopDocs;
|
use crate::collector::TopDocs;
|
||||||
use crate::core::Index;
|
use crate::core::Index;
|
||||||
use crate::fastfield::{AliveBitSet, FastFieldReader, MultiValuedFastFieldReader};
|
use crate::fastfield::{AliveBitSet, MultiValuedFastFieldReader};
|
||||||
use crate::query::QueryParser;
|
use crate::query::QueryParser;
|
||||||
use crate::schema::{
|
use crate::schema::{
|
||||||
self, BytesOptions, Cardinality, Facet, FacetOptions, IndexRecordOption, NumericOptions,
|
self, BytesOptions, Cardinality, Facet, FacetOptions, IndexRecordOption, NumericOptions,
|
||||||
@@ -186,17 +188,17 @@ mod tests {
|
|||||||
|
|
||||||
let fast_fields = segment_reader.fast_fields();
|
let fast_fields = segment_reader.fast_fields();
|
||||||
let fast_field = fast_fields.u64(int_field).unwrap();
|
let fast_field = fast_fields.u64(int_field).unwrap();
|
||||||
assert_eq!(fast_field.get(5u32), 1u64);
|
assert_eq!(fast_field.get_val(5), 1u64);
|
||||||
assert_eq!(fast_field.get(4u32), 2u64);
|
assert_eq!(fast_field.get_val(4), 2u64);
|
||||||
assert_eq!(fast_field.get(3u32), 3u64);
|
assert_eq!(fast_field.get_val(3), 3u64);
|
||||||
if force_disjunct_segment_sort_values {
|
if force_disjunct_segment_sort_values {
|
||||||
assert_eq!(fast_field.get(2u32), 20u64);
|
assert_eq!(fast_field.get_val(2u64), 20u64);
|
||||||
assert_eq!(fast_field.get(1u32), 100u64);
|
assert_eq!(fast_field.get_val(1u64), 100u64);
|
||||||
} else {
|
} else {
|
||||||
assert_eq!(fast_field.get(2u32), 10u64);
|
assert_eq!(fast_field.get_val(2u64), 10u64);
|
||||||
assert_eq!(fast_field.get(1u32), 20u64);
|
assert_eq!(fast_field.get_val(1u64), 20u64);
|
||||||
}
|
}
|
||||||
assert_eq!(fast_field.get(0u32), 1_000u64);
|
assert_eq!(fast_field.get_val(0u64), 1_000u64);
|
||||||
|
|
||||||
// test new field norm mapping
|
// test new field norm mapping
|
||||||
{
|
{
|
||||||
@@ -373,17 +375,15 @@ mod tests {
|
|||||||
|
|
||||||
let fast_fields = segment_reader.fast_fields();
|
let fast_fields = segment_reader.fast_fields();
|
||||||
let fast_field = fast_fields.u64(int_field).unwrap();
|
let fast_field = fast_fields.u64(int_field).unwrap();
|
||||||
assert_eq!(fast_field.get(0u32), 1u64);
|
assert_eq!(fast_field.get_val(0), 1u64);
|
||||||
assert_eq!(fast_field.get(1u32), 2u64);
|
assert_eq!(fast_field.get_val(1), 2u64);
|
||||||
assert_eq!(fast_field.get(2u32), 3u64);
|
assert_eq!(fast_field.get_val(2), 3u64);
|
||||||
assert_eq!(fast_field.get(3u32), 10u64);
|
assert_eq!(fast_field.get_val(3), 10u64);
|
||||||
assert_eq!(fast_field.get(4u32), 20u64);
|
assert_eq!(fast_field.get_val(4), 20u64);
|
||||||
assert_eq!(fast_field.get(5u32), 1_000u64);
|
assert_eq!(fast_field.get_val(5), 1_000u64);
|
||||||
|
|
||||||
let get_vals = |fast_field: &MultiValuedFastFieldReader<u64>, doc_id: u32| -> Vec<u64> {
|
let get_vals = |fast_field: &MultiValuedFastFieldReader<u64>, doc_id: u32| -> Vec<u64> {
|
||||||
let mut vals = vec![];
|
fast_field.get_vals(doc_id).collect()
|
||||||
fast_field.get_vals(doc_id, &mut vals);
|
|
||||||
vals
|
|
||||||
};
|
};
|
||||||
let fast_fields = segment_reader.fast_fields();
|
let fast_fields = segment_reader.fast_fields();
|
||||||
let fast_field = fast_fields.u64s(multi_numbers).unwrap();
|
let fast_field = fast_fields.u64s(multi_numbers).unwrap();
|
||||||
@@ -478,11 +478,11 @@ mod tests {
|
|||||||
#[cfg(all(test, feature = "unstable"))]
|
#[cfg(all(test, feature = "unstable"))]
|
||||||
mod bench_sorted_index_merge {
|
mod bench_sorted_index_merge {
|
||||||
|
|
||||||
|
use fastfield_codecs::Column;
|
||||||
use test::{self, Bencher};
|
use test::{self, Bencher};
|
||||||
|
|
||||||
use crate::core::Index;
|
use crate::core::Index;
|
||||||
// use cratedoc_id, readerdoc_id_mappinglet vals = reader.fate::schema;
|
use crate::fastfield::DynamicFastFieldReader;
|
||||||
use crate::fastfield::{DynamicFastFieldReader, FastFieldReader};
|
|
||||||
use crate::indexer::merger::IndexMerger;
|
use crate::indexer::merger::IndexMerger;
|
||||||
use crate::schema::{Cardinality, NumericOptions, Schema};
|
use crate::schema::{Cardinality, NumericOptions, Schema};
|
||||||
use crate::{IndexSettings, IndexSortByField, IndexWriter, Order};
|
use crate::{IndexSettings, IndexSortByField, IndexWriter, Order};
|
||||||
@@ -544,7 +544,7 @@ mod bench_sorted_index_merge {
|
|||||||
// add values in order of the new doc_ids
|
// add values in order of the new doc_ids
|
||||||
let mut val = 0;
|
let mut val = 0;
|
||||||
for (doc_id, _reader, field_reader) in sorted_doc_ids {
|
for (doc_id, _reader, field_reader) in sorted_doc_ids {
|
||||||
val = field_reader.get(doc_id);
|
val = field_reader.get_val(doc_id as u64);
|
||||||
}
|
}
|
||||||
|
|
||||||
val
|
val
|
||||||
|
|||||||
@@ -421,6 +421,7 @@ pub struct DocAddress {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
use common::{BinarySerializable, FixedSize};
|
use common::{BinarySerializable, FixedSize};
|
||||||
|
use fastfield_codecs::Column;
|
||||||
use rand::distributions::{Bernoulli, Uniform};
|
use rand::distributions::{Bernoulli, Uniform};
|
||||||
use rand::rngs::StdRng;
|
use rand::rngs::StdRng;
|
||||||
use rand::{Rng, SeedableRng};
|
use rand::{Rng, SeedableRng};
|
||||||
@@ -429,7 +430,6 @@ pub mod tests {
|
|||||||
use crate::collector::tests::TEST_COLLECTOR_WITH_SCORE;
|
use crate::collector::tests::TEST_COLLECTOR_WITH_SCORE;
|
||||||
use crate::core::SegmentReader;
|
use crate::core::SegmentReader;
|
||||||
use crate::docset::{DocSet, TERMINATED};
|
use crate::docset::{DocSet, TERMINATED};
|
||||||
use crate::fastfield::FastFieldReader;
|
|
||||||
use crate::merge_policy::NoMergePolicy;
|
use crate::merge_policy::NoMergePolicy;
|
||||||
use crate::query::BooleanQuery;
|
use crate::query::BooleanQuery;
|
||||||
use crate::schema::*;
|
use crate::schema::*;
|
||||||
@@ -1036,21 +1036,21 @@ pub mod tests {
|
|||||||
let fast_field_reader_opt = segment_reader.fast_fields().u64(fast_field_unsigned);
|
let fast_field_reader_opt = segment_reader.fast_fields().u64(fast_field_unsigned);
|
||||||
assert!(fast_field_reader_opt.is_ok());
|
assert!(fast_field_reader_opt.is_ok());
|
||||||
let fast_field_reader = fast_field_reader_opt.unwrap();
|
let fast_field_reader = fast_field_reader_opt.unwrap();
|
||||||
assert_eq!(fast_field_reader.get(0), 4u64)
|
assert_eq!(fast_field_reader.get_val(0), 4u64)
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let fast_field_reader_res = segment_reader.fast_fields().i64(fast_field_signed);
|
let fast_field_reader_res = segment_reader.fast_fields().i64(fast_field_signed);
|
||||||
assert!(fast_field_reader_res.is_ok());
|
assert!(fast_field_reader_res.is_ok());
|
||||||
let fast_field_reader = fast_field_reader_res.unwrap();
|
let fast_field_reader = fast_field_reader_res.unwrap();
|
||||||
assert_eq!(fast_field_reader.get(0), 4i64)
|
assert_eq!(fast_field_reader.get_val(0), 4i64)
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let fast_field_reader_res = segment_reader.fast_fields().f64(fast_field_float);
|
let fast_field_reader_res = segment_reader.fast_fields().f64(fast_field_float);
|
||||||
assert!(fast_field_reader_res.is_ok());
|
assert!(fast_field_reader_res.is_ok());
|
||||||
let fast_field_reader = fast_field_reader_res.unwrap();
|
let fast_field_reader = fast_field_reader_res.unwrap();
|
||||||
assert_eq!(fast_field_reader.get(0), 4f64)
|
assert_eq!(fast_field_reader.get_val(0), 4f64)
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -639,10 +639,7 @@ Survey in 2016, 2017, and 2018."#;
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_collapse_overlapped_ranges() {
|
fn test_collapse_overlapped_ranges() {
|
||||||
assert_eq!(&collapse_overlapped_ranges(&[0..1, 2..3,]), &[0..1, 2..3]);
|
assert_eq!(&collapse_overlapped_ranges(&[0..1, 2..3,]), &[0..1, 2..3]);
|
||||||
assert_eq!(
|
assert_eq!(collapse_overlapped_ranges(&[0..1, 1..2,]), &[0..1, 1..2]);
|
||||||
collapse_overlapped_ranges(&vec![0..1, 1..2,]),
|
|
||||||
vec![0..1, 1..2]
|
|
||||||
);
|
|
||||||
assert_eq!(collapse_overlapped_ranges(&[0..2, 1..2,]), vec![0..2]);
|
assert_eq!(collapse_overlapped_ranges(&[0..2, 1..2,]), vec![0..2]);
|
||||||
assert_eq!(collapse_overlapped_ranges(&[0..2, 1..3,]), vec![0..3]);
|
assert_eq!(collapse_overlapped_ranges(&[0..2, 1..3,]), vec![0..3]);
|
||||||
assert_eq!(collapse_overlapped_ranges(&[0..3, 1..2,]), vec![0..3]);
|
assert_eq!(collapse_overlapped_ranges(&[0..3, 1..2,]), vec![0..3]);
|
||||||
|
|||||||
Reference in New Issue
Block a user