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.Closeable;
021    import java.io.IOException;
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.document.Field;
027    import org.apache.lucene.document.LongField;
028    import org.apache.lucene.document.NumericDocValuesField;
029    import org.apache.lucene.facet.params.FacetIndexingParams;
030    import org.apache.lucene.facet.params.FacetSearchParams;
031    import org.apache.lucene.facet.range.LongRange;
032    import org.apache.lucene.facet.range.RangeAccumulator;
033    import org.apache.lucene.facet.range.RangeFacetRequest;
034    import org.apache.lucene.facet.search.DrillDownQuery;
035    import org.apache.lucene.facet.search.FacetResult;
036    import org.apache.lucene.facet.search.FacetsCollector;
037    import org.apache.lucene.index.DirectoryReader;
038    import org.apache.lucene.index.IndexWriter;
039    import org.apache.lucene.index.IndexWriterConfig;
040    import org.apache.lucene.search.IndexSearcher;
041    import org.apache.lucene.search.MatchAllDocsQuery;
042    import org.apache.lucene.search.NumericRangeQuery;
043    import org.apache.lucene.search.TopDocs;
044    import org.apache.lucene.store.Directory;
045    import org.apache.lucene.store.RAMDirectory;
046    
047    
048    /** Shows simple usage of dynamic range faceting. */
049    public class RangeFacetsExample implements Closeable {
050    
051      private final Directory indexDir = new RAMDirectory();
052      private IndexSearcher searcher;
053      private final long nowSec = System.currentTimeMillis();
054    
055      /** Empty constructor */
056      public RangeFacetsExample() {}
057      
058      /** Build the example index. */
059      public void index() throws IOException {
060        IndexWriter indexWriter = new IndexWriter(indexDir, new IndexWriterConfig(FacetExamples.EXAMPLES_VER, 
061            new WhitespaceAnalyzer(FacetExamples.EXAMPLES_VER)));
062    
063        // Add documents with a fake timestamp, 1000 sec before
064        // "now", 2000 sec before "now", ...:
065        for(int i=0;i<100;i++) {
066          Document doc = new Document();
067          long then = nowSec - i * 1000;
068          // Add as doc values field, so we can compute range facets:
069          doc.add(new NumericDocValuesField("timestamp", then));
070          // Add as numeric field so we can drill-down:
071          doc.add(new LongField("timestamp", then, Field.Store.NO));
072          indexWriter.addDocument(doc);
073        }
074    
075        // Open near-real-time searcher
076        searcher = new IndexSearcher(DirectoryReader.open(indexWriter, true));
077        indexWriter.close();
078      }
079    
080      /** User runs a query and counts facets. */
081      public List<FacetResult> search() throws IOException {
082    
083        FacetSearchParams fsp = new FacetSearchParams(
084                                    new RangeFacetRequest<LongRange>("timestamp",
085                                                                     new LongRange("Past hour", nowSec-3600, true, nowSec, true),
086                                                                     new LongRange("Past six hours", nowSec-6*3600, true, nowSec, true),
087                                                                     new LongRange("Past day", nowSec-24*3600, true, nowSec, true)));
088        // Aggregatses the facet counts
089        FacetsCollector fc = FacetsCollector.create(new RangeAccumulator(fsp, searcher.getIndexReader()));
090    
091        // MatchAllDocsQuery is for "browsing" (counts facets
092        // for all non-deleted docs in the index); normally
093        // you'd use a "normal" query, and use MultiCollector to
094        // wrap collecting the "normal" hits and also facets:
095        searcher.search(new MatchAllDocsQuery(), fc);
096    
097        // Retrieve results
098        return fc.getFacetResults();
099      }
100      
101      /** User drills down on the specified range. */
102      public TopDocs drillDown(LongRange range) throws IOException {
103    
104        // Passing no baseQuery means we drill down on all
105        // documents ("browse only"):
106        DrillDownQuery q = new DrillDownQuery(FacetIndexingParams.DEFAULT);
107    
108        // Use FieldCacheRangeFilter; this will use
109        // NumericDocValues:
110        q.add("timestamp", NumericRangeQuery.newLongRange("timestamp", range.min, range.max, range.minInclusive, range.maxInclusive));
111    
112        return searcher.search(q, 10);
113      }
114    
115      public void close() throws IOException {
116        searcher.getIndexReader().close();
117        indexDir.close();
118      }
119    
120      /** Runs the search and drill-down examples and prints the results. */
121      @SuppressWarnings("unchecked")
122      public static void main(String[] args) throws Exception {
123        RangeFacetsExample example = new RangeFacetsExample();
124        example.index();
125    
126        System.out.println("Facet counting example:");
127        System.out.println("-----------------------");
128        List<FacetResult> results = example.search();
129        for (FacetResult res : results) {
130          System.out.println(res);
131        }
132    
133        System.out.println("\n");
134        System.out.println("Facet drill-down example (timestamp/Past six hours):");
135        System.out.println("---------------------------------------------");
136        TopDocs hits = example.drillDown((LongRange) ((RangeFacetRequest<LongRange>) results.get(0).getFacetRequest()).ranges[1]);
137        System.out.println(hits.totalHits + " totalHits");
138    
139        example.close();
140      }
141    }