mirror of
https://github.com/meilisearch/MeiliSearch
synced 2024-11-30 08:44:27 +01:00
Integrate facet level bulk update
Only the facet bulk update has been added so far, the incremental must be completely rewritten Factorize facet merging Fix facet level extraction
This commit is contained in:
parent
774ed28539
commit
14261f8f04
@ -120,6 +120,7 @@ pub struct WriterOperation {
|
|||||||
entry: EntryOperation,
|
entry: EntryOperation,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum Database {
|
pub enum Database {
|
||||||
Documents,
|
Documents,
|
||||||
ExternalDocumentsIds,
|
ExternalDocumentsIds,
|
||||||
@ -158,6 +159,18 @@ impl Database {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<FacetKind> for Database {
|
||||||
|
fn from(value: FacetKind) -> Self {
|
||||||
|
match value {
|
||||||
|
FacetKind::Number => Database::FacetIdF64NumberDocids,
|
||||||
|
FacetKind::String => Database::FacetIdStringDocids,
|
||||||
|
FacetKind::Null => Database::FacetIdIsNullDocids,
|
||||||
|
FacetKind::Empty => Database::FacetIdIsEmptyDocids,
|
||||||
|
FacetKind::Exists => Database::FacetIdExistsDocids,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl WriterOperation {
|
impl WriterOperation {
|
||||||
pub fn database(&self, index: &Index) -> heed::Database<Bytes, Bytes> {
|
pub fn database(&self, index: &Index) -> heed::Database<Bytes, Bytes> {
|
||||||
self.database.database(index)
|
self.database.database(index)
|
||||||
@ -395,8 +408,18 @@ pub struct FacetDocidsSender<'a> {
|
|||||||
|
|
||||||
impl DocidsSender for FacetDocidsSender<'_> {
|
impl DocidsSender for FacetDocidsSender<'_> {
|
||||||
fn write(&self, key: &[u8], value: &[u8]) -> StdResult<(), SendError<()>> {
|
fn write(&self, key: &[u8], value: &[u8]) -> StdResult<(), SendError<()>> {
|
||||||
let (database, key) = self.extract_database(key);
|
let (facet_kind, key) = FacetKind::extract_from_key(key);
|
||||||
let entry = EntryOperation::Write(KeyValueEntry::from_small_key_value(key, value));
|
let database = Database::from(facet_kind);
|
||||||
|
// let entry = EntryOperation::Write(KeyValueEntry::from_small_key_value(key, value));
|
||||||
|
let entry = match facet_kind {
|
||||||
|
// skip level group size
|
||||||
|
FacetKind::String | FacetKind::Number => {
|
||||||
|
// add facet group size
|
||||||
|
let value = [&[1], value].concat();
|
||||||
|
EntryOperation::Write(KeyValueEntry::from_small_key_value(key, &value))
|
||||||
|
}
|
||||||
|
_ => EntryOperation::Write(KeyValueEntry::from_small_key_value(key, value)),
|
||||||
|
};
|
||||||
match self.sender.send(WriterOperation { database, entry }) {
|
match self.sender.send(WriterOperation { database, entry }) {
|
||||||
Ok(()) => Ok(()),
|
Ok(()) => Ok(()),
|
||||||
Err(SendError(_)) => Err(SendError(())),
|
Err(SendError(_)) => Err(SendError(())),
|
||||||
@ -404,7 +427,8 @@ impl DocidsSender for FacetDocidsSender<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn delete(&self, key: &[u8]) -> StdResult<(), SendError<()>> {
|
fn delete(&self, key: &[u8]) -> StdResult<(), SendError<()>> {
|
||||||
let (database, key) = self.extract_database(key);
|
let (facet_kind, key) = FacetKind::extract_from_key(key);
|
||||||
|
let database = Database::from(facet_kind);
|
||||||
let entry = EntryOperation::Delete(KeyEntry::from_key(key));
|
let entry = EntryOperation::Delete(KeyEntry::from_key(key));
|
||||||
match self.sender.send(WriterOperation { database, entry }) {
|
match self.sender.send(WriterOperation { database, entry }) {
|
||||||
Ok(()) => Ok(()),
|
Ok(()) => Ok(()),
|
||||||
@ -413,19 +437,6 @@ impl DocidsSender for FacetDocidsSender<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FacetDocidsSender<'_> {
|
|
||||||
fn extract_database<'a>(&self, key: &'a [u8]) -> (Database, &'a [u8]) {
|
|
||||||
let database = match FacetKind::from(key[0]) {
|
|
||||||
FacetKind::Number => Database::FacetIdF64NumberDocids,
|
|
||||||
FacetKind::String => Database::FacetIdStringDocids,
|
|
||||||
FacetKind::Null => Database::FacetIdIsNullDocids,
|
|
||||||
FacetKind::Empty => Database::FacetIdIsEmptyDocids,
|
|
||||||
FacetKind::Exists => Database::FacetIdExistsDocids,
|
|
||||||
};
|
|
||||||
(database, &key[1..])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DocumentsSender<'a>(&'a MergerSender);
|
pub struct DocumentsSender<'a>(&'a MergerSender);
|
||||||
|
|
||||||
impl DocumentsSender<'_> {
|
impl DocumentsSender<'_> {
|
||||||
|
@ -129,7 +129,7 @@ impl FacetedDocidsExtractor {
|
|||||||
buffer.clear();
|
buffer.clear();
|
||||||
buffer.push(FacetKind::Number as u8);
|
buffer.push(FacetKind::Number as u8);
|
||||||
buffer.extend_from_slice(&fid.to_be_bytes());
|
buffer.extend_from_slice(&fid.to_be_bytes());
|
||||||
buffer.push(1); // level 0
|
buffer.push(0); // level 0
|
||||||
buffer.extend_from_slice(&ordered);
|
buffer.extend_from_slice(&ordered);
|
||||||
buffer.extend_from_slice(&n.to_be_bytes());
|
buffer.extend_from_slice(&n.to_be_bytes());
|
||||||
|
|
||||||
@ -145,7 +145,7 @@ impl FacetedDocidsExtractor {
|
|||||||
buffer.clear();
|
buffer.clear();
|
||||||
buffer.push(FacetKind::String as u8);
|
buffer.push(FacetKind::String as u8);
|
||||||
buffer.extend_from_slice(&fid.to_be_bytes());
|
buffer.extend_from_slice(&fid.to_be_bytes());
|
||||||
buffer.push(1); // level 0
|
buffer.push(0); // level 0
|
||||||
buffer.extend_from_slice(truncated.as_bytes());
|
buffer.extend_from_slice(truncated.as_bytes());
|
||||||
cache_fn(cached_sorter, &*buffer, docid).map_err(Into::into)
|
cache_fn(cached_sorter, &*buffer, docid).map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ mod facet_document;
|
|||||||
pub use extract_facets::FacetedDocidsExtractor;
|
pub use extract_facets::FacetedDocidsExtractor;
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum FacetKind {
|
pub enum FacetKind {
|
||||||
Number = 0,
|
Number = 0,
|
||||||
String = 1,
|
String = 1,
|
||||||
@ -24,3 +25,10 @@ impl From<u8> for FacetKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FacetKind {
|
||||||
|
pub fn extract_from_key<'k>(key: &'k [u8]) -> (FacetKind, &'k [u8]) {
|
||||||
|
debug_assert!(key.len() > 3);
|
||||||
|
(FacetKind::from(key[0]), &key[1..])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -13,18 +13,19 @@ pub use update_by_function::UpdateByFunction;
|
|||||||
use super::channel::*;
|
use super::channel::*;
|
||||||
use super::document_change::{Deletion, DocumentChange, Insertion, Update};
|
use super::document_change::{Deletion, DocumentChange, Insertion, Update};
|
||||||
use super::extract::*;
|
use super::extract::*;
|
||||||
use super::merger::merge_grenad_entries;
|
use super::merger::{merge_grenad_entries, FacetFieldIdsDelta};
|
||||||
use super::word_fst_builder::PrefixDelta;
|
use super::word_fst_builder::PrefixDelta;
|
||||||
use super::words_prefix_docids::{
|
use super::words_prefix_docids::{
|
||||||
compute_word_prefix_docids, compute_word_prefix_fid_docids, compute_word_prefix_position_docids,
|
compute_word_prefix_docids, compute_word_prefix_fid_docids, compute_word_prefix_position_docids,
|
||||||
};
|
};
|
||||||
use super::{StdResult, TopLevelMap};
|
use super::{StdResult, TopLevelMap};
|
||||||
use crate::documents::{PrimaryKey, DEFAULT_PRIMARY_KEY};
|
use crate::documents::{PrimaryKey, DEFAULT_PRIMARY_KEY};
|
||||||
|
use crate::facet::FacetType;
|
||||||
use crate::update::new::channel::ExtractorSender;
|
use crate::update::new::channel::ExtractorSender;
|
||||||
use crate::update::settings::InnerIndexSettings;
|
use crate::update::settings::InnerIndexSettings;
|
||||||
use crate::update::new::parallel_iterator_ext::ParallelIteratorExt;
|
use crate::update::new::parallel_iterator_ext::ParallelIteratorExt;
|
||||||
use crate::update::GrenadParameters;
|
|
||||||
use crate::{Error, FieldsIdsMap, GlobalFieldsIdsMap, Index, Result, UserError};
|
use crate::{Error, FieldsIdsMap, GlobalFieldsIdsMap, Index, Result, UserError};
|
||||||
|
use crate::update::{FacetsUpdateBulk, GrenadParameters};
|
||||||
|
|
||||||
mod document_deletion;
|
mod document_deletion;
|
||||||
mod document_operation;
|
mod document_operation;
|
||||||
@ -71,11 +72,11 @@ where
|
|||||||
let global_fields_ids_map_clone = global_fields_ids_map.clone();
|
let global_fields_ids_map_clone = global_fields_ids_map.clone();
|
||||||
|
|
||||||
thread::scope(|s| {
|
thread::scope(|s| {
|
||||||
|
let indexer_span = tracing::Span::current();
|
||||||
// TODO manage the errors correctly
|
// TODO manage the errors correctly
|
||||||
let current_span = tracing::Span::current();
|
|
||||||
let handle = Builder::new().name(S("indexer-extractors")).spawn_scoped(s, move || {
|
let handle = Builder::new().name(S("indexer-extractors")).spawn_scoped(s, move || {
|
||||||
pool.in_place_scope(|_s| {
|
pool.in_place_scope(|_s| {
|
||||||
let span = tracing::trace_span!(target: "indexing::documents", parent: ¤t_span, "extract");
|
let span = tracing::trace_span!(target: "indexing::documents", parent: &indexer_span, "extract");
|
||||||
let _entered = span.enter();
|
let _entered = span.enter();
|
||||||
let document_changes = document_changes.into_par_iter();
|
let document_changes = document_changes.into_par_iter();
|
||||||
|
|
||||||
@ -179,11 +180,11 @@ where
|
|||||||
})
|
})
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
let indexer_span = tracing::Span::current();
|
||||||
// TODO manage the errors correctly
|
// TODO manage the errors correctly
|
||||||
let current_span = tracing::Span::current();
|
|
||||||
let merger_thread = Builder::new().name(S("indexer-merger")).spawn_scoped(s, move || {
|
let merger_thread = Builder::new().name(S("indexer-merger")).spawn_scoped(s, move || {
|
||||||
let span =
|
let span =
|
||||||
tracing::trace_span!(target: "indexing::documents", parent: ¤t_span, "merge");
|
tracing::trace_span!(target: "indexing::documents", parent: &indexer_span, "merge");
|
||||||
let _entered = span.enter();
|
let _entered = span.enter();
|
||||||
let rtxn = index.read_txn().unwrap();
|
let rtxn = index.read_txn().unwrap();
|
||||||
merge_grenad_entries(
|
merge_grenad_entries(
|
||||||
@ -211,17 +212,12 @@ where
|
|||||||
handle.join().unwrap()?;
|
handle.join().unwrap()?;
|
||||||
let merger_result = merger_thread.join().unwrap()?;
|
let merger_result = merger_thread.join().unwrap()?;
|
||||||
|
|
||||||
if let Some(prefix_delta) = merger_result.prefix_delta {
|
if let Some(facet_field_ids_delta) = merger_result.facet_field_ids_delta {
|
||||||
let span = tracing::trace_span!(target: "indexing", "prefix");
|
compute_facet_level_database(index, wtxn, facet_field_ids_delta)?;
|
||||||
let _entered = span.enter();
|
}
|
||||||
|
|
||||||
let PrefixDelta { modified, deleted } = prefix_delta;
|
if let Some(prefix_delta) = merger_result.prefix_delta {
|
||||||
// Compute word prefix docids
|
compute_prefix_database(index, wtxn, prefix_delta)?;
|
||||||
compute_word_prefix_docids(wtxn, index, &modified, &deleted)?;
|
|
||||||
// Compute word prefix fid docids
|
|
||||||
compute_word_prefix_fid_docids(wtxn, index, &modified, &deleted)?;
|
|
||||||
// Compute word prefix position docids
|
|
||||||
compute_word_prefix_position_docids(wtxn, index, &modified, &deleted)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(()) as Result<_>
|
Ok(()) as Result<_>
|
||||||
@ -238,6 +234,51 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(level = "trace", skip_all, target = "indexing::prefix")]
|
||||||
|
fn compute_prefix_database(
|
||||||
|
index: &Index,
|
||||||
|
wtxn: &mut RwTxn,
|
||||||
|
prefix_delta: PrefixDelta,
|
||||||
|
) -> Result<()> {
|
||||||
|
let PrefixDelta { modified, deleted } = prefix_delta;
|
||||||
|
// Compute word prefix docids
|
||||||
|
compute_word_prefix_docids(wtxn, index, &modified, &deleted)?;
|
||||||
|
// Compute word prefix fid docids
|
||||||
|
compute_word_prefix_fid_docids(wtxn, index, &modified, &deleted)?;
|
||||||
|
// Compute word prefix position docids
|
||||||
|
compute_word_prefix_position_docids(wtxn, index, &modified, &deleted)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(level = "trace", skip_all, target = "indexing::facet_field_ids")]
|
||||||
|
fn compute_facet_level_database(
|
||||||
|
index: &Index,
|
||||||
|
wtxn: &mut RwTxn,
|
||||||
|
facet_field_ids_delta: FacetFieldIdsDelta,
|
||||||
|
) -> Result<()> {
|
||||||
|
if let Some(modified_facet_string_ids) = facet_field_ids_delta.modified_facet_string_ids() {
|
||||||
|
let span = tracing::trace_span!(target: "indexing::facet_field_ids", "string");
|
||||||
|
let _entered = span.enter();
|
||||||
|
FacetsUpdateBulk::new_not_updating_level_0(
|
||||||
|
index,
|
||||||
|
modified_facet_string_ids,
|
||||||
|
FacetType::String,
|
||||||
|
)
|
||||||
|
.execute(wtxn)?;
|
||||||
|
}
|
||||||
|
if let Some(modified_facet_number_ids) = facet_field_ids_delta.modified_facet_number_ids() {
|
||||||
|
let span = tracing::trace_span!(target: "indexing::facet_field_ids", "number");
|
||||||
|
let _entered = span.enter();
|
||||||
|
FacetsUpdateBulk::new_not_updating_level_0(
|
||||||
|
index,
|
||||||
|
modified_facet_number_ids,
|
||||||
|
FacetType::Number,
|
||||||
|
)
|
||||||
|
.execute(wtxn)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// TODO: GrenadParameters::default() should be removed in favor a passed parameter
|
/// TODO: GrenadParameters::default() should be removed in favor a passed parameter
|
||||||
/// TODO: manage the errors correctly
|
/// TODO: manage the errors correctly
|
||||||
/// TODO: we must have a single trait that also gives the extractor type
|
/// TODO: we must have a single trait that also gives the extractor type
|
||||||
|
@ -16,7 +16,9 @@ use crate::update::del_add::DelAdd;
|
|||||||
use crate::update::new::channel::MergerOperation;
|
use crate::update::new::channel::MergerOperation;
|
||||||
use crate::update::new::word_fst_builder::WordFstBuilder;
|
use crate::update::new::word_fst_builder::WordFstBuilder;
|
||||||
use crate::update::MergeDeladdCboRoaringBitmaps;
|
use crate::update::MergeDeladdCboRoaringBitmaps;
|
||||||
use crate::{CboRoaringBitmapCodec, Error, GeoPoint, GlobalFieldsIdsMap, Index, Prefix, Result};
|
use crate::{
|
||||||
|
CboRoaringBitmapCodec, Error, FieldId, GeoPoint, GlobalFieldsIdsMap, Index, Prefix, Result,
|
||||||
|
};
|
||||||
|
|
||||||
/// TODO We must return some infos/stats
|
/// TODO We must return some infos/stats
|
||||||
#[tracing::instrument(level = "trace", skip_all, target = "indexing::documents", name = "merge")]
|
#[tracing::instrument(level = "trace", skip_all, target = "indexing::documents", name = "merge")]
|
||||||
@ -188,13 +190,17 @@ pub fn merge_grenad_entries(
|
|||||||
let span =
|
let span =
|
||||||
tracing::trace_span!(target: "indexing::documents::merge", "facet_docids");
|
tracing::trace_span!(target: "indexing::documents::merge", "facet_docids");
|
||||||
let _entered = span.enter();
|
let _entered = span.enter();
|
||||||
|
let mut facet_field_ids_delta = FacetFieldIdsDelta::new();
|
||||||
merge_and_send_facet_docids(
|
merge_and_send_facet_docids(
|
||||||
merger,
|
merger,
|
||||||
FacetDatabases::new(index),
|
FacetDatabases::new(index),
|
||||||
rtxn,
|
rtxn,
|
||||||
&mut buffer,
|
&mut buffer,
|
||||||
sender.facet_docids(),
|
sender.facet_docids(),
|
||||||
|
&mut facet_field_ids_delta,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
merger_result.facet_field_ids_delta = Some(facet_field_ids_delta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -218,6 +224,8 @@ pub fn merge_grenad_entries(
|
|||||||
pub struct MergerResult {
|
pub struct MergerResult {
|
||||||
/// The delta of the prefixes
|
/// The delta of the prefixes
|
||||||
pub prefix_delta: Option<PrefixDelta>,
|
pub prefix_delta: Option<PrefixDelta>,
|
||||||
|
/// The field ids that have been modified
|
||||||
|
pub facet_field_ids_delta: Option<FacetFieldIdsDelta>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GeoExtractor {
|
pub struct GeoExtractor {
|
||||||
@ -308,20 +316,23 @@ fn merge_and_send_facet_docids(
|
|||||||
rtxn: &RoTxn<'_>,
|
rtxn: &RoTxn<'_>,
|
||||||
buffer: &mut Vec<u8>,
|
buffer: &mut Vec<u8>,
|
||||||
docids_sender: impl DocidsSender,
|
docids_sender: impl DocidsSender,
|
||||||
|
facet_field_ids_delta: &mut FacetFieldIdsDelta,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut merger_iter = merger.into_stream_merger_iter().unwrap();
|
let mut merger_iter = merger.into_stream_merger_iter().unwrap();
|
||||||
while let Some((key, deladd)) = merger_iter.next().unwrap() {
|
while let Some((key, deladd)) = merger_iter.next().unwrap() {
|
||||||
let current = database.get(rtxn, key)?;
|
let current = database.get_cbo_roaring_bytes_value(rtxn, key)?;
|
||||||
let deladd: &KvReaderDelAdd = deladd.into();
|
let deladd: &KvReaderDelAdd = deladd.into();
|
||||||
let del = deladd.get(DelAdd::Deletion);
|
let del = deladd.get(DelAdd::Deletion);
|
||||||
let add = deladd.get(DelAdd::Addition);
|
let add = deladd.get(DelAdd::Addition);
|
||||||
|
|
||||||
match merge_cbo_bitmaps(current, del, add)? {
|
match merge_cbo_bitmaps(current, del, add)? {
|
||||||
Operation::Write(bitmap) => {
|
Operation::Write(bitmap) => {
|
||||||
|
facet_field_ids_delta.register_from_key(key);
|
||||||
let value = cbo_bitmap_serialize_into_vec(&bitmap, buffer);
|
let value = cbo_bitmap_serialize_into_vec(&bitmap, buffer);
|
||||||
docids_sender.write(key, value).unwrap();
|
docids_sender.write(key, value).unwrap();
|
||||||
}
|
}
|
||||||
Operation::Delete => {
|
Operation::Delete => {
|
||||||
|
facet_field_ids_delta.register_from_key(key);
|
||||||
docids_sender.delete(key).unwrap();
|
docids_sender.delete(key).unwrap();
|
||||||
}
|
}
|
||||||
Operation::Ignore => (),
|
Operation::Ignore => (),
|
||||||
@ -331,43 +342,84 @@ fn merge_and_send_facet_docids(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FacetDatabases {
|
struct FacetDatabases<'a> {
|
||||||
/// Maps the facet field id and the docids for which this field exists
|
index: &'a Index,
|
||||||
facet_id_exists_docids: Database<Bytes, Bytes>,
|
|
||||||
/// Maps the facet field id and the docids for which this field is set as null
|
|
||||||
facet_id_is_null_docids: Database<Bytes, Bytes>,
|
|
||||||
/// Maps the facet field id and the docids for which this field is considered empty
|
|
||||||
facet_id_is_empty_docids: Database<Bytes, Bytes>,
|
|
||||||
/// Maps the facet field id and ranges of numbers with the docids that corresponds to them.
|
|
||||||
facet_id_f64_docids: Database<Bytes, Bytes>,
|
|
||||||
/// Maps the facet field id and ranges of strings with the docids that corresponds to them.
|
|
||||||
facet_id_string_docids: Database<Bytes, Bytes>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FacetDatabases {
|
impl<'a> FacetDatabases<'a> {
|
||||||
fn new(index: &Index) -> Self {
|
fn new(index: &'a Index) -> Self {
|
||||||
Self {
|
Self { index }
|
||||||
facet_id_exists_docids: index.facet_id_exists_docids.remap_types(),
|
|
||||||
facet_id_is_null_docids: index.facet_id_is_null_docids.remap_types(),
|
|
||||||
facet_id_is_empty_docids: index.facet_id_is_empty_docids.remap_types(),
|
|
||||||
facet_id_f64_docids: index.facet_id_f64_docids.remap_types(),
|
|
||||||
facet_id_string_docids: index.facet_id_string_docids.remap_types(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get<'a>(&self, rtxn: &'a RoTxn<'_>, key: &[u8]) -> heed::Result<Option<&'a [u8]>> {
|
fn get_cbo_roaring_bytes_value<'t>(
|
||||||
let (facet_kind, key) = self.extract_facet_kind(key);
|
&self,
|
||||||
|
rtxn: &'t RoTxn<'_>,
|
||||||
|
key: &[u8],
|
||||||
|
) -> heed::Result<Option<&'t [u8]>> {
|
||||||
|
let (facet_kind, key) = FacetKind::extract_from_key(key);
|
||||||
|
|
||||||
|
let value =
|
||||||
|
super::channel::Database::from(facet_kind).database(self.index).get(rtxn, key)?;
|
||||||
match facet_kind {
|
match facet_kind {
|
||||||
FacetKind::Exists => self.facet_id_exists_docids.get(rtxn, key),
|
// skip level group size
|
||||||
FacetKind::Null => self.facet_id_is_null_docids.get(rtxn, key),
|
FacetKind::String | FacetKind::Number => Ok(value.map(|v| &v[1..])),
|
||||||
FacetKind::Empty => self.facet_id_is_empty_docids.get(rtxn, key),
|
_ => Ok(value),
|
||||||
FacetKind::Number => self.facet_id_f64_docids.get(rtxn, key),
|
}
|
||||||
FacetKind::String => self.facet_id_string_docids.get(rtxn, key),
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct FacetFieldIdsDelta {
|
||||||
|
/// The field ids that have been modified
|
||||||
|
modified_facet_string_ids: HashSet<FieldId>,
|
||||||
|
modified_facet_number_ids: HashSet<FieldId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FacetFieldIdsDelta {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
modified_facet_string_ids: HashSet::new(),
|
||||||
|
modified_facet_number_ids: HashSet::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_facet_kind<'a>(&self, key: &'a [u8]) -> (FacetKind, &'a [u8]) {
|
fn register_facet_string_id(&mut self, field_id: FieldId) {
|
||||||
(FacetKind::from(key[0]), &key[1..])
|
self.modified_facet_string_ids.insert(field_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_facet_number_id(&mut self, field_id: FieldId) {
|
||||||
|
self.modified_facet_number_ids.insert(field_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_from_key(&mut self, key: &[u8]) {
|
||||||
|
let (facet_kind, field_id) = self.extract_key_data(key);
|
||||||
|
match facet_kind {
|
||||||
|
FacetKind::Number => self.register_facet_number_id(field_id),
|
||||||
|
FacetKind::String => self.register_facet_string_id(field_id),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_key_data<'a>(&self, key: &'a [u8]) -> (FacetKind, FieldId) {
|
||||||
|
let facet_kind = FacetKind::from(key[0]);
|
||||||
|
let field_id = FieldId::from_be_bytes([key[1], key[2]]);
|
||||||
|
(facet_kind, field_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn modified_facet_string_ids(&self) -> Option<Vec<FieldId>> {
|
||||||
|
if self.modified_facet_string_ids.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(self.modified_facet_string_ids.iter().copied().collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn modified_facet_number_ids(&self) -> Option<Vec<FieldId>> {
|
||||||
|
if self.modified_facet_number_ids.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(self.modified_facet_number_ids.iter().copied().collect())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -396,11 +448,13 @@ fn merge_cbo_bitmaps(
|
|||||||
(Some(current), None, Some(add)) => Ok(Operation::Write(current | add)),
|
(Some(current), None, Some(add)) => Ok(Operation::Write(current | add)),
|
||||||
(Some(current), Some(del), add) => {
|
(Some(current), Some(del), add) => {
|
||||||
let output = match add {
|
let output = match add {
|
||||||
Some(add) => (current - del) | add,
|
Some(add) => (¤t - del) | add,
|
||||||
None => current - del,
|
None => ¤t - del,
|
||||||
};
|
};
|
||||||
if output.is_empty() {
|
if output.is_empty() {
|
||||||
Ok(Operation::Delete)
|
Ok(Operation::Delete)
|
||||||
|
} else if current == output {
|
||||||
|
Ok(Operation::Ignore)
|
||||||
} else {
|
} else {
|
||||||
Ok(Operation::Write(output))
|
Ok(Operation::Write(output))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user