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,68 @@ +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 CountFacetRequest(new CategoryPath("field"), 1)); + + DynamicNumericRangeAccumulator a = new DynamicNumericRangeAccumulator(fsp, r); + a.addLongRange("less than 10", 0, true, 10, false); + a.addLongRange("over 90", 90, false, 100, false); + + 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", 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/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,146 @@ +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; + +/** 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 String field; + final List ranges = new ArrayList(); + + static class Range { + public final String label; + public final long startIncl; + public final long endIncl; + public int count; + + public Range(String label, long startIncl, long endIncl) { + this.label = label; + this.startIncl = startIncl; + this.endIncl = endIncl; + } + } + + public DynamicNumericRangeAccumulator(FacetSearchParams fsp, IndexReader reader) { + // nocommit messy to pass fake FacetArrays: + super(fsp, reader, null, new FacetArrays(0)); + + if (fsp.facetRequests.size() != 1) { + throw new IllegalArgumentException("only single facet request allowed (got " + fsp.facetRequests.size() + ")"); + } + + if (fsp.facetRequests.get(0).categoryPath.length != 1) { + throw new IllegalArgumentException("only flat dimensions are supported; got categoryPath=" + fsp.facetRequests.get(0).categoryPath); + } + + field = fsp.facetRequests.get(0).categoryPath.components[0]; + } + + @Override + public FacetsAggregator getAggregator() { + // nocommit awkward ... + return new FacetsAggregator() { + + @Override + public void aggregate(MatchingDocs matchingDocs, CategoryListParams clp, FacetArrays facetArrays) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public void rollupValues(FacetRequest fr, int ordinal, int[] children, int[] siblings, FacetArrays facetArrays) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean requiresDocScores() { + return false; + } + }; + } + + // nocommit int/float/double too + + public void addLongRange(String label, long start, boolean startInclusive, long end, boolean endInclusive) { + if (!startInclusive) { + start++; + } + if (!endInclusive) { + end--; + } + ranges.add(new Range(label, start, end)); + } + + @Override + public List accumulate(List matchingDocs) throws IOException { + + Range[] rangesArray = ranges.toArray(new Range[ranges.size()]); + + 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= r.startIncl && v <= r.endIncl) { + r.count++; + } + } + + doc++; + } + } + + List nodes = new ArrayList(); + for(Range r : rangesArray) { + if (r.count > 0) { + FacetResultNode node = new FacetResultNode(-1, r.count); + node.label = new CategoryPath(field, r.label); + nodes.add(node); + } + } + + FacetResultNode rootNode = new FacetResultNode(-1, 0); + rootNode.label = new CategoryPath(field); + rootNode.subResults = nodes; + + return Collections.singletonList(new FacetResult(searchParams.facetRequests.get(0), rootNode, nodes.size())); + } +} Property changes on: lucene/facet/src/java/org/apache/lucene/facet/search/DynamicNumericRangeAccumulator.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property