    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    }