Fix some minor things in function score parser/builder

- remove default scale weight in builder
- make parameters object/double instead of string
- do not convert number to string and back again, parse double instead
- remove javadoc reference to test classes
- Set parameters in constructor instead of in method
This commit is contained in:
Britta Weber 2013-08-14 12:57:03 +02:00
parent 592e637293
commit ebbd00acc2
7 changed files with 73 additions and 93 deletions

View File

@ -19,7 +19,6 @@
package org.elasticsearch.index.query.functionscore; package org.elasticsearch.index.query.functionscore;
import org.elasticsearch.ElasticSearchIllegalStateException; import org.elasticsearch.ElasticSearchIllegalStateException;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
@ -30,45 +29,37 @@ public abstract class DecayFunctionBuilder implements ScoreFunctionBuilder {
protected static final String REFERNECE = "reference"; protected static final String REFERNECE = "reference";
protected static final String SCALE = "scale"; protected static final String SCALE = "scale";
protected static final String SCALE_WEIGHT = "scale_weight"; protected static final String SCALE_WEIGHT = "scale_weight";
protected static final String SCALE_DEFAULT = "0.5";
private String fieldName;
private String reference;
private String scale;
private String scaleWeight;
public void setParameters(String fieldName, String reference, String scale, String scaleWeight) { private String fieldName;
if(this.fieldName != null ) { private Object reference;
throw new ElasticSearchIllegalStateException("Can not set parameters of decay function more than once."); private Object scale;
} private double scaleWeight = -1;
public DecayFunctionBuilder(String fieldName, Object reference, Object scale) {
this.fieldName = fieldName; this.fieldName = fieldName;
this.reference = reference; this.reference = reference;
this.scale = scale; this.scale = scale;
}
public DecayFunctionBuilder setScaleWeight(double scaleWeight) {
if(scaleWeight <=0 || scaleWeight >= 1.0) {
throw new ElasticSearchIllegalStateException("scale weight parameter must be in range 0..1!");
}
this.scaleWeight = scaleWeight; this.scaleWeight = scaleWeight;
return this;
} }
public void setParameters(String fieldName, String reference, String scale) {
setParameters(fieldName, reference, scale, SCALE_DEFAULT);
}
@Override @Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(getName()); builder.startObject(getName());
builder.startObject(fieldName); builder.startObject(fieldName);
builder.field(REFERNECE, reference); builder.field(REFERNECE, reference);
builder.field(SCALE, scale); builder.field(SCALE, scale);
if (scaleWeight > 0) {
builder.field(SCALE_WEIGHT, scaleWeight); builder.field(SCALE_WEIGHT, scaleWeight);
builder.endObject(); }
builder.endObject();
builder.endObject(); builder.endObject();
return builder; return builder;
} }
public void addGeoParams(String fieldName, double lat, double lon, String scale) {
addGeoParams(fieldName, lat, lon, scale, SCALE_DEFAULT);
}
public void addGeoParams(String fieldName, double lat, double lon, String scale, String scaleWeight) {
String geoLoc = Double.toString(lat) + ", " + Double.toString(lon);
setParameters(fieldName, geoLoc, scale, scaleWeight);
}
} }

View File

