// # 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};

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 = 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(())
}
