• Jump To … +
    aggregation.rs basic_search.rs custom_collector.rs custom_tokenizer.rs date_time_field.rs deleting_updating_documents.rs faceted_search.rs faceted_search_with_tweaked_score.rs fuzzy_search.rs index_from_multiple_threads.rs index_with_json.rs integer_range_search.rs ip_field.rs iterating_docs_and_positions.rs json_field.rs phrase_prefix_search.rs pre_tokenized_text.rs snippet.rs stop_words.rs warmer.rs
  • §

    Faceted Search

    This example covers the faceted search functionalities of tantivy.

    We will :

    • define a text field “name” in our schema
    • define a facet field “classification” in our schema
    • create an index in memory
    • index few documents with respective facets in our index
    • search and count the number of documents that the classifications start the facet “/Felidae”
    • Search the facet “/Felidae/Pantherinae” and count the number of documents that the classifications include the facet.

  • §

    Importing tantivy…

    use tantivy::collector::FacetCollector;
    use tantivy::query::{AllQuery, TermQuery};
    use tantivy::schema::*;
    use tantivy::{doc, Index, IndexWriter};
    
    fn main() -> tantivy::Result<()> {
  • §

    Let’s create a temporary directory for the sake of this example

        let mut schema_builder = Schema::builder();
    
        let name = schema_builder.add_text_field("name", TEXT | STORED);
  • §

    this is our faceted field: its scientific classification

        let classification = schema_builder.add_facet_field("classification", FacetOptions::default());
    
        let schema = schema_builder.build();
        let index = Index::create_in_ram(schema);
    
        let mut index_writer: IndexWriter = index.writer(30_000_000)?;
  • §

    For convenience, tantivy also comes with a macro to reduce the boilerplate above.

        index_writer.add_document(doc!(
            name => "Cat",
            classification => Facet::from("/Felidae/Felinae/Felis")
        ))?;
        index_writer.add_document(doc!(
            name => "Canada lynx",
            classification => Facet::from("/Felidae/Felinae/Lynx")
        ))?;
        index_writer.add_document(doc!(
            name => "Cheetah",
            classification => Facet::from("/Felidae/Felinae/Acinonyx")
        ))?;
        index_writer.add_document(doc!(
            name => "Tiger",
            classification => Facet::from("/Felidae/Pantherinae/Panthera")
        ))?;
        index_writer.add_document(doc!(
            name => "Lion",
            classification => Facet::from("/Felidae/Pantherinae/Panthera")
        ))?;
        index_writer.add_document(doc!(
            name => "Jaguar",
            classification => Facet::from("/Felidae/Pantherinae/Panthera")
        ))?;
        index_writer.add_document(doc!(
            name => "Sunda clouded leopard",
            classification => Facet::from("/Felidae/Pantherinae/Neofelis")
        ))?;
        index_writer.add_document(doc!(
            name => "Fossa",
            classification => Facet::from("/Eupleridae/Cryptoprocta")
        ))?;
        index_writer.commit()?;
    
        let reader = index.reader()?;
        let searcher = reader.searcher();
        {
            let mut facet_collector = FacetCollector::for_field("classification");
            facet_collector.add_facet("/Felidae");
            let facet_counts = searcher.search(&AllQuery, &facet_collector)?;
  • §

    This lists all of the facet counts, right below “/Felidae”.

            let facets: Vec<(&Facet, u64)> = facet_counts.get("/Felidae").collect();
            assert_eq!(
                facets,
                vec![
                    (&Facet::from("/Felidae/Felinae"), 3),
                    (&Facet::from("/Felidae/Pantherinae"), 4),
                ]
            );
        }
  • §

    Facets are also searchable.

    For instance a common UI pattern is to allow the user someone to click on a facet link (e.g: Pantherinae) to drill down and filter the current result set with this subfacet.

    The search would then look as follows.

  • §

    Check the reference doc for different ways to create a Facet object.

        {
            let facet = Facet::from("/Felidae/Pantherinae");
            let facet_term = Term::from_facet(classification, &facet);
            let facet_term_query = TermQuery::new(facet_term, IndexRecordOption::Basic);
            let mut facet_collector = FacetCollector::for_field("classification");
            facet_collector.add_facet("/Felidae/Pantherinae");
            let facet_counts = searcher.search(&facet_term_query, &facet_collector)?;
            let facets: Vec<(&Facet, u64)> = facet_counts.get("/Felidae/Pantherinae").collect();
            assert_eq!(
                facets,
                vec![
                    (&Facet::from("/Felidae/Pantherinae/Neofelis"), 1),
                    (&Facet::from("/Felidae/Pantherinae/Panthera"), 3),
                ]
            );
        }
    
        Ok(())
    }