diff --git a/CHANGELOG.md b/CHANGELOG.md index f29e328f3..199e9c215 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ Tantivy 0.14.0 - Migrated tantivy error from the now deprecated `failure` crate to `thiserror` #760. (@hirevo) - API Change. Accessing the typed value off a `Schema::Value` now returns an Option instead of panicking if the type does not match. +Tantivy 0.13.2 +=================== +Bugfix. Acquiring a facet reader on a segment that does not contain any +doc with this facet returns `None`. (#896) + Tantivy 0.13.1 =================== Made `Query` and `Collector` `Send + Sync`. diff --git a/examples/faceted_search_with_tweaked_score.rs b/examples/faceted_search_with_tweaked_score.rs index ee493bd23..57331f822 100644 --- a/examples/faceted_search_with_tweaked_score.rs +++ b/examples/faceted_search_with_tweaked_score.rs @@ -56,7 +56,7 @@ fn main() -> tantivy::Result<()> { ); let top_docs_by_custom_score = TopDocs::with_limit(2).tweak_score(move |segment_reader: &SegmentReader| { - let mut ingredient_reader = segment_reader.facet_reader(ingredient).unwrap(); + let ingredient_reader = segment_reader.facet_reader(ingredient).unwrap(); let facet_dict = ingredient_reader.facet_dict(); let query_ords: HashSet = facets diff --git a/src/core/segment_reader.rs b/src/core/segment_reader.rs index 6ab50492f..df8fb88c3 100644 --- a/src/core/segment_reader.rs +++ b/src/core/segment_reader.rs @@ -112,8 +112,10 @@ impl SegmentReader { return None; } let term_ords_reader = self.fast_fields().u64s(field)?; - let termdict_source = self.termdict_composite.open_read(field)?; - let termdict = TermDictionary::from_source(&termdict_source); + let termdict = self.termdict_composite + .open_read(field) + .map(|source| TermDictionary::from_source(&source)) + .unwrap_or_else(TermDictionary::empty); let facet_reader = FacetReader::new(term_ords_reader, termdict); Some(facet_reader) } diff --git a/src/fastfield/facet_reader.rs b/src/fastfield/facet_reader.rs index 4bf8f3671..2d70d6377 100644 --- a/src/fastfield/facet_reader.rs +++ b/src/fastfield/facet_reader.rs @@ -73,7 +73,52 @@ impl FacetReader { } /// Return the list of facet ordinals associated to a document. - pub fn facet_ords(&mut self, doc: DocId, output: &mut Vec) { + pub fn facet_ords(&self, doc: DocId, output: &mut Vec) { self.term_ords.get_vals(doc, output); } } + +#[cfg(test)] +mod tests { + use crate::{Document, schema::{Facet, SchemaBuilder}}; + use crate::Index; + + #[test] + fn test_facet_not_populated_for_all_docs() -> crate::Result<()> { + let mut schema_builder = SchemaBuilder::default(); + let facet_field = schema_builder.add_facet_field("facet"); + let schema = schema_builder.build(); + let index = Index::create_in_ram(schema); + let mut index_writer = index.writer_with_num_threads(1, 10_000_000)?; + index_writer.add_document(doc!(facet_field=>Facet::from_text("/a/b"))); + index_writer.add_document(Document::default()); + index_writer.commit()?; + let searcher = index.reader()?.searcher(); + let facet_reader = searcher.segment_reader(0u32).facet_reader(facet_field).unwrap(); + let mut facet_ords = Vec::new(); + facet_reader.facet_ords(0u32, &mut facet_ords); + assert_eq!(&facet_ords, &[2u64]); + facet_reader.facet_ords(1u32, &mut facet_ords); + assert!(facet_ords.is_empty()); + Ok(()) + } + #[test] + fn test_facet_not_populated_for_any_docs() -> crate::Result<()> { + let mut schema_builder = SchemaBuilder::default(); + let facet_field = schema_builder.add_facet_field("facet"); + let schema = schema_builder.build(); + let index = Index::create_in_ram(schema); + let mut index_writer = index.writer_with_num_threads(1, 10_000_000)?; + index_writer.add_document(Document::default()); + index_writer.add_document(Document::default()); + index_writer.commit()?; + let searcher = index.reader()?.searcher(); + let facet_reader = searcher.segment_reader(0u32).facet_reader(facet_field).unwrap(); + let mut facet_ords = Vec::new(); + facet_reader.facet_ords(0u32, &mut facet_ords); + assert!(facet_ords.is_empty()); + facet_reader.facet_ords(1u32, &mut facet_ords); + assert!(facet_ords.is_empty()); + Ok(()) + } +} \ No newline at end of file diff --git a/src/fastfield/writer.rs b/src/fastfield/writer.rs index 375b9349d..dde7f4832 100644 --- a/src/fastfield/writer.rs +++ b/src/fastfield/writer.rs @@ -128,6 +128,7 @@ impl FastFieldsWriter { for field_writer in &self.single_value_writers { field_writer.serialize(serializer)?; } + for field_writer in &self.multi_values_writers { let field = field_writer.field(); field_writer.serialize(serializer, mapping.get(&field))?; diff --git a/src/indexer/segment_writer.rs b/src/indexer/segment_writer.rs index 1606b9d75..77be6aff0 100644 --- a/src/indexer/segment_writer.rs +++ b/src/indexer/segment_writer.rs @@ -166,7 +166,7 @@ impl SegmentWriter { if let Some(unordered_term_id) = unordered_term_id_opt { self.fast_field_writers .get_multivalue_writer(field) - .expect("multified writer for facet missing") + .expect("writer for facet missing") .add_val(unordered_term_id); } }