function score: fix cast in Gaussian decay function
Also fix the test FunctionScoreTests#simpleWeightedFunctionsTestWithRandomWeightsAndRandomCombineMode which sometimes failed due to rounding issues. Make sure only floats are returned as scores to assure ratio of expected and returned score is 1.0f.
This commit is contained in:
parent
3142fec206
commit
be7c75c745
|
@ -40,7 +40,7 @@ public class GaussDecayFunctionParser extends DecayFunctionParser {
|
|||
public double evaluate(double value, double scale) {
|
||||
// note that we already computed scale^2 in processScale() so we do
|
||||
// not need to square it here.
|
||||
return (float) Math.exp(0.5 * Math.pow(value, 2.0) / scale);
|
||||
return Math.exp(0.5 * Math.pow(value, 2.0) / scale);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -35,7 +35,6 @@ import java.io.IOException;
|
|||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import static org.elasticsearch.client.Requests.searchRequest;
|
||||
import static org.elasticsearch.common.io.Streams.copyToStringFromClasspath;
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||
import static org.elasticsearch.index.query.FilterBuilders.termFilter;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.functionScoreQuery;
|
||||
|
@ -51,10 +50,10 @@ public class FunctionScoreTests extends ElasticsearchIntegrationTest {
|
|||
static final String TYPE = "type";
|
||||
static final String INDEX = "index";
|
||||
static final String TEXT_FIELD = "text_field";
|
||||
static final String FLOAT_FIELD = "float_field";
|
||||
static final String DOUBLE_FIELD = "double_field";
|
||||
static final String GEO_POINT_FIELD = "geo_point_field";
|
||||
static final XContentBuilder SIMPLE_DOC;
|
||||
static final XContentBuilder MAPPING_WITH_FLOAT_AND_GEO_POINT_AND_TEST_FIELD;
|
||||
static final XContentBuilder MAPPING_WITH_DOUBLE_AND_GEO_POINT_AND_TEXT_FIELD;
|
||||
|
||||
@Test
|
||||
public void testExplainQueryOnlyOnce() throws IOException, ExecutionException, InterruptedException {
|
||||
|
@ -106,7 +105,7 @@ public class FunctionScoreTests extends ElasticsearchIntegrationTest {
|
|||
|
||||
static {
|
||||
XContentBuilder simpleDoc;
|
||||
XContentBuilder mappingWithFloatAndGeoPointAndTestField;
|
||||
XContentBuilder mappingWithDoubleAndGeoPointAndTestField;
|
||||
try {
|
||||
simpleDoc = jsonBuilder().startObject()
|
||||
.field(TEXT_FIELD, "value")
|
||||
|
@ -114,7 +113,7 @@ public class FunctionScoreTests extends ElasticsearchIntegrationTest {
|
|||
.field("lat", 10)
|
||||
.field("lon", 20)
|
||||
.endObject()
|
||||
.field(FLOAT_FIELD, 2.71828)
|
||||
.field(DOUBLE_FIELD, Math.E)
|
||||
.endObject();
|
||||
} catch (IOException e) {
|
||||
throw new ElasticsearchException("Exception while initializing FunctionScoreTests", e);
|
||||
|
@ -122,7 +121,7 @@ public class FunctionScoreTests extends ElasticsearchIntegrationTest {
|
|||
SIMPLE_DOC = simpleDoc;
|
||||
try {
|
||||
|
||||
mappingWithFloatAndGeoPointAndTestField = jsonBuilder().startObject()
|
||||
mappingWithDoubleAndGeoPointAndTestField = jsonBuilder().startObject()
|
||||
.startObject(TYPE)
|
||||
.startObject("properties")
|
||||
.startObject(TEXT_FIELD)
|
||||
|
@ -131,8 +130,8 @@ public class FunctionScoreTests extends ElasticsearchIntegrationTest {
|
|||
.startObject(GEO_POINT_FIELD)
|
||||
.field("type", "geo_point")
|
||||
.endObject()
|
||||
.startObject(FLOAT_FIELD)
|
||||
.field("type", "float")
|
||||
.startObject(DOUBLE_FIELD)
|
||||
.field("type", "double")
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject()
|
||||
|
@ -140,13 +139,13 @@ public class FunctionScoreTests extends ElasticsearchIntegrationTest {
|
|||
} catch (IOException e) {
|
||||
throw new ElasticsearchException("Exception while initializing FunctionScoreTests", e);
|
||||
}
|
||||
MAPPING_WITH_FLOAT_AND_GEO_POINT_AND_TEST_FIELD = mappingWithFloatAndGeoPointAndTestField;
|
||||
MAPPING_WITH_DOUBLE_AND_GEO_POINT_AND_TEXT_FIELD = mappingWithDoubleAndGeoPointAndTestField;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExplain() throws IOException, ExecutionException, InterruptedException {
|
||||
assertAcked(prepareCreate(INDEX).addMapping(
|
||||
TYPE, MAPPING_WITH_FLOAT_AND_GEO_POINT_AND_TEST_FIELD
|
||||
TYPE, MAPPING_WITH_DOUBLE_AND_GEO_POINT_AND_TEXT_FIELD
|
||||
));
|
||||
ensureYellow();
|
||||
|
||||
|
@ -158,12 +157,12 @@ public class FunctionScoreTests extends ElasticsearchIntegrationTest {
|
|||
searchSource().query(
|
||||
functionScoreQuery(termFilter(TEXT_FIELD, "value").cache(false))
|
||||
.add(gaussDecayFunction(GEO_POINT_FIELD, new GeoPoint(10, 20), "1000km"))
|
||||
.add(fieldValueFactorFunction(FLOAT_FIELD).modifier(FieldValueFactorFunction.Modifier.LN).setWeight(2))
|
||||
.add(fieldValueFactorFunction(DOUBLE_FIELD).modifier(FieldValueFactorFunction.Modifier.LN).setWeight(2))
|
||||
.add(scriptFunction("_index['" + TEXT_FIELD + "']['value'].tf()").setWeight(3))
|
||||
).explain(true))).actionGet();
|
||||
|
||||
assertThat(responseWithWeights.getHits().getAt(0).getExplanation().toString(),
|
||||
equalTo("5.999996 = (MATCH) function score, product of:\n 1.0 = (MATCH) ConstantScore(text_field:value), product of:\n 1.0 = boost\n 1.0 = queryNorm\n 5.999996 = (MATCH) Math.min of\n 5.999996 = (MATCH) function score, score mode [multiply]\n 1.0 = (MATCH) function score, product of:\n 1.0 = match filter: *:*\n 1.0 = (MATCH) Function for field geo_point_field:\n 1.0 = exp(-0.5*pow(MIN of: [Math.max(arcDistance([10.0, 20.0](=doc value),[10.0, 20.0](=origin)) - 0.0(=offset), 0)],2.0)/7.213475204444817E11)\n 1.9999987 = (MATCH) function score, product of:\n 1.0 = match filter: *:*\n 1.9999987 = (MATCH) product of:\n 0.99999934 = field value function: ln(doc['float_field'].value * factor=1.0)\n 2.0 = weight\n 3.0 = (MATCH) function score, product of:\n 1.0 = match filter: *:*\n 3.0 = (MATCH) product of:\n 1.0 = script score function, computed with script:\"_index['text_field']['value'].tf()\n 3.0 = weight\n 3.4028235E38 = maxBoost\n 1.0 = queryBoost\n")
|
||||
equalTo("6.0 = (MATCH) function score, product of:\n 1.0 = (MATCH) ConstantScore(text_field:value), product of:\n 1.0 = boost\n 1.0 = queryNorm\n 6.0 = (MATCH) Math.min of\n 6.0 = (MATCH) function score, score mode [multiply]\n 1.0 = (MATCH) function score, product of:\n 1.0 = match filter: *:*\n 1.0 = (MATCH) Function for field geo_point_field:\n 1.0 = exp(-0.5*pow(MIN of: [Math.max(arcDistance([10.0, 20.0](=doc value),[10.0, 20.0](=origin)) - 0.0(=offset), 0)],2.0)/7.213475204444817E11)\n 2.0 = (MATCH) function score, product of:\n 1.0 = match filter: *:*\n 2.0 = (MATCH) product of:\n 1.0 = field value function: ln(doc['double_field'].value * factor=1.0)\n 2.0 = weight\n 3.0 = (MATCH) function score, product of:\n 1.0 = match filter: *:*\n 3.0 = (MATCH) product of:\n 1.0 = script score function, computed with script:\"_index['text_field']['value'].tf()\n 3.0 = weight\n 3.4028235E38 = maxBoost\n 1.0 = queryBoost\n")
|
||||
);
|
||||
responseWithWeights = client().search(
|
||||
searchRequest().source(
|
||||
|
@ -180,7 +179,7 @@ public class FunctionScoreTests extends ElasticsearchIntegrationTest {
|
|||
@Test
|
||||
public void simpleWeightedFunctionsTest() throws IOException, ExecutionException, InterruptedException {
|
||||
assertAcked(prepareCreate(INDEX).addMapping(
|
||||
TYPE, MAPPING_WITH_FLOAT_AND_GEO_POINT_AND_TEST_FIELD
|
||||
TYPE, MAPPING_WITH_DOUBLE_AND_GEO_POINT_AND_TEXT_FIELD
|
||||
));
|
||||
ensureYellow();
|
||||
|
||||
|
@ -191,7 +190,7 @@ public class FunctionScoreTests extends ElasticsearchIntegrationTest {
|
|||
searchSource().query(
|
||||
functionScoreQuery(termFilter(TEXT_FIELD, "value"))
|
||||
.add(gaussDecayFunction(GEO_POINT_FIELD, new GeoPoint(10, 20), "1000km"))
|
||||
.add(fieldValueFactorFunction(FLOAT_FIELD).modifier(FieldValueFactorFunction.Modifier.LN))
|
||||
.add(fieldValueFactorFunction(DOUBLE_FIELD).modifier(FieldValueFactorFunction.Modifier.LN))
|
||||
.add(scriptFunction("_index['" + TEXT_FIELD + "']['value'].tf()"))
|
||||
))).actionGet();
|
||||
SearchResponse responseWithWeights = client().search(
|
||||
|
@ -199,29 +198,22 @@ public class FunctionScoreTests extends ElasticsearchIntegrationTest {
|
|||
searchSource().query(
|
||||
functionScoreQuery(termFilter(TEXT_FIELD, "value"))
|
||||
.add(gaussDecayFunction(GEO_POINT_FIELD, new GeoPoint(10, 20), "1000km").setWeight(2))
|
||||
.add(fieldValueFactorFunction(FLOAT_FIELD).modifier(FieldValueFactorFunction.Modifier.LN).setWeight(2))
|
||||
.add(fieldValueFactorFunction(DOUBLE_FIELD).modifier(FieldValueFactorFunction.Modifier.LN).setWeight(2))
|
||||
.add(scriptFunction("_index['" + TEXT_FIELD + "']['value'].tf()").setWeight(2))
|
||||
))).actionGet();
|
||||
|
||||
assertThat((double) response.getHits().getAt(0).getScore(), closeTo(1.0, 1.e-5));
|
||||
assertThat((double) responseWithWeights.getHits().getAt(0).getScore(), closeTo(8.0, 1.e-5));
|
||||
assertThat(response.getHits().getAt(0).getScore(), is(1.0f));
|
||||
assertThat(responseWithWeights.getHits().getAt(0).getScore(), is(8.0f));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleWeightedFunctionsTestWithRandomWeightsAndRandomCombineMode() throws IOException, ExecutionException, InterruptedException {
|
||||
assertAcked(prepareCreate(INDEX).addMapping(
|
||||
TYPE,
|
||||
MAPPING_WITH_FLOAT_AND_GEO_POINT_AND_TEST_FIELD));
|
||||
MAPPING_WITH_DOUBLE_AND_GEO_POINT_AND_TEXT_FIELD));
|
||||
ensureYellow();
|
||||
|
||||
XContentBuilder doc = jsonBuilder().startObject()
|
||||
.field(TEXT_FIELD, "value")
|
||||
.startObject(GEO_POINT_FIELD)
|
||||
.field("lat", 10)
|
||||
.field("lon", 20)
|
||||
.endObject()
|
||||
.field(FLOAT_FIELD, 10)
|
||||
.endObject();
|
||||
XContentBuilder doc = SIMPLE_DOC;
|
||||
index(INDEX, TYPE, "1", doc);
|
||||
refresh();
|
||||
ScoreFunctionBuilder[] scoreFunctionBuilders = getScoreFunctionBuilders();
|
||||
|
@ -232,7 +224,7 @@ public class FunctionScoreTests extends ElasticsearchIntegrationTest {
|
|||
FunctionScoreQueryBuilder withWeights = functionScoreQuery(termFilter(TEXT_FIELD, "value")).scoreMode(scoreMode);
|
||||
int weightscounter = 0;
|
||||
for (ScoreFunctionBuilder builder : scoreFunctionBuilders) {
|
||||
withWeights.add(builder.setWeight((float) weights[weightscounter]));
|
||||
withWeights.add(builder.setWeight(weights[weightscounter]));
|
||||
weightscounter++;
|
||||
}
|
||||
SearchResponse responseWithWeights = client().search(
|
||||
|
@ -240,8 +232,7 @@ public class FunctionScoreTests extends ElasticsearchIntegrationTest {
|
|||
).actionGet();
|
||||
|
||||
double expectedScore = computeExpectedScore(weights, scores, scoreMode);
|
||||
assertThat(expectedScore / responseWithWeights.getHits().getAt(0).getScore(), closeTo(1.0, 1.e-6));
|
||||
|
||||
assertThat((float) expectedScore / responseWithWeights.getHits().getAt(0).getScore(), is(1.0f));
|
||||
}
|
||||
|
||||
protected double computeExpectedScore(float[] weights, float[] scores, String scoreMode) {
|
||||
|
@ -273,7 +264,7 @@ public class FunctionScoreTests extends ElasticsearchIntegrationTest {
|
|||
|
||||
}
|
||||
if ("avg".equals(scoreMode)) {
|
||||
expectedScore /= (double) weights.length;
|
||||
expectedScore /= weights.length;
|
||||
}
|
||||
return expectedScore;
|
||||
}
|
||||
|
@ -282,7 +273,7 @@ public class FunctionScoreTests extends ElasticsearchIntegrationTest {
|
|||
public void simpleWeightedFunctionsTestSingleFunction() throws IOException, ExecutionException, InterruptedException {
|
||||
assertAcked(prepareCreate(INDEX).addMapping(
|
||||
TYPE,
|
||||
MAPPING_WITH_FLOAT_AND_GEO_POINT_AND_TEST_FIELD));
|
||||
MAPPING_WITH_DOUBLE_AND_GEO_POINT_AND_TEXT_FIELD));
|
||||
ensureYellow();
|
||||
|
||||
XContentBuilder doc = jsonBuilder().startObject()
|
||||
|
@ -291,7 +282,7 @@ public class FunctionScoreTests extends ElasticsearchIntegrationTest {
|
|||
.field("lat", 12)
|
||||
.field("lon", 21)
|
||||
.endObject()
|
||||
.field(FLOAT_FIELD, 10)
|
||||
.field(DOUBLE_FIELD, 10)
|
||||
.endObject();
|
||||
index(INDEX, TYPE, "1", doc);
|
||||
refresh();
|
||||
|
@ -306,7 +297,7 @@ public class FunctionScoreTests extends ElasticsearchIntegrationTest {
|
|||
searchRequest().source(searchSource().query(withWeights))
|
||||
).actionGet();
|
||||
|
||||
assertThat((double) scores[0] * weights[0] / responseWithWeights.getHits().getAt(0).getScore(), closeTo(1.0, 1.e-6));
|
||||
assertThat( (double) scores[0] * weights[0]/ responseWithWeights.getHits().getAt(0).getScore(), closeTo(1.0, 1.e-6));
|
||||
|
||||
}
|
||||
|
||||
|
@ -334,16 +325,16 @@ public class FunctionScoreTests extends ElasticsearchIntegrationTest {
|
|||
private float[] createRandomWeights(int size) {
|
||||
float[] weights = new float[size];
|
||||
for (int i = 0; i < weights.length; i++) {
|
||||
weights[i] = randomFloat() * (randomBoolean() ? 1.0f : -1.0f) * (float) randomInt(100) + 1.e-6f;
|
||||
weights[i] = randomFloat() * (randomBoolean() ? 1.0f : -1.0f) * randomInt(100) + 1.e-6f;
|
||||
}
|
||||
return weights;
|
||||
}
|
||||
|
||||
public ScoreFunctionBuilder[] getScoreFunctionBuilders() {
|
||||
ScoreFunctionBuilder[] builders = new ScoreFunctionBuilder[4];
|
||||
builders[0] = gaussDecayFunction(GEO_POINT_FIELD, new GeoPoint(11, 20), "1000km");
|
||||
builders[0] = gaussDecayFunction(GEO_POINT_FIELD, new GeoPoint(10, 20), "1000km");
|
||||
builders[1] = randomFunction(10);
|
||||
builders[2] = fieldValueFactorFunction(FLOAT_FIELD).modifier(FieldValueFactorFunction.Modifier.LN);
|
||||
builders[2] = fieldValueFactorFunction(DOUBLE_FIELD).modifier(FieldValueFactorFunction.Modifier.LN);
|
||||
builders[3] = scriptFunction("_index['" + TEXT_FIELD + "']['value'].tf()");
|
||||
return builders;
|
||||
}
|
||||
|
@ -352,7 +343,7 @@ public class FunctionScoreTests extends ElasticsearchIntegrationTest {
|
|||
public void checkWeightOnlyCreatesBoostFunction() throws IOException {
|
||||
assertAcked(prepareCreate(INDEX).addMapping(
|
||||
TYPE,
|
||||
MAPPING_WITH_FLOAT_AND_GEO_POINT_AND_TEST_FIELD));
|
||||
MAPPING_WITH_DOUBLE_AND_GEO_POINT_AND_TEXT_FIELD));
|
||||
ensureYellow();
|
||||
|
||||
index(INDEX, TYPE, "1", SIMPLE_DOC);
|
||||
|
|
Loading…
Reference in New Issue