Index: lucene/facet/src/java/org/apache/lucene/facet/search/AllFacetsAccumulator.java =================================================================== --- lucene/facet/src/java/org/apache/lucene/facet/search/AllFacetsAccumulator.java (revision 0) +++ lucene/facet/src/java/org/apache/lucene/facet/search/AllFacetsAccumulator.java (working copy) @@ -0,0 +1,109 @@ +package org.apache.lucene.facet.search; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import org.apache.lucene.facet.params.FacetSearchParams; +import org.apache.lucene.facet.search.FacetsCollector.MatchingDocs; +import org.apache.lucene.facet.sortedset.SortedSetDocValuesAccumulator; +import org.apache.lucene.facet.sortedset.SortedSetDocValuesReaderState; +import org.apache.lucene.facet.taxonomy.CategoryPath; +import org.apache.lucene.facet.taxonomy.TaxonomyReader; +import org.apache.lucene.facet.taxonomy.TaxonomyReader.ChildrenIterator; +import org.apache.lucene.index.IndexReader; + +/* + * 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. + */ + +/** + * Accumulates whatever facets match the user's query. That is, it asks to + * aggregate all known dimensions and whatever matches is returned. In that + * sense, {@link #accumulate(List)} returns an unspecified number of + * {@link FacetResult}s. + * + * @lucene.experimental + */ +public class AllFacetsAccumulator extends FacetsAccumulator { + + // TODO we can create a FacetRequestBuilder so the app can pass to create a + // FacetRequest given CP; that way app will be able to use any FR, not just + // CountFR + + private final int numResults; + private final FacetsAccumulator fa; + + public AllFacetsAccumulator(IndexReader indexReader, TaxonomyReader taxoReader, int numResults) throws IOException { + super(null); + this.numResults = numResults; + FacetSearchParams fsp = new FacetSearchParams(createRequests(taxoReader)); + this.fa = new TaxonomyFacetsAccumulator(fsp, indexReader, taxoReader); + } + + public AllFacetsAccumulator(SortedSetDocValuesReaderState state, int numResults) throws IOException { + super(null); + this.numResults = numResults; + this.fa = new SortedSetDocValuesAccumulator(state, new FacetSearchParams(createRequests(state))); + } + + private List createRequests(SortedSetDocValuesReaderState state) { + List requests = new ArrayList(); + for (String dim : state.getDimensions()) { + requests.add(new CountFacetRequest(new CategoryPath(dim), numResults)); + } + return requests; + } + + private List createRequests(TaxonomyReader taxoReader) throws IOException { + ChildrenIterator dims = taxoReader.getChildren(TaxonomyReader.ROOT_ORDINAL); + if (dims == null) { + throw new IllegalArgumentException("taxonomy has no dimensions"); + } + List requests = new ArrayList(); + int ord; + while ((ord = dims.next()) != TaxonomyReader.INVALID_ORDINAL) { + requests.add(new CountFacetRequest(taxoReader.getPath(ord), numResults)); + } + return requests; + } + + @Override + public List accumulate(List matchingDocs) throws IOException { + List results = new ArrayList(); + for (FacetResult res : fa.accumulate(matchingDocs)) { + if (!res.getFacetResultNode().subResults.isEmpty()) { + results.add(res); + } + } + // sort the results by their dimension + Collections.sort(results, new Comparator() { + @Override + public int compare(FacetResult res1, FacetResult res2) { + return res1.getFacetRequest().categoryPath.compareTo(res2.getFacetRequest().categoryPath); + } + }); + return results; + } + + @Override + public boolean requiresDocScores() { + return fa.requiresDocScores(); + } + +} Property changes on: lucene/facet/src/java/org/apache/lucene/facet/search/AllFacetsAccumulator.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: lucene/facet/src/java/org/apache/lucene/facet/sortedset/SortedSetDocValuesReaderState.java =================================================================== --- lucene/facet/src/java/org/apache/lucene/facet/sortedset/SortedSetDocValuesReaderState.java (revision 1540517) +++ lucene/facet/src/java/org/apache/lucene/facet/sortedset/SortedSetDocValuesReaderState.java (working copy) @@ -19,12 +19,12 @@ import java.io.IOException; import java.util.HashMap; import java.util.Map; +import java.util.Set; import java.util.regex.Pattern; import org.apache.lucene.facet.params.CategoryListParams; import org.apache.lucene.facet.params.FacetIndexingParams; import org.apache.lucene.index.AtomicReader; -import org.apache.lucene.index.CompositeReader; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.SlowCompositeReaderWrapper; import org.apache.lucene.index.SortedSetDocValues; @@ -136,7 +136,11 @@ prefixToOrdRange.put(lastDim, new OrdRange(startOrd, valueCount-1)); } } - + + public Set getDimensions() { + return prefixToOrdRange.keySet(); + } + SortedSetDocValues getDocValues() throws IOException { return topReader.getSortedSetDocValues(field); } Index: lucene/facet/src/test/org/apache/lucene/facet/search/TestAllFacetsAccumulator.java =================================================================== --- lucene/facet/src/test/org/apache/lucene/facet/search/TestAllFacetsAccumulator.java (revision 0) +++ lucene/facet/src/test/org/apache/lucene/facet/search/TestAllFacetsAccumulator.java (working copy) @@ -0,0 +1,156 @@ +package org.apache.lucene.facet.search; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.lucene.document.Document; +import org.apache.lucene.facet.FacetTestCase; +import org.apache.lucene.facet.FacetTestUtils; +import org.apache.lucene.facet.index.FacetFields; +import org.apache.lucene.facet.sortedset.SortedSetDocValuesFacetFields; +import org.apache.lucene.facet.sortedset.SortedSetDocValuesReaderState; +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.RandomIndexWriter; +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.MatchAllDocsQuery; +import org.apache.lucene.store.Directory; +import org.apache.lucene.util.IOUtils; +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 TestAllFacetsAccumulator extends FacetTestCase { + + @Test + public void testSortedSet() throws Exception { + assumeTrue("Test requires SortedSetDV support", defaultCodecSupportsSortedSet()); + Directory dir = newDirectory(); + RandomIndexWriter writer = new RandomIndexWriter(random(), dir); + + SortedSetDocValuesFacetFields dvFields = new SortedSetDocValuesFacetFields(); + + Document doc = new Document(); + List paths = new ArrayList(); + paths.add(new CategoryPath("b", "bar1")); + dvFields.addFields(doc, paths); + writer.addDocument(doc); + + if (random().nextBoolean()) { + writer.commit(); + } + + doc = new Document(); + paths = new ArrayList(); + paths.add(new CategoryPath("b", "bar2")); + paths.add(new CategoryPath("a", "foo1")); + dvFields.addFields(doc, paths); + writer.addDocument(doc); + + if (random().nextBoolean()) { + writer.commit(); + } + + doc = new Document(); + paths = new ArrayList(); + paths.add(new CategoryPath("a", "foo2")); + paths.add(new CategoryPath("b", "bar3")); + paths.add(new CategoryPath("c", "baz1")); + dvFields.addFields(doc, paths); + writer.addDocument(doc); + + // NRT open + IndexSearcher searcher = newSearcher(writer.getReader()); + writer.close(); + + // Per-top-reader state: + SortedSetDocValuesReaderState state = new SortedSetDocValuesReaderState(searcher.getIndexReader()); + + // Ask for top 10 labels for all dims that have counts: + FacetsCollector c = FacetsCollector.create(new AllFacetsAccumulator(state, 10)); + searcher.search(new MatchAllDocsQuery(), c); + List results = c.getFacetResults(); + + assertEquals(3, results.size()); + assertEquals("a (0)\n foo1 (1)\n foo2 (1)\n", FacetTestUtils.toSimpleString(results.get(0))); + assertEquals("b (0)\n bar1 (1)\n bar2 (1)\n bar3 (1)\n", FacetTestUtils.toSimpleString(results.get(1))); + assertEquals("c (0)\n baz1 (1)\n", FacetTestUtils.toSimpleString(results.get(2))); + + searcher.getIndexReader().close(); + dir.close(); + } + + @Test + public void testTaxonomyIndex() throws Exception { + Directory indexDir = newDirectory(), taxoDir = newDirectory(); + DirectoryTaxonomyWriter taxoWriter = new DirectoryTaxonomyWriter(taxoDir); + RandomIndexWriter indexWriter = new RandomIndexWriter(random(), indexDir); + + FacetFields facetFields = new FacetFields(taxoWriter); + + Document doc = new Document(); + List paths = new ArrayList(); + paths.add(new CategoryPath("b", "bar1")); + facetFields.addFields(doc, paths); + indexWriter.addDocument(doc); + + if (random().nextBoolean()) { + indexWriter.commit(); + } + + doc = new Document(); + paths = new ArrayList(); + paths.add(new CategoryPath("b", "bar2")); + paths.add(new CategoryPath("a", "foo1")); + facetFields.addFields(doc, paths); + indexWriter.addDocument(doc); + + if (random().nextBoolean()) { + indexWriter.commit(); + } + + doc = new Document(); + paths = new ArrayList(); + paths.add(new CategoryPath("a", "foo2")); + paths.add(new CategoryPath("b", "bar3")); + paths.add(new CategoryPath("c", "baz1")); + facetFields.addFields(doc, paths); + indexWriter.addDocument(doc); + + // NRT open + IndexSearcher searcher = newSearcher(indexWriter.getReader()); + TaxonomyReader taxoReader = new DirectoryTaxonomyReader(taxoWriter); + indexWriter.close(); + taxoWriter.close(); + + // Ask for top 10 labels for all dims that have counts: + FacetsCollector c = FacetsCollector.create(new AllFacetsAccumulator(searcher.getIndexReader(), taxoReader, 10)); + searcher.search(new MatchAllDocsQuery(), c); + List results = c.getFacetResults(); + + assertEquals(3, results.size()); + assertEquals("a (0)\n foo2 (1)\n foo1 (1)\n", FacetTestUtils.toSimpleString(results.get(0))); + assertEquals("b (0)\n bar3 (1)\n bar2 (1)\n bar1 (1)\n", FacetTestUtils.toSimpleString(results.get(1))); + assertEquals("c (0)\n baz1 (1)\n", FacetTestUtils.toSimpleString(results.get(2))); + + IOUtils.close(searcher.getIndexReader(), taxoReader, indexDir, taxoDir); + } + +} Property changes on: lucene/facet/src/test/org/apache/lucene/facet/search/TestAllFacetsAccumulator.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property