mirror of https://github.com/apache/lucene.git
LUCENE-1681: Fix infinite loop caused by a call to DocValues methods getMinValue, getMaxValue, getAverageValue.
git-svn-id: https://svn.apache.org/repos/asf/lucene/java/trunk@785238 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
ea9fcfe3fc
commit
baaa029331
|
@ -266,6 +266,9 @@ Bug fixes
|
|||
on EOF, removed numeric overflow possibilities and added support
|
||||
for a hack to unmap the buffers on closing IndexInput.
|
||||
(Uwe Schindler)
|
||||
|
||||
16. LUCENE-1681: Fix infinite loop caused by a call to DocValues methods
|
||||
getMinValue, getMaxValue, getAverageValue. (Simon Willnauer via Mark Miller)
|
||||
|
||||
New features
|
||||
|
||||
|
|
|
@ -114,17 +114,15 @@ public abstract class DocValues {
|
|||
}
|
||||
|
||||
// --- some simple statistics on values
|
||||
private float minVal;
|
||||
private float maxVal;
|
||||
private float avgVal;
|
||||
private float minVal = Float.NaN;
|
||||
private float maxVal = Float.NaN;
|
||||
private float avgVal = Float.NaN;
|
||||
private boolean computed=false;
|
||||
// compute optional values
|
||||
private void compute () {
|
||||
private void compute() {
|
||||
if (computed) {
|
||||
return;
|
||||
}
|
||||
minVal = Float.MAX_VALUE;
|
||||
maxVal = 0;
|
||||
float sum = 0;
|
||||
int n = 0;
|
||||
while (true) {
|
||||
|
@ -135,34 +133,56 @@ public abstract class DocValues {
|
|||
break;
|
||||
}
|
||||
sum += val;
|
||||
minVal = Math.min(minVal,val);
|
||||
maxVal = Math.max(maxVal,val);
|
||||
minVal = Float.isNaN(minVal) ? val : Math.min(minVal, val);
|
||||
maxVal = Float.isNaN(maxVal) ? val : Math.max(maxVal, val);
|
||||
++n;
|
||||
}
|
||||
avgVal = sum / n;
|
||||
|
||||
avgVal = n == 0 ? Float.NaN : sum / n;
|
||||
computed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional op.
|
||||
* Returns the minimum of all values.
|
||||
* Returns the minimum of all values or <code>Float.NaN</code> if this
|
||||
* DocValues instance does not contain any value.
|
||||
* <p>
|
||||
* This operation is optional
|
||||
* </p>
|
||||
*
|
||||
* @return the minimum of all values or <code>Float.NaN</code> if this
|
||||
* DocValues instance does not contain any value.
|
||||
*/
|
||||
public float getMinValue () {
|
||||
public float getMinValue() {
|
||||
compute();
|
||||
return minVal;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Optional op.
|
||||
* Returns the maximum of all values.
|
||||
* Returns the maximum of all values or <code>Float.NaN</code> if this
|
||||
* DocValues instance does not contain any value.
|
||||
* <p>
|
||||
* This operation is optional
|
||||
* </p>
|
||||
*
|
||||
* @return the maximum of all values or <code>Float.NaN</code> if this
|
||||
* DocValues instance does not contain any value.
|
||||
*/
|
||||
public float getMaxValue () {
|
||||
public float getMaxValue() {
|
||||
compute();
|
||||
return maxVal;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the average of all values.
|
||||
* Returns the average of all values or <code>Float.NaN</code> if this
|
||||
* DocValues instance does not contain any value. *
|
||||
* <p>
|
||||
* This operation is optional
|
||||
* </p>
|
||||
*
|
||||
* @return the average of all values or <code>Float.NaN</code> if this
|
||||
* DocValues instance does not contain any value
|
||||
*/
|
||||
public float getAverageValue () {
|
||||
public float getAverageValue() {
|
||||
compute();
|
||||
return avgVal;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
package org.apache.lucene.search.function;
|
||||
|
||||
/**
|
||||
* 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.util.LuceneTestCase;
|
||||
|
||||
/**
|
||||
* DocValues TestCase
|
||||
*/
|
||||
public class TestDocValues extends LuceneTestCase {
|
||||
|
||||
/* @override constructor */
|
||||
public TestDocValues(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
/* @override */
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
/* @override */
|
||||
protected void setUp() throws Exception {
|
||||
// prepare a small index with just a few documents.
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
public void testGetMinValue() {
|
||||
float[] innerArray = new float[] { 1.0f, 2.0f, -1.0f, 100.0f };
|
||||
DocValuesTestImpl docValues = new DocValuesTestImpl(innerArray);
|
||||
assertEquals("-1.0f is the min value in the source array", -1.0f, docValues
|
||||
.getMinValue());
|
||||
|
||||
// test with without values - NaN
|
||||
innerArray = new float[] {};
|
||||
docValues = new DocValuesTestImpl(innerArray);
|
||||
assertTrue("max is NaN - no values in inner array", Float.isNaN(docValues
|
||||
.getMinValue()));
|
||||
}
|
||||
|
||||
public void testGetMaxValue() {
|
||||
float[] innerArray = new float[] { 1.0f, 2.0f, -1.0f, 10.0f };
|
||||
DocValuesTestImpl docValues = new DocValuesTestImpl(innerArray);
|
||||
assertEquals("10.0f is the max value in the source array", 10.0f, docValues
|
||||
.getMaxValue());
|
||||
|
||||
innerArray = new float[] { -3.0f, -1.0f, -100.0f };
|
||||
docValues = new DocValuesTestImpl(innerArray);
|
||||
assertEquals("-1.0f is the max value in the source array", -1.0f, docValues
|
||||
.getMaxValue());
|
||||
|
||||
innerArray = new float[] { -3.0f, -1.0f, 100.0f, Float.MAX_VALUE,
|
||||
Float.MAX_VALUE - 1 };
|
||||
docValues = new DocValuesTestImpl(innerArray);
|
||||
assertEquals(Float.MAX_VALUE + " is the max value in the source array",
|
||||
Float.MAX_VALUE, docValues.getMaxValue());
|
||||
|
||||
// test with without values - NaN
|
||||
innerArray = new float[] {};
|
||||
docValues = new DocValuesTestImpl(innerArray);
|
||||
assertTrue("max is NaN - no values in inner array", Float.isNaN(docValues
|
||||
.getMaxValue()));
|
||||
}
|
||||
|
||||
public void testGetAverageValue() {
|
||||
float[] innerArray = new float[] { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
DocValuesTestImpl docValues = new DocValuesTestImpl(innerArray);
|
||||
assertEquals("the average is 1.0f", 1.0f, docValues.getAverageValue());
|
||||
|
||||
innerArray = new float[] { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f };
|
||||
docValues = new DocValuesTestImpl(innerArray);
|
||||
assertEquals("the average is 3.5f", 3.5f, docValues.getAverageValue());
|
||||
|
||||
// test with negative values
|
||||
innerArray = new float[] { -1.0f, 2.0f };
|
||||
docValues = new DocValuesTestImpl(innerArray);
|
||||
assertEquals("the average is 0.5f", 0.5f, docValues.getAverageValue());
|
||||
|
||||
// test with without values - NaN
|
||||
innerArray = new float[] {};
|
||||
docValues = new DocValuesTestImpl(innerArray);
|
||||
assertTrue("the average is NaN - no values in inner array", Float
|
||||
.isNaN(docValues.getAverageValue()));
|
||||
}
|
||||
|
||||
static class DocValuesTestImpl extends DocValues {
|
||||
float[] innerArray;
|
||||
|
||||
DocValuesTestImpl(float[] innerArray) {
|
||||
this.innerArray = innerArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.lucene.search.function.DocValues#floatVal(int)
|
||||
*/
|
||||
/* @Override */
|
||||
public float floatVal(int doc) {
|
||||
return innerArray[doc];
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.apache.lucene.search.function.DocValues#toString(int)
|
||||
*/
|
||||
/* @Override */
|
||||
public String toString(int doc) {
|
||||
return Integer.toString(doc);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue