mirror of
https://github.com/meilisearch/MeiliSearch
synced 2025-07-04 20:37:15 +02:00
Simplify word level position DB into a word position DB
This commit is contained in:
parent
75d341d928
commit
3296bb243c
18 changed files with 220 additions and 545 deletions
|
@ -28,9 +28,9 @@ impl<'t, 'u, 'i> ClearDocuments<'t, 'u, 'i> {
|
|||
docid_word_positions,
|
||||
word_pair_proximity_docids,
|
||||
word_prefix_pair_proximity_docids,
|
||||
word_level_position_docids,
|
||||
word_position_docids,
|
||||
field_id_word_count_docids,
|
||||
word_prefix_level_position_docids,
|
||||
word_prefix_position_docids,
|
||||
facet_id_f64_docids,
|
||||
facet_id_string_docids,
|
||||
field_id_docid_facet_f64s,
|
||||
|
@ -64,9 +64,9 @@ impl<'t, 'u, 'i> ClearDocuments<'t, 'u, 'i> {
|
|||
docid_word_positions.clear(self.wtxn)?;
|
||||
word_pair_proximity_docids.clear(self.wtxn)?;
|
||||
word_prefix_pair_proximity_docids.clear(self.wtxn)?;
|
||||
word_level_position_docids.clear(self.wtxn)?;
|
||||
word_position_docids.clear(self.wtxn)?;
|
||||
field_id_word_count_docids.clear(self.wtxn)?;
|
||||
word_prefix_level_position_docids.clear(self.wtxn)?;
|
||||
word_prefix_position_docids.clear(self.wtxn)?;
|
||||
facet_id_f64_docids.clear(self.wtxn)?;
|
||||
facet_id_string_docids.clear(self.wtxn)?;
|
||||
field_id_docid_facet_f64s.clear(self.wtxn)?;
|
||||
|
|
|
@ -102,8 +102,8 @@ impl<'t, 'u, 'i> DeleteDocuments<'t, 'u, 'i> {
|
|||
word_pair_proximity_docids,
|
||||
field_id_word_count_docids,
|
||||
word_prefix_pair_proximity_docids,
|
||||
word_level_position_docids,
|
||||
word_prefix_level_position_docids,
|
||||
word_position_docids,
|
||||
word_prefix_position_docids,
|
||||
facet_id_f64_docids,
|
||||
facet_id_string_docids,
|
||||
field_id_docid_facet_f64s,
|
||||
|
@ -326,8 +326,7 @@ impl<'t, 'u, 'i> DeleteDocuments<'t, 'u, 'i> {
|
|||
drop(iter);
|
||||
|
||||
// We delete the documents ids that are under the word level position docids.
|
||||
let mut iter =
|
||||
word_level_position_docids.iter_mut(self.wtxn)?.remap_key_type::<ByteSlice>();
|
||||
let mut iter = word_position_docids.iter_mut(self.wtxn)?.remap_key_type::<ByteSlice>();
|
||||
while let Some(result) = iter.next() {
|
||||
let (bytes, mut docids) = result?;
|
||||
let previous_len = docids.len();
|
||||
|
@ -346,7 +345,7 @@ impl<'t, 'u, 'i> DeleteDocuments<'t, 'u, 'i> {
|
|||
|
||||
// We delete the documents ids that are under the word prefix level position docids.
|
||||
let mut iter =
|
||||
word_prefix_level_position_docids.iter_mut(self.wtxn)?.remap_key_type::<ByteSlice>();
|
||||
word_prefix_position_docids.iter_mut(self.wtxn)?.remap_key_type::<ByteSlice>();
|
||||
while let Some(result) = iter.next() {
|
||||
let (bytes, mut docids) = result?;
|
||||
let previous_len = docids.len();
|
||||
|
|
|
@ -14,13 +14,13 @@ use crate::{DocumentId, Result};
|
|||
/// Returns a grenad reader with the list of extracted words at positions and
|
||||
/// documents ids from the given chunk of docid word positions.
|
||||
#[logging_timer::time]
|
||||
pub fn extract_word_level_position_docids<R: io::Read>(
|
||||
pub fn extract_word_position_docids<R: io::Read>(
|
||||
mut docid_word_positions: grenad::Reader<R>,
|
||||
indexer: GrenadParameters,
|
||||
) -> Result<grenad::Reader<File>> {
|
||||
let max_memory = indexer.max_memory_by_thread();
|
||||
|
||||
let mut word_level_position_docids_sorter = create_sorter(
|
||||
let mut word_position_docids_sorter = create_sorter(
|
||||
merge_cbo_roaring_bitmaps,
|
||||
indexer.chunk_compression_type,
|
||||
indexer.chunk_compression_level,
|
||||
|
@ -37,15 +37,11 @@ pub fn extract_word_level_position_docids<R: io::Read>(
|
|||
for position in read_u32_ne_bytes(value) {
|
||||
key_buffer.clear();
|
||||
key_buffer.extend_from_slice(word_bytes);
|
||||
key_buffer.push(0); // tree level
|
||||
|
||||
// Levels are composed of left and right bounds.
|
||||
key_buffer.extend_from_slice(&position.to_be_bytes());
|
||||
key_buffer.extend_from_slice(&position.to_be_bytes());
|
||||
|
||||
word_level_position_docids_sorter.insert(&key_buffer, &document_id.to_ne_bytes())?;
|
||||
word_position_docids_sorter.insert(&key_buffer, &document_id.to_ne_bytes())?;
|
||||
}
|
||||
}
|
||||
|
||||
sorter_into_reader(word_level_position_docids_sorter, indexer)
|
||||
sorter_into_reader(word_position_docids_sorter, indexer)
|
||||
}
|
|
@ -5,8 +5,8 @@ mod extract_fid_docid_facet_values;
|
|||
mod extract_fid_word_count_docids;
|
||||
mod extract_geo_points;
|
||||
mod extract_word_docids;
|
||||
mod extract_word_level_position_docids;
|
||||
mod extract_word_pair_proximity_docids;
|
||||
mod extract_word_position_docids;
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::fs::File;
|
||||
|
@ -22,8 +22,8 @@ use self::extract_fid_docid_facet_values::extract_fid_docid_facet_values;
|
|||
use self::extract_fid_word_count_docids::extract_fid_word_count_docids;
|
||||
use self::extract_geo_points::extract_geo_points;
|
||||
use self::extract_word_docids::extract_word_docids;
|
||||
use self::extract_word_level_position_docids::extract_word_level_position_docids;
|
||||
use self::extract_word_pair_proximity_docids::extract_word_pair_proximity_docids;
|
||||
use self::extract_word_position_docids::extract_word_position_docids;
|
||||
use super::helpers::{
|
||||
into_clonable_grenad, keep_first_prefix_value_merge_roaring_bitmaps, merge_cbo_roaring_bitmaps,
|
||||
merge_readers, merge_roaring_bitmaps, CursorClonableMmap, GrenadParameters, MergeFn,
|
||||
|
@ -98,10 +98,10 @@ pub(crate) fn data_from_obkv_documents(
|
|||
docid_word_positions_chunks.clone(),
|
||||
indexer.clone(),
|
||||
lmdb_writer_sx.clone(),
|
||||
extract_word_level_position_docids,
|
||||
extract_word_position_docids,
|
||||
merge_cbo_roaring_bitmaps,
|
||||
TypedChunk::WordLevelPositionDocids,
|
||||
"word-level-position-docids",
|
||||
TypedChunk::WordPositionDocids,
|
||||
"word-position-docids",
|
||||
);
|
||||
|
||||
spawn_extraction_task(
|
||||
|
|
|
@ -27,7 +27,7 @@ pub use self::transform::{Transform, TransformOutput};
|
|||
use crate::documents::DocumentBatchReader;
|
||||
use crate::update::{
|
||||
Facets, UpdateBuilder, UpdateIndexingStep, WordPrefixDocids, WordPrefixPairProximityDocids,
|
||||
WordsLevelPositions, WordsPrefixesFst,
|
||||
WordPrefixPositionDocids, WordsPrefixesFst,
|
||||
};
|
||||
use crate::{Index, Result};
|
||||
|
||||
|
@ -412,8 +412,8 @@ impl<'t, 'u, 'i, 'a> IndexDocuments<'t, 'u, 'i, 'a> {
|
|||
total_databases: TOTAL_POSTING_DATABASE_COUNT,
|
||||
});
|
||||
|
||||
// Run the words level positions update operation.
|
||||
let mut builder = WordsLevelPositions::new(self.wtxn, self.index);
|
||||
// Run the words prefix position docids update operation.
|
||||
let mut builder = WordPrefixPositionDocids::new(self.wtxn, self.index);
|
||||
builder.chunk_compression_type = self.chunk_compression_type;
|
||||
builder.chunk_compression_level = self.chunk_compression_level;
|
||||
builder.max_nb_chunks = self.max_nb_chunks;
|
||||
|
|
|
@ -22,7 +22,7 @@ pub(crate) enum TypedChunk {
|
|||
FieldIdWordcountDocids(grenad::Reader<File>),
|
||||
NewDocumentsIds(RoaringBitmap),
|
||||
WordDocids(grenad::Reader<File>),
|
||||
WordLevelPositionDocids(grenad::Reader<File>),
|
||||
WordPositionDocids(grenad::Reader<File>),
|
||||
WordPairProximityDocids(grenad::Reader<File>),
|
||||
FieldIdFacetStringDocids(grenad::Reader<File>),
|
||||
FieldIdFacetNumberDocids(grenad::Reader<File>),
|
||||
|
@ -110,10 +110,10 @@ pub(crate) fn write_typed_chunk_into_index(
|
|||
index.put_words_fst(wtxn, &fst)?;
|
||||
is_merged_database = true;
|
||||
}
|
||||
TypedChunk::WordLevelPositionDocids(word_level_position_docids_iter) => {
|
||||
TypedChunk::WordPositionDocids(word_position_docids_iter) => {
|
||||
append_entries_into_database(
|
||||
word_level_position_docids_iter,
|
||||
&index.word_level_position_docids,
|
||||
word_position_docids_iter,
|
||||
&index.word_position_docids,
|
||||
wtxn,
|
||||
index_is_empty,
|
||||
|value, _buffer| Ok(value),
|
||||
|
|
|
@ -8,7 +8,7 @@ pub use self::update_builder::UpdateBuilder;
|
|||
pub use self::update_step::UpdateIndexingStep;
|
||||
pub use self::word_prefix_docids::WordPrefixDocids;
|
||||
pub use self::word_prefix_pair_proximity_docids::WordPrefixPairProximityDocids;
|
||||
pub use self::words_level_positions::WordsLevelPositions;
|
||||
pub use self::words_prefix_position_docids::WordPrefixPositionDocids;
|
||||
pub use self::words_prefixes_fst::WordsPrefixesFst;
|
||||
|
||||
mod available_documents_ids;
|
||||
|
@ -21,5 +21,5 @@ mod update_builder;
|
|||
mod update_step;
|
||||
mod word_prefix_docids;
|
||||
mod word_prefix_pair_proximity_docids;
|
||||
mod words_level_positions;
|
||||
mod words_prefix_position_docids;
|
||||
mod words_prefixes_fst;
|
||||
|
|
|
@ -1,268 +0,0 @@
|
|||
use std::convert::TryFrom;
|
||||
use std::fs::File;
|
||||
use std::num::NonZeroU32;
|
||||
use std::{cmp, str};
|
||||
|
||||
use fst::Streamer;
|
||||
use grenad::{CompressionType, Reader, Writer};
|
||||
use heed::types::{ByteSlice, DecodeIgnore, Str};
|
||||
use heed::{BytesEncode, Error};
|
||||
use log::debug;
|
||||
use roaring::RoaringBitmap;
|
||||
|
||||
use crate::error::{InternalError, SerializationError};
|
||||
use crate::heed_codec::{CboRoaringBitmapCodec, StrLevelPositionCodec};
|
||||
use crate::index::main_key::WORDS_PREFIXES_FST_KEY;
|
||||
use crate::update::index_documents::{
|
||||
create_sorter, create_writer, merge_cbo_roaring_bitmaps, sorter_into_lmdb_database,
|
||||
write_into_lmdb_database, writer_into_reader, WriteMethod,
|
||||
};
|
||||
use crate::{Index, Result, TreeLevel};
|
||||
|
||||
pub struct WordsLevelPositions<'t, 'u, 'i> {
|
||||
wtxn: &'t mut heed::RwTxn<'i, 'u>,
|
||||
index: &'i Index,
|
||||
pub(crate) chunk_compression_type: CompressionType,
|
||||
pub(crate) chunk_compression_level: Option<u32>,
|
||||
pub(crate) max_nb_chunks: Option<usize>,
|
||||
pub(crate) max_memory: Option<usize>,
|
||||
level_group_size: NonZeroU32,
|
||||
min_level_size: NonZeroU32,
|
||||
}
|
||||
|
||||
impl<'t, 'u, 'i> WordsLevelPositions<'t, 'u, 'i> {
|
||||
pub fn new(
|
||||
wtxn: &'t mut heed::RwTxn<'i, 'u>,
|
||||
index: &'i Index,
|
||||
) -> WordsLevelPositions<'t, 'u, 'i> {
|
||||
WordsLevelPositions {
|
||||
wtxn,
|
||||
index,
|
||||
chunk_compression_type: CompressionType::None,
|
||||
chunk_compression_level: None,
|
||||
max_nb_chunks: None,
|
||||
max_memory: None,
|
||||
level_group_size: NonZeroU32::new(4).unwrap(),
|
||||
min_level_size: NonZeroU32::new(5).unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn level_group_size(&mut self, value: NonZeroU32) -> &mut Self {
|
||||
self.level_group_size = NonZeroU32::new(cmp::max(value.get(), 2)).unwrap();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn min_level_size(&mut self, value: NonZeroU32) -> &mut Self {
|
||||
self.min_level_size = value;
|
||||
self
|
||||
}
|
||||
|
||||
#[logging_timer::time("WordsLevelPositions::{}")]
|
||||
pub fn execute(self) -> Result<()> {
|
||||
debug!("Computing and writing the word levels positions docids into LMDB on disk...");
|
||||
|
||||
let entries = compute_positions_levels(
|
||||
self.wtxn,
|
||||
self.index.word_docids.remap_data_type::<DecodeIgnore>(),
|
||||
self.index.word_level_position_docids,
|
||||
self.chunk_compression_type,
|
||||
self.chunk_compression_level,
|
||||
self.level_group_size,
|
||||
self.min_level_size,
|
||||
)?;
|
||||
|
||||
// The previously computed entries also defines the level 0 entries
|
||||
// so we can clear the database and append all of these entries.
|
||||
self.index.word_level_position_docids.clear(self.wtxn)?;
|
||||
|
||||
write_into_lmdb_database(
|
||||
self.wtxn,
|
||||
*self.index.word_level_position_docids.as_polymorph(),
|
||||
entries,
|
||||
|_, _| Err(InternalError::IndexingMergingKeys { process: "word level position" })?,
|
||||
WriteMethod::Append,
|
||||
)?;
|
||||
|
||||
// We compute the word prefix level positions database.
|
||||
self.index.word_prefix_level_position_docids.clear(self.wtxn)?;
|
||||
|
||||
let mut word_prefix_level_positions_docids_sorter = create_sorter(
|
||||
merge_cbo_roaring_bitmaps,
|
||||
self.chunk_compression_type,
|
||||
self.chunk_compression_level,
|
||||
self.max_nb_chunks,
|
||||
self.max_memory,
|
||||
);
|
||||
|
||||
// We insert the word prefix level positions where the level is equal to 0 and
|
||||
// corresponds to the word-prefix level positions where the prefixes appears
|
||||
// in the prefix FST previously constructed.
|
||||
let prefix_fst = self.index.words_prefixes_fst(self.wtxn)?;
|
||||
let db = self.index.word_level_position_docids.remap_data_type::<ByteSlice>();
|
||||
// iter over all prefixes in the prefix fst.
|
||||
let mut word_stream = prefix_fst.stream();
|
||||
while let Some(prefix_bytes) = word_stream.next() {
|
||||
let prefix = str::from_utf8(prefix_bytes).map_err(|_| {
|
||||
SerializationError::Decoding { db_name: Some(WORDS_PREFIXES_FST_KEY) }
|
||||
})?;
|
||||
|
||||
// iter over all lines of the DB where the key is prefixed by the current prefix.
|
||||
let mut iter = db
|
||||
.remap_key_type::<ByteSlice>()
|
||||
.prefix_iter(self.wtxn, &prefix_bytes)?
|
||||
.remap_key_type::<StrLevelPositionCodec>();
|
||||
while let Some(((_word, level, left, right), data)) = iter.next().transpose()? {
|
||||
// if level is 0, we push the line in the sorter
|
||||
// replacing the complete word by the prefix.
|
||||
if level == TreeLevel::min_value() {
|
||||
let key = (prefix, level, left, right);
|
||||
let bytes = StrLevelPositionCodec::bytes_encode(&key).unwrap();
|
||||
word_prefix_level_positions_docids_sorter.insert(bytes, data)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We finally write all the word prefix level positions docids with
|
||||
// a level equal to 0 into the LMDB database.
|
||||
sorter_into_lmdb_database(
|
||||
self.wtxn,
|
||||
*self.index.word_prefix_level_position_docids.as_polymorph(),
|
||||
word_prefix_level_positions_docids_sorter,
|
||||
merge_cbo_roaring_bitmaps,
|
||||
WriteMethod::Append,
|
||||
)?;
|
||||
|
||||
let entries = compute_positions_levels(
|
||||
self.wtxn,
|
||||
self.index.word_prefix_docids.remap_data_type::<DecodeIgnore>(),
|
||||
self.index.word_prefix_level_position_docids,
|
||||
self.chunk_compression_type,
|
||||
self.chunk_compression_level,
|
||||
self.level_group_size,
|
||||
self.min_level_size,
|
||||
)?;
|
||||
|
||||
// The previously computed entries also defines the level 0 entries
|
||||
// so we can clear the database and append all of these entries.
|
||||
self.index.word_prefix_level_position_docids.clear(self.wtxn)?;
|
||||
|
||||
write_into_lmdb_database(
|
||||
self.wtxn,
|
||||
*self.index.word_prefix_level_position_docids.as_polymorph(),
|
||||
entries,
|
||||
|_, _| {
|
||||
Err(InternalError::IndexingMergingKeys { process: "word prefix level position" })?
|
||||
},
|
||||
WriteMethod::Append,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the next number after or equal to `x` that is divisible by `d`.
|
||||
fn next_divisible(x: u32, d: u32) -> u32 {
|
||||
(x.saturating_sub(1) | (d - 1)) + 1
|
||||
}
|
||||
|
||||
/// Returns the previous number after or equal to `x` that is divisible by `d`,
|
||||
/// saturates on zero.
|
||||
fn previous_divisible(x: u32, d: u32) -> u32 {
|
||||
match x.checked_sub(d - 1) {
|
||||
Some(0) | None => 0,
|
||||
Some(x) => next_divisible(x, d),
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates all the words positions levels based on the levels zero (including the level zero).
|
||||
fn compute_positions_levels(
|
||||
rtxn: &heed::RoTxn,
|
||||
words_db: heed::Database<Str, DecodeIgnore>,
|
||||
words_positions_db: heed::Database<StrLevelPositionCodec, CboRoaringBitmapCodec>,
|
||||
compression_type: CompressionType,
|
||||
compression_level: Option<u32>,
|
||||
level_group_size: NonZeroU32,
|
||||
min_level_size: NonZeroU32,
|
||||
) -> Result<Reader<File>> {
|
||||
// It is forbidden to keep a cursor and write in a database at the same time with LMDB
|
||||
// therefore we write the facet levels entries into a grenad file before transfering them.
|
||||
let mut writer = tempfile::tempfile()
|
||||
.and_then(|file| create_writer(compression_type, compression_level, file))?;
|
||||
|
||||
for result in words_db.iter(rtxn)? {
|
||||
let (word, ()) = result?;
|
||||
|
||||
let level_0_range = {
|
||||
let left = (word, TreeLevel::min_value(), u32::min_value(), u32::min_value());
|
||||
let right = (word, TreeLevel::min_value(), u32::max_value(), u32::max_value());
|
||||
left..=right
|
||||
};
|
||||
|
||||
let first_level_size = words_positions_db
|
||||
.remap_data_type::<DecodeIgnore>()
|
||||
.range(rtxn, &level_0_range)?
|
||||
.fold(Ok(0u32), |count, result| result.and(count).map(|c| c + 1))?;
|
||||
|
||||
// Groups sizes are always a power of the original level_group_size and therefore a group
|
||||
// always maps groups of the previous level and never splits previous levels groups in half.
|
||||
let group_size_iter = (1u8..)
|
||||
.map(|l| (TreeLevel::try_from(l).unwrap(), level_group_size.get().pow(l as u32)))
|
||||
.take_while(|(_, s)| first_level_size / *s >= min_level_size.get());
|
||||
|
||||
// As specified in the documentation, we also write the level 0 entries.
|
||||
for result in words_positions_db.range(rtxn, &level_0_range)? {
|
||||
let ((word, level, left, right), docids) = result?;
|
||||
write_level_entry(&mut writer, word, level, left, right, &docids)?;
|
||||
}
|
||||
|
||||
for (level, group_size) in group_size_iter {
|
||||
let mut left = 0;
|
||||
let mut right = 0;
|
||||
let mut group_docids = RoaringBitmap::new();
|
||||
|
||||
for (i, result) in words_positions_db.range(rtxn, &level_0_range)?.enumerate() {
|
||||
let ((_word, _level, value, _right), docids) = result?;
|
||||
|
||||
if i == 0 {
|
||||
left = previous_divisible(value, group_size);
|
||||
right = left + (group_size - 1);
|
||||
}
|
||||
|
||||
if value > right {
|
||||
// we found the first bound of the next group, we must store the left
|
||||
// and right bounds associated with the docids.
|
||||
write_level_entry(&mut writer, word, level, left, right, &group_docids)?;
|
||||
|
||||
// We save the left bound for the new group and also reset the docids.
|
||||
group_docids = RoaringBitmap::new();
|
||||
left = previous_divisible(value, group_size);
|
||||
right = left + (group_size - 1);
|
||||
}
|
||||
|
||||
// The right bound is always the bound we run through.
|
||||
group_docids |= docids;
|
||||
}
|
||||
|
||||
if !group_docids.is_empty() {
|
||||
write_level_entry(&mut writer, word, level, left, right, &group_docids)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writer_into_reader(writer)
|
||||
}
|
||||
|
||||
fn write_level_entry(
|
||||
writer: &mut Writer<File>,
|
||||
word: &str,
|
||||
level: TreeLevel,
|
||||
left: u32,
|
||||
right: u32,
|
||||
ids: &RoaringBitmap,
|
||||
) -> Result<()> {
|
||||
let key = (word, level, left, right);
|
||||
let key = StrLevelPositionCodec::bytes_encode(&key).ok_or(Error::Encoding)?;
|
||||
let data = CboRoaringBitmapCodec::bytes_encode(&ids).ok_or(Error::Encoding)?;
|
||||
writer.insert(&key, &data)?;
|
||||
Ok(())
|
||||
}
|
105
milli/src/update/words_prefix_position_docids.rs
Normal file
105
milli/src/update/words_prefix_position_docids.rs
Normal file
|
@ -0,0 +1,105 @@
|
|||
use std::num::NonZeroU32;
|
||||
use std::{cmp, str};
|
||||
|
||||
use fst::Streamer;
|
||||
use grenad::CompressionType;
|
||||
use heed::types::ByteSlice;
|
||||
use heed::BytesEncode;
|
||||
use log::debug;
|
||||
|
||||
use crate::error::SerializationError;
|
||||
use crate::heed_codec::StrBEU32Codec;
|
||||
use crate::index::main_key::WORDS_PREFIXES_FST_KEY;
|
||||
use crate::update::index_documents::{
|
||||
create_sorter, merge_cbo_roaring_bitmaps, sorter_into_lmdb_database, WriteMethod,
|
||||
};
|
||||
use crate::{Index, Result};
|
||||
|
||||
pub struct WordPrefixPositionDocids<'t, 'u, 'i> {
|
||||
wtxn: &'t mut heed::RwTxn<'i, 'u>,
|
||||
index: &'i Index,
|
||||
pub(crate) chunk_compression_type: CompressionType,
|
||||
pub(crate) chunk_compression_level: Option<u32>,
|
||||
pub(crate) max_nb_chunks: Option<usize>,
|
||||
pub(crate) max_memory: Option<usize>,
|
||||
level_group_size: NonZeroU32,
|
||||
min_level_size: NonZeroU32,
|
||||
}
|
||||
|
||||
impl<'t, 'u, 'i> WordPrefixPositionDocids<'t, 'u, 'i> {
|
||||
pub fn new(
|
||||
wtxn: &'t mut heed::RwTxn<'i, 'u>,
|
||||
index: &'i Index,
|
||||
) -> WordPrefixPositionDocids<'t, 'u, 'i> {
|
||||
WordPrefixPositionDocids {
|
||||
wtxn,
|
||||
index,
|
||||
chunk_compression_type: CompressionType::None,
|
||||
chunk_compression_level: None,
|
||||
max_nb_chunks: None,
|
||||
max_memory: None,
|
||||
level_group_size: NonZeroU32::new(4).unwrap(),
|
||||
min_level_size: NonZeroU32::new(5).unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn level_group_size(&mut self, value: NonZeroU32) -> &mut Self {
|
||||
self.level_group_size = NonZeroU32::new(cmp::max(value.get(), 2)).unwrap();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn min_level_size(&mut self, value: NonZeroU32) -> &mut Self {
|
||||
self.min_level_size = value;
|
||||
self
|
||||
}
|
||||
|
||||
#[logging_timer::time("WordPrefixPositionDocids::{}")]
|
||||
pub fn execute(self) -> Result<()> {
|
||||
debug!("Computing and writing the word levels positions docids into LMDB on disk...");
|
||||
|
||||
self.index.word_prefix_position_docids.clear(self.wtxn)?;
|
||||
|
||||
let mut word_prefix_positions_docids_sorter = create_sorter(
|
||||
merge_cbo_roaring_bitmaps,
|
||||
self.chunk_compression_type,
|
||||
self.chunk_compression_level,
|
||||
self.max_nb_chunks,
|
||||
self.max_memory,
|
||||
);
|
||||
|
||||
// We insert the word prefix position and
|
||||
// corresponds to the word-prefix position where the prefixes appears
|
||||
// in the prefix FST previously constructed.
|
||||
let prefix_fst = self.index.words_prefixes_fst(self.wtxn)?;
|
||||
let db = self.index.word_position_docids.remap_data_type::<ByteSlice>();
|
||||
// iter over all prefixes in the prefix fst.
|
||||
let mut word_stream = prefix_fst.stream();
|
||||
while let Some(prefix_bytes) = word_stream.next() {
|
||||
let prefix = str::from_utf8(prefix_bytes).map_err(|_| {
|
||||
SerializationError::Decoding { db_name: Some(WORDS_PREFIXES_FST_KEY) }
|
||||
})?;
|
||||
|
||||
// iter over all lines of the DB where the key is prefixed by the current prefix.
|
||||
let mut iter = db
|
||||
.remap_key_type::<ByteSlice>()
|
||||
.prefix_iter(self.wtxn, &prefix_bytes)?
|
||||
.remap_key_type::<StrBEU32Codec>();
|
||||
while let Some(((_word, pos), data)) = iter.next().transpose()? {
|
||||
let key = (prefix, pos);
|
||||
let bytes = StrBEU32Codec::bytes_encode(&key).unwrap();
|
||||
word_prefix_positions_docids_sorter.insert(bytes, data)?;
|
||||
}
|
||||
}
|
||||
|
||||
// We finally write all the word prefix position docids into the LMDB database.
|
||||
sorter_into_lmdb_database(
|
||||
self.wtxn,
|
||||
*self.index.word_prefix_position_docids.as_polymorph(),
|
||||
word_prefix_positions_docids_sorter,
|
||||
merge_cbo_roaring_bitmaps,
|
||||
WriteMethod::Append,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue