Struct tantivy::collector::FacetCollector

source ·
pub struct FacetCollector { /* private fields */ }
Expand description

Collector for faceting

The collector collects all facets. You need to configure it beforehand with the facet you want to extract.

This is done by calling .add_facet(...) with the root of the facet you want to extract as argument.

Facet counts will only be computed for the facet that are direct children of such a root facet.

For instance, if your index represents books, your hierarchy of facets may contain category, language.

The category facet may include subcategories. For instance, a book could belong to /category/fiction/fantasy.

If you request the facet counts for /category, the result will be the breakdown of counts for the direct children of /category (e.g. /category/fiction, /category/biography, /category/personal_development).

Once collection is finished, you can harvest its results in the form of a FacetCounts object, and extract your facet counts from it.

This implementation assumes you are working with a number of facets that is many hundreds of times smaller than your number of documents.

use tantivy::collector::FacetCollector;
use tantivy::query::AllQuery;
use tantivy::schema::{Facet, Schema, FacetOptions, TEXT};
use tantivy::{doc, Index};

fn example() -> tantivy::Result<()> {
    let mut schema_builder = Schema::builder();

    // Facet have their own specific type.
    // It is not a bad practise to put all of your
    // facet information in the same field.
    let facet = schema_builder.add_facet_field("facet", FacetOptions::default());
    let title = schema_builder.add_text_field("title", TEXT);
    let schema = schema_builder.build();
    let index = Index::create_in_ram(schema);
    {
        let mut index_writer = index.writer(15_000_000)?;
        // a document can be associated with any number of facets
        index_writer.add_document(doc!(
            title => "The Name of the Wind",
            facet => Facet::from("/lang/en"),
            facet => Facet::from("/category/fiction/fantasy")
        ))?;
        index_writer.add_document(doc!(
            title => "Dune",
            facet => Facet::from("/lang/en"),
            facet => Facet::from("/category/fiction/sci-fi")
        ))?;
        index_writer.add_document(doc!(
            title => "La Vénus d'Ille",
            facet => Facet::from("/lang/fr"),
            facet => Facet::from("/category/fiction/fantasy"),
            facet => Facet::from("/category/fiction/horror")
        ))?;
        index_writer.add_document(doc!(
            title => "The Diary of a Young Girl",
            facet => Facet::from("/lang/en"),
            facet => Facet::from("/category/biography")
        ))?;
        index_writer.commit()?;
    }
    let reader = index.reader()?;
    let searcher = reader.searcher();

    {
        let mut facet_collector = FacetCollector::for_field("facet");
        facet_collector.add_facet("/lang");
        facet_collector.add_facet("/category");
        let facet_counts = searcher.search(&AllQuery, &facet_collector)?;

        // This lists all of the facet counts
        let facets: Vec<(&Facet, u64)> = facet_counts
            .get("/category")
            .collect();
        assert_eq!(facets, vec![
            (&Facet::from("/category/biography"), 1),
            (&Facet::from("/category/fiction"), 3)
        ]);
    }

    {
        let mut facet_collector = FacetCollector::for_field("facet");
        facet_collector.add_facet("/category/fiction");
        let facet_counts = searcher.search(&AllQuery, &facet_collector)?;

        // This lists all of the facet counts
        let facets: Vec<(&Facet, u64)> = facet_counts
            .get("/category/fiction")
            .collect();
        assert_eq!(facets, vec![
            (&Facet::from("/category/fiction/fantasy"), 2),
            (&Facet::from("/category/fiction/horror"), 1),
            (&Facet::from("/category/fiction/sci-fi"), 1)
        ]);
    }

    {
        let mut facet_collector = FacetCollector::for_field("facet");
        facet_collector.add_facet("/category/fiction");
        let facet_counts = searcher.search(&AllQuery, &facet_collector)?;

        // This lists all of the facet counts
        let facets: Vec<(&Facet, u64)> = facet_counts.top_k("/category/fiction", 1);
        assert_eq!(facets, vec![
            (&Facet::from("/category/fiction/fantasy"), 2)
        ]);
    }

    {
        let mut facet_collector = FacetCollector::for_field("facet");
        facet_collector.add_facet("/");
        let facet_counts = searcher.search(&AllQuery, &facet_collector)?;

        // This lists all of the facet counts
        let facets: Vec<(&Facet, u64)> = facet_counts
            .get("/")
            .collect();
        assert_eq!(facets, vec![
            (&Facet::from("/category"), 4),
            (&Facet::from("/lang"), 4)
        ]);
    }

    Ok(())
}

Implementations§

source§

impl FacetCollector

source

pub fn for_field(field_name: impl ToString) -> FacetCollector

Create a facet collector to collect the facets from a specific facet Field.

This function does not check whether the field is of the proper type.

source

pub fn add_facet<T>(&mut self, facet_from: T)
where Facet: From<T>,

Adds a facet that we want to record counts

Adding facet Facet::from("/country") for instance, will record the counts of all of the direct children of the facet country (e.g. /country/FR, /country/UK).

Adding two facets within which one is the prefix of the other is forbidden. If you need the correct number of unique documents for two such facets, just add them in a separate FacetCollector.

Trait Implementations§

source§

impl Collector for FacetCollector

§

type Fruit = FacetCounts

Fruit is the type for the result of our collection. e.g. usize for the Count collector.
§

type Child = FacetSegmentCollector

Type of the SegmentCollector associated with this collector.
source§

fn for_segment( &self, _: SegmentOrdinal, reader: &SegmentReader ) -> Result<FacetSegmentCollector>

set_segment is called before beginning to enumerate on this segment.
source§

fn requires_scoring(&self) -> bool

Returns true iff the collector requires to compute scores for documents.
source§

fn merge_fruits( &self, segments_facet_counts: Vec<FacetCounts> ) -> Result<FacetCounts>

Combines the fruit associated with the collection of each segments into one fruit.
source§

fn collect_segment( &self, weight: &dyn Weight, segment_ord: u32, reader: &SegmentReader ) -> Result<<Self::Child as SegmentCollector>::Fruit>

Created a segment collector and

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> Downcast for T
where T: Any,

source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Sync + Send>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> Pointable for T

source§

const ALIGN: usize = _

The alignment of pointer.
§

type Init = T

The type for initializers.
source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> Fruit for T
where T: Send + Downcast,