You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by sh...@apache.org on 2013/02/10 13:55:40 UTC

svn commit: r1444538 - in /lucene/dev/trunk/lucene/demo/src: java/org/apache/lucene/demo/facet/ java/org/apache/lucene/demo/facet/adaptive/ java/org/apache/lucene/demo/facet/association/ java/org/apache/lucene/demo/facet/multiCL/ java/org/apache/lucene...

Author: shaie
Date: Sun Feb 10 12:55:40 2013
New Revision: 1444538

URL: http://svn.apache.org/r1444538
Log:
LUCENE-4762: improve facet examples

Added:
    lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/AssociationsFacetsExample.java   (with props)
    lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/FacetExamples.java
      - copied, changed from r1444520, lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/ExampleUtils.java
    lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/MultiCategoryListsFacetsExample.java   (with props)
    lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/SimpleFacetsExample.java   (with props)
    lucene/dev/trunk/lucene/demo/src/test/org/apache/lucene/demo/facet/TestAssociationsFacetsExample.java   (with props)
    lucene/dev/trunk/lucene/demo/src/test/org/apache/lucene/demo/facet/TestMultiCategoryListsFacetsExample.java   (with props)
    lucene/dev/trunk/lucene/demo/src/test/org/apache/lucene/demo/facet/TestSimpleFacetsExample.java   (with props)
Removed:
    lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/ExampleResult.java
    lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/ExampleUtils.java
    lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/adaptive/
    lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/association/
    lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/multiCL/
    lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/simple/
    lucene/dev/trunk/lucene/demo/src/test/org/apache/lucene/demo/facet/TestAdaptiveExample.java
    lucene/dev/trunk/lucene/demo/src/test/org/apache/lucene/demo/facet/TestAssociationExample.java
    lucene/dev/trunk/lucene/demo/src/test/org/apache/lucene/demo/facet/TestMultiCLExample.java
    lucene/dev/trunk/lucene/demo/src/test/org/apache/lucene/demo/facet/TestSimpleExample.java

