Index: lucene/facet/src/test/org/apache/lucene/facet/search/TestDynamicNumericRangeAccumulator.java =================================================================== --- lucene/facet/src/test/org/apache/lucene/facet/search/TestDynamicNumericRangeAccumulator.java (revision 0) +++ lucene/facet/src/test/org/apache/lucene/facet/search/TestDynamicNumericRangeAccumulator.java (working copy) @@ -0,0 +1,70 @@ +package org.apache.lucene.facet.search; + +/* + * 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. + */ + +import java.util.List; + +import org.apache.lucene.document.Document; +import org.apache.lucene.document.LongDocValuesField; +import org.apache.lucene.facet.FacetTestCase; +import org.apache.lucene.facet.FacetTestUtils; +import org.apache.lucene.facet.params.FacetSearchParams; +import org.apache.lucene.facet.taxonomy.CategoryPath; +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.RandomIndexWriter; +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.MatchAllDocsQuery; +import org.apache.lucene.store.Directory; + +public class TestDynamicNumericRangeAccumulator extends FacetTestCase { + + public void testBasic() throws Exception { + Directory d = newDirectory(); + RandomIndexWriter w = new RandomIndexWriter(random(), d); + Document doc = new Document(); + LongDocValuesField field = new LongDocValuesField("field", 0L); + doc.add(field); + for(long l=0;l<100;l++) { + field.setLongValue(l); + w.addDocument(doc); + } + + IndexReader r = w.getReader(); + w.close(); + + FacetSearchParams fsp = new FacetSearchParams( + new DynamicRangeFacetRequest("field", + DynamicRange.newLongRange("less than 10", 0L, true, 10L, false), + DynamicRange.newLongRange("over 90", 90L, false, 100L, false), + DynamicRange.newLongRange("over 1000", 1000L, false, null, false))); + + DynamicNumericRangeAccumulator a = new DynamicNumericRangeAccumulator(fsp, r); + + FacetsCollector fc = FacetsCollector.create(a); + + IndexSearcher s = newSearcher(r); + s.search(new MatchAllDocsQuery(), fc); + List result = a.accumulate(fc.getMatchingDocs()); + assertEquals(1, result.size()); + assertEquals("field (0)\n less than 10 (10)\n over 90 (9)\n over 1000 (0)\n", FacetTestUtils.toSimpleString(result.get(0))); + + r.close(); + d.close(); + } +} + Property changes on: lucene/facet/src/test/org/apache/lucene/facet/search/TestDynamicNumericRangeAccumulator.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: lucene/facet/src/java/org/apache/lucene/facet/search/FacetsCollector.java =================================================================== --- lucene/facet/src/java/org/apache/lucene/facet/search/FacetsCollector.java (revision 1476634) +++ lucene/facet/src/java/org/apache/lucene/facet/search/FacetsCollector.java (working copy) @@ -175,7 +175,7 @@ * given {@link FacetsAccumulator}. */ public static FacetsCollector create(FacetsAccumulator accumulator) { - if (accumulator.getAggregator().requiresDocScores()) { + if (accumulator.requiresDocScores()) { return new DocsAndScoresCollector(accumulator); } else { return new DocsOnlyCollector(accumulator); Index: lucene/facet/src/java/org/apache/lucene/facet/search/DynamicRangeFacetRequest.java =================================================================== --- lucene/facet/src/java/org/apache/lucene/facet/search/DynamicRangeFacetRequest.java (revision 0) +++ lucene/facet/src/java/org/apache/lucene/facet/search/DynamicRangeFacetRequest.java (working copy) @@ -0,0 +1,57 @@ +package org.apache.lucene.facet.search; + +/* + * 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. + */ + +import org.apache.lucene.facet.complements.ComplementCountingAggregator; +import org.apache.lucene.facet.taxonomy.CategoryPath; +import org.apache.lucene.facet.taxonomy.TaxonomyReader; + +// nocommit rename to NDV? + +/** + * Facet request for dynamic ranges based on a + * NumericDocValues field. This does not use the taxonomy + * index nor any indexed facet values. + * + * @lucene.experimental + */ +public class DynamicRangeFacetRequest extends FacetRequest { + + public final DynamicRange[] ranges; + + public DynamicRangeFacetRequest(String field, DynamicRange...ranges) { + super(new CategoryPath(field), 1); + this.ranges = ranges; + } + + @Override + public Aggregator createAggregator(boolean useComplements, FacetArrays arrays, TaxonomyReader taxonomy) { + throw new UnsupportedOperationException(); + } + + @Override + public double getValueOf(FacetArrays arrays, int ordinal) { + throw new UnsupportedOperationException(); + } + + @Override + public FacetArraysSource getFacetArraysSource() { + throw new UnsupportedOperationException(); + } + +} Property changes on: lucene/facet/src/java/org/apache/lucene/facet/search/DynamicRangeFacetRequest.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: lucene/facet/src/java/org/apache/lucene/facet/search/DynamicNumericRangeAccumulator.java =================================================================== --- lucene/facet/src/java/org/apache/lucene/facet/search/DynamicNumericRangeAccumulator.java (revision 0) +++ lucene/facet/src/java/org/apache/lucene/facet/search/DynamicNumericRangeAccumulator.java (working copy) @@ -0,0 +1,114 @@ +package org.apache.lucene.facet.search; + +/* + * 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. + */ + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.apache.lucene.facet.params.CategoryListParams; +import org.apache.lucene.facet.params.FacetSearchParams; +import org.apache.lucene.facet.search.FacetsCollector.MatchingDocs; +import org.apache.lucene.facet.taxonomy.CategoryPath; +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.NumericDocValues; + +// nocommit add DynamicRangeFacetRequest + +/** Uses a {@link NumericDocValues} and accumulates + * counts for provided ranges. This is dynamic (does not + * use the taxonomy index or anything from the index + * except the NumericDocValuesField). */ + +public class DynamicNumericRangeAccumulator extends FacetsAccumulator { + final DynamicRange[] ranges; + final String field; + + // nocommit sugar to take DynamicRange... directly? + + public DynamicNumericRangeAccumulator(FacetSearchParams fsp, IndexReader reader) { + super(fsp, reader, null, null); + + // ncoommit allow more than one request? against more + // than one field? + if (fsp.facetRequests.size() != 1) { + throw new IllegalArgumentException("only single facet request allowed (got " + fsp.facetRequests.size() + ")"); + } + + if (!(fsp.facetRequests.get(0) instanceof DynamicRangeFacetRequest)) { + throw new IllegalArgumentException("only DynamicRangeFacetRequest is supported; got " + fsp.facetRequests.get(0).getClass()); + } + + DynamicRangeFacetRequest fr = (DynamicRangeFacetRequest) fsp.facetRequests.get(0); + + this.field = fr.categoryPath.components[0]; + + ranges = fr.ranges; + } + + // nocommit ok to leave default getAggregator? it won't + // be called? + + @Override + public List accumulate(List matchingDocs) throws IOException { + + int[] counts = new int[ranges.length]; + + for(MatchingDocs hits : matchingDocs) { + NumericDocValues ndv = hits.context.reader().getNumericDocValues(field); + if (ndv == null) { + continue; + } + + final int length = hits.bits.length(); + int doc = 0; + while (doc < length && (doc = hits.bits.nextSetBit(doc)) != -1) { + long v = ndv.get(doc); + + // nocommit use interval tree: + for(int i=0;i nodes = new ArrayList(); + for(int i=0;i= minIncl && value <= maxIncl; + } + + // nocommit .newIntRange/etc. + + public static DynamicRange newLongRange(String label, Long min, boolean minInclusive, Long max, boolean maxInclusive) { + long minLong; + if (min == null) { + minLong = Long.MIN_VALUE; + } else { + minLong = min.longValue(); + if (!minInclusive) { + minLong++; + } + } + + long maxLong; + if (max == null) { + maxLong = Long.MAX_VALUE; + } else { + maxLong = max.longValue(); + if (!maxInclusive) { + maxLong--; + } + } + + return new DynamicRange(label, minLong, maxLong); + } +} Property changes on: lucene/facet/src/java/org/apache/lucene/facet/search/DynamicRange.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: lucene/facet/src/java/org/apache/lucene/facet/search/FacetsAccumulator.java =================================================================== --- lucene/facet/src/java/org/apache/lucene/facet/search/FacetsAccumulator.java (revision 1476634) +++ lucene/facet/src/java/org/apache/lucene/facet/search/FacetsAccumulator.java (working copy) @@ -58,7 +58,7 @@ * constructor. */ public FacetsAccumulator(FacetSearchParams searchParams, IndexReader indexReader, TaxonomyReader taxonomyReader) { - this(searchParams, indexReader, taxonomyReader, null); + this(searchParams, indexReader, taxonomyReader, new FacetArrays(taxonomyReader.getSize())); } /** @@ -97,9 +97,6 @@ */ public FacetsAccumulator(FacetSearchParams searchParams, IndexReader indexReader, TaxonomyReader taxonomyReader, FacetArrays facetArrays) { - if (facetArrays == null) { - facetArrays = new FacetArrays(taxonomyReader.getSize()); - } this.facetArrays = facetArrays; this.indexReader = indexReader; this.taxonomyReader = taxonomyReader; @@ -199,4 +196,7 @@ return res; } + protected boolean requiresDocScores() { + return getAggregator().requiresDocScores(); + } }