    001    package org.apache.lucene.demo.facet;
    002
    003    import java.io.IOException;
    004    import java.util.ArrayList;
    005    import java.util.List;
    006
    007    import org.apache.lucene.analysis.core.WhitespaceAnalyzer;
    008    import org.apache.lucene.document.Document;
    009    import org.apache.lucene.facet.index.FacetFields;
    010    import org.apache.lucene.facet.params.FacetSearchParams;
    011    import org.apache.lucene.facet.search.CountFacetRequest;
    012    import org.apache.lucene.facet.search.DrillDownQuery;
    013    import org.apache.lucene.facet.search.FacetResult;
    014    import org.apache.lucene.facet.search.FacetsCollector;
    015    import org.apache.lucene.facet.taxonomy.CategoryPath;
    016    import org.apache.lucene.facet.taxonomy.TaxonomyReader;
    017    import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyReader;
    018    import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyWriter;
    019    import org.apache.lucene.index.DirectoryReader;
    020    import org.apache.lucene.index.IndexWriter;
    021    import org.apache.lucene.index.IndexWriterConfig;
    022    import org.apache.lucene.search.IndexSearcher;
    023    import org.apache.lucene.search.MatchAllDocsQuery;
    024    import org.apache.lucene.store.Directory;
    025    import org.apache.lucene.store.RAMDirectory;
    026
    027    /*
    028     * Licensed to the Apache Software Foundation (ASF) under one or more
    029     * contributor license agreements.  See the NOTICE file distributed with
    030     * this work for additional information regarding copyright ownership.
    031     * The ASF licenses this file to You under the Apache License, Version 2.0
    032     * (the "License"); you may not use this file except in compliance with
    033     * the License.  You may obtain a copy of the License at
    034     *
    035     *     http://www.apache.org/licenses/LICENSE-2.0
    036     *
    037     * Unless required by applicable law or agreed to in writing, software
    038     * distributed under the License is distributed on an "AS IS" BASIS,
    039     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    040     * See the License for the specific language governing permissions and
    041     * limitations under the License.
    042     */
    043
    044    /** Shows simple usage of faceted indexing and search. */
    045    public class SimpleFacetsExample {
    046
    047      private final Directory indexDir = new RAMDirectory();
    048      private final Directory taxoDir = new RAMDirectory();
    049
    050      /** Empty constructor */
    051      public SimpleFacetsExample() {}
    052
    053      private void add(IndexWriter indexWriter, FacetFields facetFields, String ... categoryPaths) throws IOException {
    054        Document doc = new Document();
    055
    056        List<CategoryPath> paths = new ArrayList<CategoryPath>();
    057        for (String categoryPath : categoryPaths) {
    058          paths.add(new CategoryPath(categoryPath, '/'));
    059        }
    060        facetFields.addFields(doc, paths);
    061        indexWriter.addDocument(doc);
    062      }
    063
    064      /** Build the example index. */
    065      private void index() throws IOException {
    066        IndexWriter indexWriter = new IndexWriter(indexDir, new IndexWriterConfig(FacetExamples.EXAMPLES_VER,
    067            new WhitespaceAnalyzer(FacetExamples.EXAMPLES_VER)));
    068
    069        // Writes facet ords to a separate directory from the main index
    070        DirectoryTaxonomyWriter taxoWriter = new DirectoryTaxonomyWriter(taxoDir, IndexWriterConfig.OpenMode.CREATE);
    071
    072        // Reused across documents, to add the necessary facet fields
    073        FacetFields facetFields = new FacetFields(taxoWriter);
    074
    075        add(indexWriter, facetFields, "Author/Bob", "Publish Date/2010/10/15");
    076        add(indexWriter, facetFields, "Author/Lisa", "Publish Date/2010/10/20");
    077        add(indexWriter, facetFields, "Author/Lisa", "Publish Date/2012/1/1");
    078        add(indexWriter, facetFields, "Author/Susan", "Publish Date/2012/1/7");
    079        add(indexWriter, facetFields, "Author/Frank", "Publish Date/1999/5/5");
    080
    081        indexWriter.close();
    082        taxoWriter.close();
    083      }
    084
    085      /** User runs a query and counts facets. */
    086      private List<FacetResult> search() throws IOException {
    087        DirectoryReader indexReader = DirectoryReader.open(indexDir);
    088        IndexSearcher searcher = new IndexSearcher(indexReader);
    089        TaxonomyReader taxoReader = new DirectoryTaxonomyReader(taxoDir);
    090
    091        // Count both "Publish Date" and "Author" dimensions
    092        FacetSearchParams fsp = new FacetSearchParams(
    093            new CountFacetRequest(new CategoryPath("Publish Date"), 10),
    094            new CountFacetRequest(new CategoryPath("Author"), 10));
    095
    096        // Aggregatses the facet counts
    097        FacetsCollector fc = FacetsCollector.create(fsp, searcher.getIndexReader(), taxoReader);
    098
    099        // MatchAllDocsQuery is for "browsing" (counts facets
    100        // for all non-deleted docs in the index); normally
    101        // you'd use a "normal" query, and use MultiCollector to
    102        // wrap collecting the "normal" hits and also facets:
    103        searcher.search(new MatchAllDocsQuery(), fc);
    104
    105        // Retrieve results
    106        List<FacetResult> facetResults = fc.getFacetResults();
    107
    108        indexReader.close();
    109        taxoReader.close();
    110
    111        return facetResults;
    112      }
    113
    114      /** User drills down on 'Publish date/2010'. */
    115      private List<FacetResult> drillDown() throws IOException {
    116        DirectoryReader indexReader = DirectoryReader.open(indexDir);
    117        IndexSearcher searcher = new IndexSearcher(indexReader);
    118        TaxonomyReader taxoReader = new DirectoryTaxonomyReader(taxoDir);
    119
    120        // Now user drills down on Publish Date/2010:
    121        FacetSearchParams fsp = new FacetSearchParams(new CountFacetRequest(new CategoryPath("Author"), 10));
    122        DrillDownQuery q = new DrillDownQuery(fsp.indexingParams, new MatchAllDocsQuery());
    123        q.add(new CategoryPath("Publish Date/2010", '/'));
    124        FacetsCollector fc = FacetsCollector.create(fsp, searcher.getIndexReader(), taxoReader);
    125        searcher.search(q, fc);
    126
    127        // Retrieve results
    128        List<FacetResult> facetResults = fc.getFacetResults();
    129
    130        indexReader.close();
    131        taxoReader.close();
    132
    133        return facetResults;
    134      }
    135
    136      /** Runs the search example. */
    137      public List<FacetResult> runSearch() throws IOException {
    138        index();
    139        return search();
    140      }
    141
    142      /** Runs the drill-down example. */
    143      public List<FacetResult> runDrillDown() throws IOException {
    144        index();
    145        return drillDown();
    146      }
    147
    148      /** Runs the search and drill-down examples and prints the results. */
    149      public static void main(String[] args) throws Exception {
    150        System.out.println("Facet counting example:");
    151        System.out.println("-----------------------");
    152        List<FacetResult> results = new SimpleFacetsExample().runSearch();
    153        for (FacetResult res : results) {
    154          System.out.println(res);
    155        }
    156
    157        System.out.println("\n");
    158        System.out.println("Facet drill-down example (Publish Date/2010):");
    159        System.out.println("---------------------------------------------");
    160        results = new SimpleFacetsExample().runDrillDown();
    161        for (FacetResult res : results) {
    162          System.out.println(res);
    163        }
    164      }
    165
    166    }