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
|
on EOF, removed numeric overflow possibilities and added support
|
||||||
for a hack to unmap the buffers on closing IndexInput.
|
for a hack to unmap the buffers on closing IndexInput.
|
||||||
(Uwe Schindler)
|
(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
|
New features
|
||||||
|
|
||||||
|
|
|
@ -114,17 +114,15 @@ public abstract class DocValues {
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- some simple statistics on values
|
// --- some simple statistics on values
|
||||||
private float minVal;
|
private float minVal = Float.NaN;
|
||||||
private float maxVal;
|
private float maxVal = Float.NaN;
|
||||||
private float avgVal;
|
private float avgVal = Float.NaN;
|
||||||
private boolean computed=false;
|
private boolean computed=false;
|
||||||
// compute optional values
|
// compute optional values
|
||||||
private void compute () {
|
private void compute() {
|
||||||
if (computed) {
|
if (computed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
minVal = Float.MAX_VALUE;
|
|
||||||
maxVal = 0;
|
|
||||||
float sum = 0;
|
float sum = 0;
|
||||||
int n = 0;
|
int n = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -135,34 +133,56 @@ public abstract class DocValues {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
sum += val;
|
sum += val;
|
||||||
minVal = Math.min(minVal,val);
|
minVal = Float.isNaN(minVal) ? val : Math.min(minVal, val);
|
||||||
maxVal = Math.max(maxVal,val);
|
maxVal = Float.isNaN(maxVal) ? val : Math.max(maxVal, val);
|
||||||
|
++n;
|
||||||
}
|
}
|
||||||
avgVal = sum / n;
|
|
||||||
|
avgVal = n == 0 ? Float.NaN : sum / n;
|
||||||
computed = true;
|
computed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optional op.
|
* Returns the minimum of all values or <code>Float.NaN</code> if this
|
||||||
* Returns the minimum of all values.
|
* 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();
|
compute();
|
||||||
return minVal;
|
return minVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optional op.
|
* Returns the maximum of all values or <code>Float.NaN</code> if this
|
||||||
* Returns the maximum of all values.
|
* 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();
|
compute();
|
||||||
return maxVal;
|
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();
|
compute();
|
||||||
return avgVal;
|
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