@ -84,12 +84,7 @@ import java.io.IOException;
* See {@link GaussDecayFunctionBuilder} and {@link GaussDecayFunctionParser} * See {@link GaussDecayFunctionBuilder} and {@link GaussDecayFunctionParser}
* for an example. The parser furthermore needs to be registered in the * for an example. The parser furthermore needs to be registered in the
* {@link org.elasticsearch.index.query.functionscore.FunctionScoreModule * {@link org.elasticsearch.index.query.functionscore.FunctionScoreModule
* FunctionScoreModule}. See * FunctionScoreModule}.
* {@link org.elasticsearch.test.integration.search.functionscore.CustomDistanceScorePlugin
* CustomDistanceScorePlugin} and
* {@link org.elasticsearch.test.integration.search.functionscore.CustomDistanceScorePlugin
* DistanceScorePluginTest DistanceScorePluginTest} for an example on how to
* write your own function and plugin.
* *
* **/ * **/
@ -165,28 +160,30 @@ public abstract class DecayFunctionParser implements ScoreFunctionParser {
NumberFieldMapper<?> mapper) throws IOException { NumberFieldMapper<?> mapper) throws IOException {
XContentParser.Token token; XContentParser.Token token;
String parameterName = null; String parameterName = null;
String scaleString = null; double scale = 0;
String referenceString = null; double reference = 0;
double scaleWeight = 0.5; double scaleWeight = 0.5;
boolean scaleFound = false;
boolean refFound = false;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) { if (token == XContentParser.Token.FIELD_NAME) {
parameterName = parser.currentName(); parameterName = parser.currentName();
} else if (parameterName.equals(DecayFunctionBuilder.SCALE)) { } else if (parameterName.equals(DecayFunctionBuilder.SCALE)) {
scaleString = parser.text(); scale = parser.doubleValue();
scaleFound = true;
} else if (parameterName.equals(DecayFunctionBuilder.SCALE_WEIGHT)) { } else if (parameterName.equals(DecayFunctionBuilder.SCALE_WEIGHT)) {
scaleWeight = parser.doubleValue(); scaleWeight = parser.doubleValue();
} else if (parameterName.equals(DecayFunctionBuilder.REFERNECE)) { } else if (parameterName.equals(DecayFunctionBuilder.REFERNECE)) {
referenceString = parser.text(); reference = parser.doubleValue();
refFound = true;
} else { } else {
throw new ElasticSearchParseException("Parameter " + parameterName + " not supported!"); throw new ElasticSearchParseException("Parameter " + parameterName + " not supported!");
} }
} }
if (scaleString == null || referenceString == null) { if (!scaleFound || !refFound) {
throw new ElasticSearchParseException("Both " + DecayFunctionBuilder.SCALE + "and " + DecayFunctionBuilder.REFERNECE throw new ElasticSearchParseException("Both " + DecayFunctionBuilder.SCALE + "and " + DecayFunctionBuilder.REFERNECE
+ " must be set for numeric fields."); + " must be set for numeric fields.");
} }
double reference = mapper.value(referenceString).doubleValue();
double scale = mapper.value(scaleString).doubleValue();
IndexNumericFieldData<?> numericFieldData = parseContext.fieldData().getForField(mapper); IndexNumericFieldData<?> numericFieldData = parseContext.fieldData().getForField(mapper);
return new NumericFieldDataScoreFunction(reference, scale, scaleWeight, getDecayFunction(), numericFieldData); return new NumericFieldDataScoreFunction(reference, scale, scaleWeight, getDecayFunction(), numericFieldData);
} }
@ -375,7 +372,7 @@ public abstract class DecayFunctionParser implements ScoreFunctionParser {
@Override @Override
public Explanation explainScore(int docId, Explanation subQueryExpl) { public Explanation explainScore(int docId, Explanation subQueryExpl) {
ComplexExplanation ce = new ComplexExplanation(); ComplexExplanation ce = new ComplexExplanation();
ce.setValue((float)score(docId, subQueryExpl.getValue())); ce.setValue((float) score(docId, subQueryExpl.getValue()));
ce.setMatch(true); ce.setMatch(true);
ce.setDescription("subQueryScore * Function for field " + getFieldName() + ":"); ce.setDescription("subQueryScore * Function for field " + getFieldName() + ":");
ce.addDetail(func.explainFunction(getDistanceString(docId), distance(docId), scale)); ce.addDetail(func.explainFunction(getDistanceString(docId), distance(docId), scale));
@ -385,7 +382,7 @@ public abstract class DecayFunctionParser implements ScoreFunctionParser {
@Override @Override
public Explanation explainFactor(int docId) { public Explanation explainFactor(int docId) {
ComplexExplanation ce = new ComplexExplanation(); ComplexExplanation ce = new ComplexExplanation();
ce.setValue((float)factor(docId)); ce.setValue((float) factor(docId));
ce.setMatch(true); ce.setMatch(true);
ce.setDescription("subQueryScore * Function for field " + getFieldName() + ":"); ce.setDescription("subQueryScore * Function for field " + getFieldName() + ":");
ce.addDetail(func.explainFunction(getDistanceString(docId), distance(docId), scale)); ce.addDetail(func.explainFunction(getDistanceString(docId), distance(docId), scale));

View File

@ -24,6 +24,10 @@ import org.elasticsearch.index.query.functionscore.DecayFunctionBuilder;
public class ExponentialDecayFunctionBuilder extends DecayFunctionBuilder { public class ExponentialDecayFunctionBuilder extends DecayFunctionBuilder {
public ExponentialDecayFunctionBuilder(String fieldName, Object reference, Object scale) {
super(fieldName, reference, scale);
}
@Override @Override
public String getName() { public String getName() {
return ExponentialDecayFunctionParser.NAMES[0]; return ExponentialDecayFunctionParser.NAMES[0];

View File

@ -24,6 +24,10 @@ import org.elasticsearch.index.query.functionscore.DecayFunctionBuilder;
public class GaussDecayFunctionBuilder extends DecayFunctionBuilder { public class GaussDecayFunctionBuilder extends DecayFunctionBuilder {
public GaussDecayFunctionBuilder(String fieldName, Object reference, Object scale) {
super(fieldName, reference, scale);
}
@Override @Override
public String getName() { public String getName() {
return GaussDecayFunctionParser.NAMES[0]; return GaussDecayFunctionParser.NAMES[0];

View File

@ -23,6 +23,10 @@ import org.elasticsearch.index.query.functionscore.DecayFunctionBuilder;
public class LinearDecayFunctionBuilder extends DecayFunctionBuilder { public class LinearDecayFunctionBuilder extends DecayFunctionBuilder {
public LinearDecayFunctionBuilder(String fieldName, Object reference, Object scale) {
super(fieldName, reference, scale);
}
@Override @Override
public String getName() { public String getName() {
return LinearDecayFunctionParser.NAMES[0]; return LinearDecayFunctionParser.NAMES[0];

View File

@ -19,6 +19,7 @@
package org.elasticsearch.test.integration.search.functionscore; package org.elasticsearch.test.integration.search.functionscore;
import org.elasticsearch.ElasticSearchIllegalStateException;
import org.elasticsearch.action.ActionFuture; import org.elasticsearch.action.ActionFuture;
import org.elasticsearch.action.index.IndexRequestBuilder; import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.search.SearchPhaseExecutionException; import org.elasticsearch.action.search.SearchPhaseExecutionException;
@ -86,8 +87,10 @@ public class DecayFunctionScoreTests extends AbstractSharedClusterTest {
refresh(); refresh();
// Test Gauss // Test Gauss
DecayFunctionBuilder fb = new GaussDecayFunctionBuilder(); List<Float> lonlat = new ArrayList<Float>();
fb.addGeoParams("loc", 11, 20, "1000km"); lonlat.add(new Float(20));
lonlat.add(new Float(11));
DecayFunctionBuilder fb = new GaussDecayFunctionBuilder("loc", lonlat, "1000km");
ActionFuture<SearchResponse> response = client().search( ActionFuture<SearchResponse> response = client().search(
searchRequest().searchType(SearchType.QUERY_THEN_FETCH).source( searchRequest().searchType(SearchType.QUERY_THEN_FETCH).source(
@ -106,8 +109,7 @@ public class DecayFunctionScoreTests extends AbstractSharedClusterTest {
assertThat(sh.getAt(0).getId(), equalTo("1")); assertThat(sh.getAt(0).getId(), equalTo("1"));
assertThat(sh.getAt(1).getId(), equalTo("2")); assertThat(sh.getAt(1).getId(), equalTo("2"));
// Test Exp // Test Exp
fb = new ExponentialDecayFunctionBuilder(); fb = new ExponentialDecayFunctionBuilder("loc", lonlat, "1000km");
fb.addGeoParams("loc", 11, 20, "1000km");
response = client().search( response = client().search(
searchRequest().searchType(SearchType.QUERY_THEN_FETCH).source( searchRequest().searchType(SearchType.QUERY_THEN_FETCH).source(
@ -126,8 +128,7 @@ public class DecayFunctionScoreTests extends AbstractSharedClusterTest {
assertThat(sh.getAt(0).getId(), equalTo("1")); assertThat(sh.getAt(0).getId(), equalTo("1"));
assertThat(sh.getAt(1).getId(), equalTo("2")); assertThat(sh.getAt(1).getId(), equalTo("2"));
// Test Lin // Test Lin
fb = new LinearDecayFunctionBuilder(); fb = new LinearDecayFunctionBuilder("loc", lonlat, "1000km");
fb.addGeoParams("loc", 11, 20, "1000km");
response = client().search( response = client().search(
searchRequest().searchType(SearchType.QUERY_THEN_FETCH).source( searchRequest().searchType(SearchType.QUERY_THEN_FETCH).source(
@ -160,8 +161,7 @@ public class DecayFunctionScoreTests extends AbstractSharedClusterTest {
.source(jsonBuilder().startObject().field("test", "value").field("num1", "2013-05-28").endObject())).actionGet(); .source(jsonBuilder().startObject().field("test", "value").field("num1", "2013-05-28").endObject())).actionGet();
refresh(); refresh();
DecayFunctionBuilder gfb = new GaussDecayFunctionBuilder(); DecayFunctionBuilder gfb = new GaussDecayFunctionBuilder("num1", "2013-05-28", "-1d");
gfb.setParameters("num1", "2013-05-28", "-1d");
ActionFuture<SearchResponse> response = client().search( ActionFuture<SearchResponse> response = client().search(
searchRequest().searchType(SearchType.QUERY_THEN_FETCH).source( searchRequest().searchType(SearchType.QUERY_THEN_FETCH).source(
@ -176,32 +176,10 @@ public class DecayFunctionScoreTests extends AbstractSharedClusterTest {
} }
@Test(expected = SearchPhaseExecutionException.class) @Test(expected = ElasticSearchIllegalStateException.class)
public void testExceptionThrownIfScaleRefNotBetween0And1() throws Exception { public void testExceptionThrownIfScaleRefNotBetween0And1() throws Exception {
createIndexMapped("test", "type1", "test", "string", "num1", "date"); DecayFunctionBuilder gfb = new GaussDecayFunctionBuilder("num1", "2013-05-28", "1d").setScaleWeight(100);
ensureYellow();
client().index(
indexRequest("test").type("type1").id("1")
.source(jsonBuilder().startObject().field("test", "value").field("num1", "2013-05-27").endObject())).actionGet();
client().index(
indexRequest("test").type("type1").id("2")
.source(jsonBuilder().startObject().field("test", "value").field("num1", "2013-05-28").endObject())).actionGet();
refresh();
DecayFunctionBuilder gfb = new GaussDecayFunctionBuilder();
gfb.setParameters("num1", "2013-05-28", "1d", "-1");
ActionFuture<SearchResponse> response = client().search(
searchRequest().searchType(SearchType.QUERY_THEN_FETCH).source(
searchSource().explain(true).query(functionScoreQuery(termQuery("test", "value")).add(gfb))));
SearchResponse sr = response.actionGet();
ElasticsearchAssertions.assertNoFailures(sr);
SearchHits sh = sr.getHits();
assertThat(sh.hits().length, equalTo(2));
assertThat(sh.getAt(0).getId(), equalTo("2"));
assertThat(sh.getAt(1).getId(), equalTo("1"));
} }
@ -231,10 +209,8 @@ public class DecayFunctionScoreTests extends AbstractSharedClusterTest {
refresh(); refresh();
DecayFunctionBuilder gfb1 = new LinearDecayFunctionBuilder(); DecayFunctionBuilder gfb1 = new LinearDecayFunctionBuilder("num1", "2013-05-28", "+3d");
gfb1.setParameters("num1", "2013-05-28", "+3d"); DecayFunctionBuilder gfb2 = new LinearDecayFunctionBuilder("num2", "0.0", "1");
DecayFunctionBuilder gfb2 = new LinearDecayFunctionBuilder();
gfb2.setParameters("num2", "0.0", "1");
ActionFuture<SearchResponse> response = client().search( ActionFuture<SearchResponse> response = client().search(
searchRequest().searchType(SearchType.QUERY_THEN_FETCH).source( searchRequest().searchType(SearchType.QUERY_THEN_FETCH).source(
@ -282,13 +258,13 @@ public class DecayFunctionScoreTests extends AbstractSharedClusterTest {
indexRandom("test", false, builders); indexRandom("test", false, builders);
refresh(); refresh();
DecayFunctionBuilder gfb1 = new LinearDecayFunctionBuilder(); List<Float> lonlat = new ArrayList<Float>();
DecayFunctionBuilder gfb2 = new LinearDecayFunctionBuilder(); lonlat.add(new Float(100));
DecayFunctionBuilder gfb3 = new LinearDecayFunctionBuilder(); lonlat.add(new Float(110));
gfb1.setParameters("date", "2013-05-30", "+15d"); DecayFunctionBuilder gfb1 = new LinearDecayFunctionBuilder("date", "2013-05-30", "+15d");
gfb2.addGeoParams("geo", 110, 100, "1000km"); DecayFunctionBuilder gfb2 = new LinearDecayFunctionBuilder("geo", lonlat, "1000km");
gfb3.setParameters("num", Integer.toString(numDocs), Integer.toString(numDocs / 2)); DecayFunctionBuilder gfb3 = new LinearDecayFunctionBuilder("num", Integer.toString(numDocs), Integer.toString(numDocs / 2));
ActionFuture<SearchResponse> response = client().search( ActionFuture<SearchResponse> response = client().search(
searchRequest().searchType(SearchType.QUERY_THEN_FETCH).source( searchRequest().searchType(SearchType.QUERY_THEN_FETCH).source(
@ -324,8 +300,10 @@ public class DecayFunctionScoreTests extends AbstractSharedClusterTest {
jsonBuilder().startObject().field("test", "value").startObject("geo").field("lat", 1).field("lon", 2).endObject() jsonBuilder().startObject().field("test", "value").startObject("geo").field("lat", 1).field("lon", 2).endObject()
.endObject())).actionGet(); .endObject())).actionGet();
refresh(); refresh();
DecayFunctionBuilder gfb2 = new LinearDecayFunctionBuilder(); List<Float> lonlat = new ArrayList<Float>();
gfb2.addGeoParams("type1.geo", 110, 100, "1000km"); lonlat.add(new Float(100));
lonlat.add(new Float(110));
DecayFunctionBuilder gfb2 = new LinearDecayFunctionBuilder("type1.geo", lonlat, "1000km");
ActionFuture<SearchResponse> response = client().search( ActionFuture<SearchResponse> response = client().search(
searchRequest().searchType(SearchType.QUERY_THEN_FETCH).source( searchRequest().searchType(SearchType.QUERY_THEN_FETCH).source(
searchSource() searchSource()
@ -345,9 +323,8 @@ public class DecayFunctionScoreTests extends AbstractSharedClusterTest {
indexRequest("test").type("type").source( indexRequest("test").type("type").source(
jsonBuilder().startObject().field("test", "value").field("num", Integer.toString(1)).endObject())).actionGet(); jsonBuilder().startObject().field("test", "value").field("num", Integer.toString(1)).endObject())).actionGet();
refresh(); refresh();
DecayFunctionBuilder lfb = new LinearDecayFunctionBuilder(); DecayFunctionBuilder lfb = new LinearDecayFunctionBuilder("num", Integer.toString(1), Integer.toString(1 / 2));
//so, we indexed a string field, but now we try to score a num field // so, we indexed a string field, but now we try to score a num field
lfb.setParameters("num", Integer.toString(1), Integer.toString(1 / 2));
ActionFuture<SearchResponse> response = client() ActionFuture<SearchResponse> response = client()
.search(searchRequest() .search(searchRequest()
.searchType(SearchType.QUERY_THEN_FETCH) .searchType(SearchType.QUERY_THEN_FETCH)

View File

@ -83,8 +83,7 @@ public class FunctionScorePluginTests extends AbstractNodesTests {
.source(jsonBuilder().startObject().field("test", "value").field("num1", "2013-05-27").endObject())).actionGet(); .source(jsonBuilder().startObject().field("test", "value").field("num1", "2013-05-27").endObject())).actionGet();
client.admin().indices().prepareRefresh().execute().actionGet(); client.admin().indices().prepareRefresh().execute().actionGet();
DecayFunctionBuilder gfb = new CustomDistanceScoreBuilder(); DecayFunctionBuilder gfb = new CustomDistanceScoreBuilder("num1", "2013-05-28", "+1d");
gfb.setParameters("num1", "2013-05-28", "+1d");
ActionFuture<SearchResponse> response = client.search(searchRequest().searchType(SearchType.QUERY_THEN_FETCH).source( ActionFuture<SearchResponse> response = client.search(searchRequest().searchType(SearchType.QUERY_THEN_FETCH).source(
searchSource().explain(false).query(functionScoreQuery(termQuery("test", "value")).add(gfb)))); searchSource().explain(false).query(functionScoreQuery(termQuery("test", "value")).add(gfb))));
@ -160,6 +159,10 @@ public class FunctionScorePluginTests extends AbstractNodesTests {
public class CustomDistanceScoreBuilder extends DecayFunctionBuilder { public class CustomDistanceScoreBuilder extends DecayFunctionBuilder {
public CustomDistanceScoreBuilder(String fieldName, Object reference, Object scale) {
super(fieldName, reference, scale);
}
@Override @Override
public String getName() { public String getName() {
return CustomDistanceScoreParser.NAMES[0]; return CustomDistanceScoreParser.NAMES[0];