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