    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *     http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017package org.apache.lucene.demo.facet;
    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));
    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}