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:
Mark Robert Miller 2009-06-16 14:49:18 +00:00
parent ea9fcfe3fc
commit baaa029331
3 changed files with 168 additions and 19 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}
}
}