Added: lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/AssociationsFacetsExample.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/AssociationsFacetsExample.java?rev=1444538&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/AssociationsFacetsExample.java (added)
+++ lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/AssociationsFacetsExample.java Sun Feb 10 12:55:40 2013
@@ -0,0 +1,209 @@
+package org.apache.lucene.demo.facet;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.lucene.analysis.core.WhitespaceAnalyzer;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.facet.associations.AssociationFloatSumFacetRequest;
+import org.apache.lucene.facet.associations.AssociationIntSumFacetRequest;
+import org.apache.lucene.facet.associations.AssociationsFacetFields;
+import org.apache.lucene.facet.associations.CategoryAssociation;
+import org.apache.lucene.facet.associations.CategoryAssociationsContainer;
+import org.apache.lucene.facet.associations.CategoryFloatAssociation;
+import org.apache.lucene.facet.associations.CategoryIntAssociation;
+import org.apache.lucene.facet.index.FacetFields;
+import org.apache.lucene.facet.params.FacetSearchParams;
+import org.apache.lucene.facet.search.FacetResult;
+import org.apache.lucene.facet.search.FacetsAccumulator;
+import org.apache.lucene.facet.search.FacetsCollector;
+import org.apache.lucene.facet.search.StandardFacetsAccumulator;
+import org.apache.lucene.facet.taxonomy.CategoryPath;
+import org.apache.lucene.facet.taxonomy.TaxonomyReader;
+import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyReader;
+import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyWriter;
+import org.apache.lucene.index.DirectoryReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.IndexWriterConfig;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.MatchAllDocsQuery;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.RAMDirectory;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** Shows example usage of category associations. */
+public class AssociationsFacetsExample {
+
+  /**
+   * Categories per document, {@link #ASSOCIATIONS} hold the association value
+   * for each category.
+   */
+  public static CategoryPath[][] CATEGORIES = {
+    // Doc #1
+    { new CategoryPath("tags", "lucene") , 
+      new CategoryPath("genre", "computing")
+    },
+        
+    // Doc #2
+    { new CategoryPath("tags", "lucene"),  
+      new CategoryPath("tags", "solr"),
+      new CategoryPath("genre", "computing"),
+      new CategoryPath("genre", "software")
+    }
+  };
+
+  /** Association values for each category. */
+  public static CategoryAssociation[][] ASSOCIATIONS = {
+    // Doc #1 associations
+    {
+      /* 3 occurrences for tag 'lucene' */
+      new CategoryIntAssociation(3), 
+      /* 87% confidence level of genre 'computing' */
+      new CategoryFloatAssociation(0.87f)
+    },
+    
+    // Doc #2 associations
+    {
+      /* 1 occurrence for tag 'lucene' */
+      new CategoryIntAssociation(1),
+      /* 2 occurrences for tag 'solr' */
+      new CategoryIntAssociation(2),
+      /* 75% confidence level of genre 'computing' */
+      new CategoryFloatAssociation(0.75f),
+      /* 34% confidence level of genre 'software' */
+      new CategoryFloatAssociation(0.34f),
+    }
+  };
+
+  private final Directory indexDir = new RAMDirectory();
+  private final Directory taxoDir = new RAMDirectory();
+
+  /** Empty constructor */
+  public AssociationsFacetsExample() {}
+  
+  /** Build the example index. */
+  private void index() throws IOException {
+    IndexWriter indexWriter = new IndexWriter(indexDir, new IndexWriterConfig(FacetExamples.EXAMPLES_VER, 
+        new WhitespaceAnalyzer(FacetExamples.EXAMPLES_VER)));
+
+    // Writes facet ords to a separate directory from the main index
+    DirectoryTaxonomyWriter taxoWriter = new DirectoryTaxonomyWriter(taxoDir, IndexWriterConfig.OpenMode.CREATE);
+
+    // Reused across documents, to add the necessary facet fields
+    FacetFields facetFields = new AssociationsFacetFields(taxoWriter);
+    
+    for (int i = 0; i < CATEGORIES.length; i++) {
+      Document doc = new Document();
+      CategoryAssociationsContainer associations = new CategoryAssociationsContainer();
+      for (int j = 0; j < CATEGORIES[i].length; j++) {
+        associations.setAssociation(CATEGORIES[i][j], ASSOCIATIONS[i][j]);
+      }
+      facetFields.addFields(doc, associations);
+      indexWriter.addDocument(doc);
+    }
+    
+    indexWriter.close();
+    taxoWriter.close();
+  }
+
+  /** User runs a query and aggregates facets by summing their int associations. */
+  private List<FacetResult> sumIntAssociations() throws IOException {
+    DirectoryReader indexReader = DirectoryReader.open(indexDir);
+    IndexSearcher searcher = new IndexSearcher(indexReader);
+    TaxonomyReader taxoReader = new DirectoryTaxonomyReader(taxoDir);
+
+    // sum the 'tags' dimension
+    FacetSearchParams fsp = new FacetSearchParams(new AssociationIntSumFacetRequest(new CategoryPath("tags"), 10));
+
+    FacetsAccumulator fa = new StandardFacetsAccumulator(fsp, indexReader, taxoReader);
+    FacetsCollector fc = FacetsCollector.create(fa);
+
+    // MatchAllDocsQuery is for "browsing" (counts facets
+    // for all non-deleted docs in the index); normally
+    // you'd use a "normal" query, and use MultiCollector to
+    // wrap collecting the "normal" hits and also facets:
+    searcher.search(new MatchAllDocsQuery(), fc);
+
+    // Retrieve results
+    List<FacetResult> facetResults = fc.getFacetResults();
+    
+    indexReader.close();
+    taxoReader.close();
+    
+    return facetResults;
+  }
+  
+  /** User runs a query and aggregates facets by summing their float associations. */
+  private List<FacetResult> sumFloatAssociations() throws IOException {
+    DirectoryReader indexReader = DirectoryReader.open(indexDir);
+    IndexSearcher searcher = new IndexSearcher(indexReader);
+    TaxonomyReader taxoReader = new DirectoryTaxonomyReader(taxoDir);
+    
+    // sum the 'tags' dimension
+    FacetSearchParams fsp = new FacetSearchParams(new AssociationFloatSumFacetRequest(new CategoryPath("genre"), 10));
+    
+    FacetsAccumulator fa = new StandardFacetsAccumulator(fsp, indexReader, taxoReader);
+    FacetsCollector fc = FacetsCollector.create(fa);
+    
+    // MatchAllDocsQuery is for "browsing" (counts facets
+    // for all non-deleted docs in the index); normally
+    // you'd use a "normal" query, and use MultiCollector to
+    // wrap collecting the "normal" hits and also facets:
+    searcher.search(new MatchAllDocsQuery(), fc);
+    
+    // Retrieve results
+    List<FacetResult> facetResults = fc.getFacetResults();
+    
+    indexReader.close();
+    taxoReader.close();
+    
+    return facetResults;
+  }
+  
+  /** Runs summing int association example. */
+  public List<FacetResult> runSumIntAssociations() throws IOException {
+    index();
+    return sumIntAssociations();
+  }
+  
+  /** Runs summing float association example. */
+  public List<FacetResult> runSumFloatAssociations() throws IOException {
+    index();
+    return sumFloatAssociations();
+  }
+
+  /** Runs the sum int/float associations examples and prints the results. */
+  public static void main(String[] args) throws Exception {
+    System.out.println("Sum int-associations example:");
+    System.out.println("-----------------------------");
+    List<FacetResult> results = new AssociationsFacetsExample().runSumIntAssociations();
+    for (FacetResult res : results) {
+      System.out.println(res);
+    }
+
+    System.out.println("\n");
+    System.out.println("Sum float-associations example:");
+    System.out.println("-------------------------------");
+    results = new AssociationsFacetsExample().runSumFloatAssociations();
+    for (FacetResult res : results) {
+      System.out.println(res);
+    }
+  }
+  
+}

Copied: lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/FacetExamples.java (from r1444520, lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/ExampleUtils.java)
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/FacetExamples.java?p2=lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/FacetExamples.java&p1=lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/ExampleUtils.java&r1=1444520&r2=1444538&rev=1444538&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/ExampleUtils.java (original)
+++ lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/FacetExamples.java Sun Feb 10 12:55:40 2013
@@ -20,32 +20,13 @@ import org.apache.lucene.util.Version;
  */
 
 /**
- * Simple utility functions for the faceting examples
+ * Hold various constants used by facet examples.
+ * 
  * @lucene.experimental
  */
-public class ExampleUtils {
+public interface FacetExamples {
   
-  /** No instance */
-  private ExampleUtils() {}
-
-  /** 
-   * True if the system property <code>tests.verbose</code> has been set.
-   * If true, it causes {@link #log(Object)} to print messages to the console.
-   */
-  public static final boolean VERBOSE = Boolean.getBoolean("tests.verbose");
-
   /** The Lucene {@link Version} used by the example code. */
-  public static final Version EXAMPLE_VER = Version.LUCENE_40;
-  
-  /**
-   * Logs the String representation of <code>msg</code> to the console,
-   * if {@link #VERBOSE} is true. Otherwise, does nothing.
-   * @see #VERBOSE
-   */
-  public static void log(Object msg) {
-    if (VERBOSE) {
-      System.out.println(msg.toString());
-    }
-  }
+  public static final Version EXAMPLES_VER = Version.LUCENE_50;
 
 }

Added: lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/MultiCategoryListsFacetsExample.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/MultiCategoryListsFacetsExample.java?rev=1444538&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/MultiCategoryListsFacetsExample.java (added)
+++ lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/MultiCategoryListsFacetsExample.java Sun Feb 10 12:55:40 2013
@@ -0,0 +1,141 @@
+package org.apache.lucene.demo.facet;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.lucene.analysis.core.WhitespaceAnalyzer;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.facet.index.FacetFields;
+import org.apache.lucene.facet.params.CategoryListParams;
+import org.apache.lucene.facet.params.FacetIndexingParams;
+import org.apache.lucene.facet.params.FacetSearchParams;
+import org.apache.lucene.facet.params.PerDimensionIndexingParams;
+import org.apache.lucene.facet.search.CountFacetRequest;
+import org.apache.lucene.facet.search.FacetResult;
+import org.apache.lucene.facet.search.FacetsCollector;
+import org.apache.lucene.facet.taxonomy.CategoryPath;
+import org.apache.lucene.facet.taxonomy.TaxonomyReader;
+import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyReader;
+import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyWriter;
+import org.apache.lucene.index.DirectoryReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.IndexWriterConfig;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.MatchAllDocsQuery;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.RAMDirectory;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** Demonstrates indexing categories into different category lists. */
+public class MultiCategoryListsFacetsExample {
+
+  private final FacetIndexingParams indexingParams;
+  private final Directory indexDir = new RAMDirectory();
+  private final Directory taxoDir = new RAMDirectory();
+
+  /** Creates a new instance and populates the catetory list params mapping. */
+  public MultiCategoryListsFacetsExample() {
+    // index all Author facets in one category list and all Publish Date in another.
+    Map<CategoryPath,CategoryListParams> categoryListParams = new HashMap<CategoryPath,CategoryListParams>();
+    categoryListParams.put(new CategoryPath("Author"), new CategoryListParams("author"));
+    categoryListParams.put(new CategoryPath("Publish Date"), new CategoryListParams("pubdate"));
+    indexingParams = new PerDimensionIndexingParams(categoryListParams);
+  }
+  
+  private void add(IndexWriter indexWriter, FacetFields facetFields, String ... categoryPaths) throws IOException {
+    Document doc = new Document();
+    
+    List<CategoryPath> paths = new ArrayList<CategoryPath>();
+    for (String categoryPath : categoryPaths) {
+      paths.add(new CategoryPath(categoryPath, '/'));
+    }
+    facetFields.addFields(doc, paths);
+    indexWriter.addDocument(doc);
+  }
+
+  /** Build the example index. */
+  private void index() throws IOException {
+    IndexWriter indexWriter = new IndexWriter(indexDir, new IndexWriterConfig(FacetExamples.EXAMPLES_VER, 
+        new WhitespaceAnalyzer(FacetExamples.EXAMPLES_VER)));
+
+    // Writes facet ords to a separate directory from the main index
+    DirectoryTaxonomyWriter taxoWriter = new DirectoryTaxonomyWriter(taxoDir, IndexWriterConfig.OpenMode.CREATE);
+
+    // Reused across documents, to add the necessary facet fields
+    FacetFields facetFields = new FacetFields(taxoWriter, indexingParams);
+
+    add(indexWriter, facetFields, "Author/Bob", "Publish Date/2010/10/15");
+    add(indexWriter, facetFields, "Author/Lisa", "Publish Date/2010/10/20");
+    add(indexWriter, facetFields, "Author/Lisa", "Publish Date/2012/1/1");
+    add(indexWriter, facetFields, "Author/Susan", "Publish Date/2012/1/7");
+    add(indexWriter, facetFields, "Author/Frank", "Publish Date/1999/5/5");
+    
+    indexWriter.close();
+    taxoWriter.close();
+  }
+
+  /** User runs a query and counts facets. */
+  private List<FacetResult> search() throws IOException {
+    DirectoryReader indexReader = DirectoryReader.open(indexDir);
+    IndexSearcher searcher = new IndexSearcher(indexReader);
+    TaxonomyReader taxoReader = new DirectoryTaxonomyReader(taxoDir);
+
+    // Count both "Publish Date" and "Author" dimensions
+    FacetSearchParams fsp = new FacetSearchParams(indexingParams,
+        new CountFacetRequest(new CategoryPath("Publish Date"), 10), 
+        new CountFacetRequest(new CategoryPath("Author"), 10));
+
+    // Aggregatses the facet counts
+    FacetsCollector fc = FacetsCollector.create(fsp, searcher.getIndexReader(), taxoReader);
+
+    // MatchAllDocsQuery is for "browsing" (counts facets
+    // for all non-deleted docs in the index); normally
+    // you'd use a "normal" query, and use MultiCollector to
+    // wrap collecting the "normal" hits and also facets:
+    searcher.search(new MatchAllDocsQuery(), fc);
+
+    // Retrieve results
+    List<FacetResult> facetResults = fc.getFacetResults();
+    
+    indexReader.close();
+    taxoReader.close();
+    
+    return facetResults;
+  }
+
+  /** Runs the search example. */
+  public List<FacetResult> runSearch() throws IOException {
+    index();
+    return search();
+  }
+  
+  /** Runs the search example and prints the results. */
+  public static void main(String[] args) throws Exception {
+    System.out.println("Facet counting over multiple category lists example:");
+    System.out.println("-----------------------");
+    List<FacetResult> results = new MultiCategoryListsFacetsExample().runSearch();
+    for (FacetResult res : results) {
+      System.out.println(res);
+    }
+  }
+  
+}

Added: lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/SimpleFacetsExample.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/SimpleFacetsExample.java?rev=1444538&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/SimpleFacetsExample.java (added)
+++ lucene/dev/trunk/lucene/demo/src/java/org/apache/lucene/demo/facet/SimpleFacetsExample.java Sun Feb 10 12:55:40 2013
@@ -0,0 +1,166 @@
+package org.apache.lucene.demo.facet;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.lucene.analysis.core.WhitespaceAnalyzer;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.facet.index.FacetFields;
+import org.apache.lucene.facet.params.FacetSearchParams;
+import org.apache.lucene.facet.search.CountFacetRequest;
+import org.apache.lucene.facet.search.DrillDownQuery;
+import org.apache.lucene.facet.search.FacetResult;
+import org.apache.lucene.facet.search.FacetsCollector;
+import org.apache.lucene.facet.taxonomy.CategoryPath;
+import org.apache.lucene.facet.taxonomy.TaxonomyReader;
+import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyReader;
+import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyWriter;
+import org.apache.lucene.index.DirectoryReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.IndexWriterConfig;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.MatchAllDocsQuery;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.RAMDirectory;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** Shows simple usage of faceted indexing and search. */
+public class SimpleFacetsExample {
+
+  private final Directory indexDir = new RAMDirectory();
+  private final Directory taxoDir = new RAMDirectory();
+
+  /** Empty constructor */
+  public SimpleFacetsExample() {}
+  
+  private void add(IndexWriter indexWriter, FacetFields facetFields, String ... categoryPaths) throws IOException {
+    Document doc = new Document();
+    
+    List<CategoryPath> paths = new ArrayList<CategoryPath>();
+    for (String categoryPath : categoryPaths) {
+      paths.add(new CategoryPath(categoryPath, '/'));
+    }
+    facetFields.addFields(doc, paths);
+    indexWriter.addDocument(doc);
+  }
+
+  /** Build the example index. */
+  private void index() throws IOException {
+    IndexWriter indexWriter = new IndexWriter(indexDir, new IndexWriterConfig(FacetExamples.EXAMPLES_VER, 
+        new WhitespaceAnalyzer(FacetExamples.EXAMPLES_VER)));
+
+    // Writes facet ords to a separate directory from the main index
+    DirectoryTaxonomyWriter taxoWriter = new DirectoryTaxonomyWriter(taxoDir, IndexWriterConfig.OpenMode.CREATE);
+
+    // Reused across documents, to add the necessary facet fields
+    FacetFields facetFields = new FacetFields(taxoWriter);
+
+    add(indexWriter, facetFields, "Author/Bob", "Publish Date/2010/10/15");
+    add(indexWriter, facetFields, "Author/Lisa", "Publish Date/2010/10/20");
+    add(indexWriter, facetFields, "Author/Lisa", "Publish Date/2012/1/1");
+    add(indexWriter, facetFields, "Author/Susan", "Publish Date/2012/1/7");
+    add(indexWriter, facetFields, "Author/Frank", "Publish Date/1999/5/5");
+    
+    indexWriter.close();
+    taxoWriter.close();
+  }
+
+  /** User runs a query and counts facets. */
+  private List<FacetResult> search() throws IOException {
+    DirectoryReader indexReader = DirectoryReader.open(indexDir);
+    IndexSearcher searcher = new IndexSearcher(indexReader);
+    TaxonomyReader taxoReader = new DirectoryTaxonomyReader(taxoDir);
+
+    // Count both "Publish Date" and "Author" dimensions
+    FacetSearchParams fsp = new FacetSearchParams(
+        new CountFacetRequest(new CategoryPath("Publish Date"), 10), 
+        new CountFacetRequest(new CategoryPath("Author"), 10));
+
+    // Aggregatses the facet counts
+    FacetsCollector fc = FacetsCollector.create(fsp, searcher.getIndexReader(), taxoReader);
+
+    // MatchAllDocsQuery is for "browsing" (counts facets
+    // for all non-deleted docs in the index); normally
+    // you'd use a "normal" query, and use MultiCollector to
+    // wrap collecting the "normal" hits and also facets:
+    searcher.search(new MatchAllDocsQuery(), fc);
+
+    // Retrieve results
+    List<FacetResult> facetResults = fc.getFacetResults();
+    
+    indexReader.close();
+    taxoReader.close();
+    
+    return facetResults;
+  }
+  
+  /** User drills down on 'Publish date/2010'. */
+  private List<FacetResult> drillDown() throws IOException {
+    DirectoryReader indexReader = DirectoryReader.open(indexDir);
+    IndexSearcher searcher = new IndexSearcher(indexReader);
+    TaxonomyReader taxoReader = new DirectoryTaxonomyReader(taxoDir);
+
+    // Now user drills down on Publish Date/2010:
+    FacetSearchParams fsp = new FacetSearchParams(new CountFacetRequest(new CategoryPath("Author"), 10));
+    DrillDownQuery q = new DrillDownQuery(fsp.indexingParams, new MatchAllDocsQuery());
+    q.add(new CategoryPath("Publish Date/2010", '/'));
+    FacetsCollector fc = FacetsCollector.create(fsp, searcher.getIndexReader(), taxoReader);
+    searcher.search(q, fc);
+
+    // Retrieve results
+    List<FacetResult> facetResults = fc.getFacetResults();
+    
+    indexReader.close();
+    taxoReader.close();
+    
+    return facetResults;
+  }
+
+  /** Runs the search example. */
+  public List<FacetResult> runSearch() throws IOException {
+    index();
+    return search();
+  }
+  
+  /** Runs the drill-down example. */
+  public List<FacetResult> runDrillDown() throws IOException {
+    index();
+    return drillDown();
+  }
+
+  /** Runs the search and drill-down examples and prints the results. */
+  public static void main(String[] args) throws Exception {
+    System.out.println("Facet counting example:");
+    System.out.println("-----------------------");
+    List<FacetResult> results = new SimpleFacetsExample().runSearch();
+    for (FacetResult res : results) {
+      System.out.println(res);
+    }
+
+    System.out.println("\n");
+    System.out.println("Facet drill-down example (Publish Date/2010):");
+    System.out.println("---------------------------------------------");
+    results = new SimpleFacetsExample().runDrillDown();
+    for (FacetResult res : results) {
+      System.out.println(res);
+    }
+  }
+  
+}

Added: lucene/dev/trunk/lucene/demo/src/test/org/apache/lucene/demo/facet/TestAssociationsFacetsExample.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/demo/src/test/org/apache/lucene/demo/facet/TestAssociationsFacetsExample.java?rev=1444538&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/demo/src/test/org/apache/lucene/demo/facet/TestAssociationsFacetsExample.java (added)
+++ lucene/dev/trunk/lucene/demo/src/test/org/apache/lucene/demo/facet/TestAssociationsFacetsExample.java Sun Feb 10 12:55:40 2013
@@ -0,0 +1,50 @@
+package org.apache.lucene.demo.facet;
+
+import java.util.List;
+
+import org.apache.lucene.facet.search.FacetResult;
+import org.apache.lucene.facet.search.FacetResultNode;
+import org.apache.lucene.util.LuceneTestCase;
+import org.junit.Test;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class TestAssociationsFacetsExample extends LuceneTestCase {
+  
+  private static final double[] EXPECTED_INT_SUM_RESULTS = { 4, 2};
+  private static final double[] EXPECTED_FLOAT_SUM_RESULTS = { 1.62, 0.34};
+
+  @Test
+  public void testExamples() throws Exception {
+    assertExampleResult(new AssociationsFacetsExample().runSumIntAssociations(), EXPECTED_INT_SUM_RESULTS);
+    assertExampleResult(new AssociationsFacetsExample().runSumFloatAssociations(), EXPECTED_FLOAT_SUM_RESULTS);
+  }
+
+  private void assertExampleResult(List<FacetResult> res, double[] expectedResults) {
+    assertNotNull("Null result!", res);
+    assertEquals("Wrong number of results!", 1, res.size());
+    assertEquals("Wrong number of facets!", 2, res.get(0).getNumValidDescendants());
+    
+    Iterable<? extends FacetResultNode> it = res.get(0).getFacetResultNode().subResults;
+    int i = 0;
+    for (FacetResultNode fResNode : it) {
+      assertEquals("Wrong result for facet "+fResNode.label, expectedResults[i++], fResNode.value, 1E-5);
+    }
+  }
+  
+}

Added: lucene/dev/trunk/lucene/demo/src/test/org/apache/lucene/demo/facet/TestMultiCategoryListsFacetsExample.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/demo/src/test/org/apache/lucene/demo/facet/TestMultiCategoryListsFacetsExample.java?rev=1444538&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/demo/src/test/org/apache/lucene/demo/facet/TestMultiCategoryListsFacetsExample.java (added)
+++ lucene/dev/trunk/lucene/demo/src/test/org/apache/lucene/demo/facet/TestMultiCategoryListsFacetsExample.java Sun Feb 10 12:55:40 2013
@@ -0,0 +1,58 @@
+package org.apache.lucene.demo.facet;
+
+import java.util.List;
+
+import org.apache.lucene.facet.collections.ObjectToIntMap;
+import org.apache.lucene.facet.search.FacetResult;
+import org.apache.lucene.facet.search.FacetResultNode;
+import org.apache.lucene.facet.taxonomy.CategoryPath;
+import org.apache.lucene.util.LuceneTestCase;
+import org.junit.Test;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class TestMultiCategoryListsFacetsExample extends LuceneTestCase {
+
+  private static final ObjectToIntMap<CategoryPath> expectedCounts = new ObjectToIntMap<CategoryPath>();
+  static {
+    expectedCounts.put(new CategoryPath("Publish Date", "2012"), 2);
+    expectedCounts.put(new CategoryPath("Publish Date", "2010"), 2);
+    expectedCounts.put(new CategoryPath("Publish Date", "1999"), 1);
+    expectedCounts.put(new CategoryPath("Author", "Lisa"), 2);
+    expectedCounts.put(new CategoryPath("Author", "Frank"), 1);
+    expectedCounts.put(new CategoryPath("Author", "Susan"), 1);
+    expectedCounts.put(new CategoryPath("Author", "Bob"), 1);
+  }
+  
+  private void assertExpectedCounts(List<FacetResult> facetResults, ObjectToIntMap<CategoryPath> expCounts) {
+    for (FacetResult res : facetResults) {
+      FacetResultNode root = res.getFacetResultNode();
+      for (FacetResultNode node : root.subResults) {
+        assertEquals("incorrect count for " + node.label, expCounts.get(node.label), (int) node.value);
+      }
+    }
+  }
+
+  @Test
+  public void testExample() throws Exception {
+    List<FacetResult> facetResults = new MultiCategoryListsFacetsExample().runSearch();
+    assertEquals(2, facetResults.size());
+    assertExpectedCounts(facetResults, expectedCounts);
+  }
+  
+}

Added: lucene/dev/trunk/lucene/demo/src/test/org/apache/lucene/demo/facet/TestSimpleFacetsExample.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/demo/src/test/org/apache/lucene/demo/facet/TestSimpleFacetsExample.java?rev=1444538&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/demo/src/test/org/apache/lucene/demo/facet/TestSimpleFacetsExample.java (added)
+++ lucene/dev/trunk/lucene/demo/src/test/org/apache/lucene/demo/facet/TestSimpleFacetsExample.java Sun Feb 10 12:55:40 2013
@@ -0,0 +1,71 @@
+package org.apache.lucene.demo.facet;
+
+import java.util.List;
+
+import org.apache.lucene.facet.collections.ObjectToIntMap;
+import org.apache.lucene.facet.search.FacetResult;
+import org.apache.lucene.facet.search.FacetResultNode;
+import org.apache.lucene.facet.taxonomy.CategoryPath;
+import org.apache.lucene.util.LuceneTestCase;
+import org.junit.Test;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class TestSimpleFacetsExample extends LuceneTestCase {
+
+  private static final ObjectToIntMap<CategoryPath> expectedCounts = new ObjectToIntMap<CategoryPath>();
+  static {
+    expectedCounts.put(new CategoryPath("Publish Date", "2012"), 2);
+    expectedCounts.put(new CategoryPath("Publish Date", "2010"), 2);
+    expectedCounts.put(new CategoryPath("Publish Date", "1999"), 1);
+    expectedCounts.put(new CategoryPath("Author", "Lisa"), 2);
+    expectedCounts.put(new CategoryPath("Author", "Frank"), 1);
+    expectedCounts.put(new CategoryPath("Author", "Susan"), 1);
+    expectedCounts.put(new CategoryPath("Author", "Bob"), 1);
+  }
+  
+  private static final ObjectToIntMap<CategoryPath> expectedCountsDrillDown = new ObjectToIntMap<CategoryPath>();
+  static {
+    expectedCountsDrillDown.put(new CategoryPath("Author", "Lisa"), 1);
+    expectedCountsDrillDown.put(new CategoryPath("Author", "Bob"), 1);
+  }
+  
+  private void assertExpectedCounts(List<FacetResult> facetResults, ObjectToIntMap<CategoryPath> expCounts) {
+    for (FacetResult res : facetResults) {
+      FacetResultNode root = res.getFacetResultNode();
+      for (FacetResultNode node : root.subResults) {
+        assertEquals("incorrect count for " + node.label, expCounts.get(node.label), (int) node.value);
+      }
+    }
+  }
+  
+  @Test
+  public void testSimple() throws Exception {
+    List<FacetResult> facetResults = new SimpleFacetsExample().runSearch();
+    assertEquals(2, facetResults.size());
+    assertExpectedCounts(facetResults, expectedCounts);
+  }
+
+  @Test
+  public void testDrillDown() throws Exception {
+    List<FacetResult> facetResults = new SimpleFacetsExample().runDrillDown();
+    assertEquals(1, facetResults.size());
+    assertExpectedCounts(facetResults, expectedCountsDrillDown);
+  }
+  
+}