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