diff --git a/src/main/java/org/elasticsearch/index/query/functionscore/DecayFunctionBuilder.java b/src/main/java/org/elasticsearch/index/query/functionscore/DecayFunctionBuilder.java index 2c30fb0bdc5..98e67238513 100644 --- a/src/main/java/org/elasticsearch/index/query/functionscore/DecayFunctionBuilder.java +++ b/src/main/java/org/elasticsearch/index/query/functionscore/DecayFunctionBuilder.java @@ -19,7 +19,6 @@ package org.elasticsearch.index.query.functionscore; - import org.elasticsearch.ElasticSearchIllegalStateException; 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 SCALE = "scale"; 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) { - if(this.fieldName != null ) { - throw new ElasticSearchIllegalStateException("Can not set parameters of decay function more than once."); - } + private String fieldName; + private Object reference; + private Object scale; + private double scaleWeight = -1; + + public DecayFunctionBuilder(String fieldName, Object reference, Object scale) { this.fieldName = fieldName; this.reference = reference; 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; + return this; } - - public void setParameters(String fieldName, String reference, String scale) { - setParameters(fieldName, reference, scale, SCALE_DEFAULT); - } - + @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(getName()); - builder.startObject(fieldName); - builder.field(REFERNECE, reference); - builder.field(SCALE, scale); + builder.startObject(fieldName); + builder.field(REFERNECE, reference); + builder.field(SCALE, scale); + if (scaleWeight > 0) { builder.field(SCALE_WEIGHT, scaleWeight); - builder.endObject(); + } + builder.endObject(); builder.endObject(); 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); - } } \ No newline at end of file diff --git a/src/main/java/org/elasticsearch/index/query/functionscore/DecayFunctionParser.java b/src/main/java/org/elasticsearch/index/query/functionscore/DecayFunctionParser.java index 97725dd8a1f..686c6402573 100644 --- a/src/main/java/org/elasticsearch/index/query/functionscore/DecayFunctionParser.java +++ b/src/main/java/org/elasticsearch/index/query/functionscore/DecayFunctionParser.java @@ -84,12 +84,7 @@ import java.io.IOException; * See {@link GaussDecayFunctionBuilder} and {@link GaussDecayFunctionParser} * for an example. The parser furthermore needs to be registered in the * {@link org.elasticsearch.index.query.functionscore.FunctionScoreModule - * FunctionScoreModule}. See - * {@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. + * FunctionScoreModule}. * * **/ @@ -165,28 +160,30 @@ public abstract class DecayFunctionParser implements ScoreFunctionParser { NumberFieldMapper mapper) throws IOException { XContentParser.Token token; String parameterName = null; - String scaleString = null; - String referenceString = null; + double scale = 0; + double reference = 0; double scaleWeight = 0.5; + boolean scaleFound = false; + boolean refFound = false; while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { if (token == XContentParser.Token.FIELD_NAME) { parameterName = parser.currentName(); } else if (parameterName.equals(DecayFunctionBuilder.SCALE)) { - scaleString = parser.text(); + scale = parser.doubleValue(); + scaleFound = true; } else if (parameterName.equals(DecayFunctionBuilder.SCALE_WEIGHT)) { scaleWeight = parser.doubleValue(); } else if (parameterName.equals(DecayFunctionBuilder.REFERNECE)) { - referenceString = parser.text(); + reference = parser.doubleValue(); + refFound = true; } else { throw new ElasticSearchParseException("Parameter " + parameterName + " not supported!"); } } - if (scaleString == null || referenceString == null) { + if (!scaleFound || !refFound) { throw new ElasticSearchParseException("Both " + DecayFunctionBuilder.SCALE + "and " + DecayFunctionBuilder.REFERNECE + " must be set for numeric fields."); } - double reference = mapper.value(referenceString).doubleValue(); - double scale = mapper.value(scaleString).doubleValue(); IndexNumericFieldData numericFieldData = parseContext.fieldData().getForField(mapper); return new NumericFieldDataScoreFunction(reference, scale, scaleWeight, getDecayFunction(), numericFieldData); } @@ -375,7 +372,7 @@ public abstract class DecayFunctionParser implements ScoreFunctionParser { @Override public Explanation explainScore(int docId, Explanation subQueryExpl) { ComplexExplanation ce = new ComplexExplanation(); - ce.setValue((float)score(docId, subQueryExpl.getValue())); + ce.setValue((float) score(docId, subQueryExpl.getValue())); ce.setMatch(true); ce.setDescription("subQueryScore * Function for field " + getFieldName() + ":"); ce.addDetail(func.explainFunction(getDistanceString(docId), distance(docId), scale)); @@ -385,7 +382,7 @@ public abstract class DecayFunctionParser implements ScoreFunctionParser { @Override public Explanation explainFactor(int docId) { ComplexExplanation ce = new ComplexExplanation(); - ce.setValue((float)factor(docId)); + ce.setValue((float) factor(docId)); ce.setMatch(true); ce.setDescription("subQueryScore * Function for field " + getFieldName() + ":"); ce.addDetail(func.explainFunction(getDistanceString(docId), distance(docId), scale)); diff --git a/src/main/java/org/elasticsearch/index/query/functionscore/exp/ExponentialDecayFunctionBuilder.java b/src/main/java/org/elasticsearch/index/query/functionscore/exp/ExponentialDecayFunctionBuilder.java index a013cecec6e..fe43514877f 100644 --- a/src/main/java/org/elasticsearch/index/query/functionscore/exp/ExponentialDecayFunctionBuilder.java +++ b/src/main/java/org/elasticsearch/index/query/functionscore/exp/ExponentialDecayFunctionBuilder.java @@ -24,6 +24,10 @@ import org.elasticsearch.index.query.functionscore.DecayFunctionBuilder; public class ExponentialDecayFunctionBuilder extends DecayFunctionBuilder { + public ExponentialDecayFunctionBuilder(String fieldName, Object reference, Object scale) { + super(fieldName, reference, scale); + } + @Override public String getName() { return ExponentialDecayFunctionParser.NAMES[0]; diff --git a/src/main/java/org/elasticsearch/index/query/functionscore/gauss/GaussDecayFunctionBuilder.java b/src/main/java/org/elasticsearch/index/query/functionscore/gauss/GaussDecayFunctionBuilder.java index a6ddb706aa7..da51b2f048f 100644 --- a/src/main/java/org/elasticsearch/index/query/functionscore/gauss/GaussDecayFunctionBuilder.java +++ b/src/main/java/org/elasticsearch/index/query/functionscore/gauss/GaussDecayFunctionBuilder.java @@ -24,6 +24,10 @@ import org.elasticsearch.index.query.functionscore.DecayFunctionBuilder; public class GaussDecayFunctionBuilder extends DecayFunctionBuilder { + public GaussDecayFunctionBuilder(String fieldName, Object reference, Object scale) { + super(fieldName, reference, scale); + } + @Override public String getName() { return GaussDecayFunctionParser.NAMES[0]; diff --git a/src/main/java/org/elasticsearch/index/query/functionscore/lin/LinearDecayFunctionBuilder.java b/src/main/java/org/elasticsearch/index/query/functionscore/lin/LinearDecayFunctionBuilder.java index 1c02d9a4e6e..e5e71341e8c 100644 --- a/src/main/java/org/elasticsearch/index/query/functionscore/lin/LinearDecayFunctionBuilder.java +++ b/src/main/java/org/elasticsearch/index/query/functionscore/lin/LinearDecayFunctionBuilder.java @@ -23,6 +23,10 @@ import org.elasticsearch.index.query.functionscore.DecayFunctionBuilder; public class LinearDecayFunctionBuilder extends DecayFunctionBuilder { + public LinearDecayFunctionBuilder(String fieldName, Object reference, Object scale) { + super(fieldName, reference, scale); + } + @Override public String getName() { return LinearDecayFunctionParser.NAMES[0]; diff --git a/src/test/java/org/elasticsearch/test/integration/search/functionscore/DecayFunctionScoreTests.java b/src/test/java/org/elasticsearch/test/integration/search/functionscore/DecayFunctionScoreTests.java index 93e1d9217f3..d2bc201c244 100644 --- a/src/test/java/org/elasticsearch/test/integration/search/functionscore/DecayFunctionScoreTests.java +++ b/src/test/java/org/elasticsearch/test/integration/search/functionscore/DecayFunctionScoreTests.java @@ -19,6 +19,7 @@ package org.elasticsearch.test.integration.search.functionscore; +import org.elasticsearch.ElasticSearchIllegalStateException; import org.elasticsearch.action.ActionFuture; import org.elasticsearch.action.index.IndexRequestBuilder; import org.elasticsearch.action.search.SearchPhaseExecutionException; @@ -86,8 +87,10 @@ public class DecayFunctionScoreTests extends AbstractSharedClusterTest { refresh(); // Test Gauss - DecayFunctionBuilder fb = new GaussDecayFunctionBuilder(); - fb.addGeoParams("loc", 11, 20, "1000km"); + List lonlat = new ArrayList(); + lonlat.add(new Float(20)); + lonlat.add(new Float(11)); + DecayFunctionBuilder fb = new GaussDecayFunctionBuilder("loc", lonlat, "1000km"); ActionFuture response = client().search( 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(1).getId(), equalTo("2")); // Test Exp - fb = new ExponentialDecayFunctionBuilder(); - fb.addGeoParams("loc", 11, 20, "1000km"); + fb = new ExponentialDecayFunctionBuilder("loc", lonlat, "1000km"); response = client().search( 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(1).getId(), equalTo("2")); // Test Lin - fb = new LinearDecayFunctionBuilder(); - fb.addGeoParams("loc", 11, 20, "1000km"); + fb = new LinearDecayFunctionBuilder("loc", lonlat, "1000km"); response = client().search( 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(); refresh(); - DecayFunctionBuilder gfb = new GaussDecayFunctionBuilder(); - gfb.setParameters("num1", "2013-05-28", "-1d"); + DecayFunctionBuilder gfb = new GaussDecayFunctionBuilder("num1", "2013-05-28", "-1d"); ActionFuture response = client().search( 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 { - createIndexMapped("test", "type1", "test", "string", "num1", "date"); - 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 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")); + DecayFunctionBuilder gfb = new GaussDecayFunctionBuilder("num1", "2013-05-28", "1d").setScaleWeight(100); } @@ -231,10 +209,8 @@ public class DecayFunctionScoreTests extends AbstractSharedClusterTest { refresh(); - DecayFunctionBuilder gfb1 = new LinearDecayFunctionBuilder(); - gfb1.setParameters("num1", "2013-05-28", "+3d"); - DecayFunctionBuilder gfb2 = new LinearDecayFunctionBuilder(); - gfb2.setParameters("num2", "0.0", "1"); + DecayFunctionBuilder gfb1 = new LinearDecayFunctionBuilder("num1", "2013-05-28", "+3d"); + DecayFunctionBuilder gfb2 = new LinearDecayFunctionBuilder("num2", "0.0", "1"); ActionFuture response = client().search( searchRequest().searchType(SearchType.QUERY_THEN_FETCH).source( @@ -282,13 +258,13 @@ public class DecayFunctionScoreTests extends AbstractSharedClusterTest { indexRandom("test", false, builders); refresh(); - - DecayFunctionBuilder gfb1 = new LinearDecayFunctionBuilder(); - DecayFunctionBuilder gfb2 = new LinearDecayFunctionBuilder(); - DecayFunctionBuilder gfb3 = new LinearDecayFunctionBuilder(); - gfb1.setParameters("date", "2013-05-30", "+15d"); - gfb2.addGeoParams("geo", 110, 100, "1000km"); - gfb3.setParameters("num", Integer.toString(numDocs), Integer.toString(numDocs / 2)); + + List lonlat = new ArrayList(); + lonlat.add(new Float(100)); + lonlat.add(new Float(110)); + DecayFunctionBuilder gfb1 = new LinearDecayFunctionBuilder("date", "2013-05-30", "+15d"); + DecayFunctionBuilder gfb2 = new LinearDecayFunctionBuilder("geo", lonlat, "1000km"); + DecayFunctionBuilder gfb3 = new LinearDecayFunctionBuilder("num", Integer.toString(numDocs), Integer.toString(numDocs / 2)); ActionFuture response = client().search( 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() .endObject())).actionGet(); refresh(); - DecayFunctionBuilder gfb2 = new LinearDecayFunctionBuilder(); - gfb2.addGeoParams("type1.geo", 110, 100, "1000km"); + List lonlat = new ArrayList(); + lonlat.add(new Float(100)); + lonlat.add(new Float(110)); + DecayFunctionBuilder gfb2 = new LinearDecayFunctionBuilder("type1.geo", lonlat, "1000km"); ActionFuture response = client().search( searchRequest().searchType(SearchType.QUERY_THEN_FETCH).source( searchSource() @@ -345,9 +323,8 @@ public class DecayFunctionScoreTests extends AbstractSharedClusterTest { indexRequest("test").type("type").source( jsonBuilder().startObject().field("test", "value").field("num", Integer.toString(1)).endObject())).actionGet(); refresh(); - DecayFunctionBuilder lfb = new LinearDecayFunctionBuilder(); - //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)); + 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 ActionFuture response = client() .search(searchRequest() .searchType(SearchType.QUERY_THEN_FETCH) diff --git a/src/test/java/org/elasticsearch/test/integration/search/functionscore/FunctionScorePluginTests.java b/src/test/java/org/elasticsearch/test/integration/search/functionscore/FunctionScorePluginTests.java index 51f9bb4018e..ab1011c4da8 100644 --- a/src/test/java/org/elasticsearch/test/integration/search/functionscore/FunctionScorePluginTests.java +++ b/src/test/java/org/elasticsearch/test/integration/search/functionscore/FunctionScorePluginTests.java @@ -83,8 +83,7 @@ public class FunctionScorePluginTests extends AbstractNodesTests { .source(jsonBuilder().startObject().field("test", "value").field("num1", "2013-05-27").endObject())).actionGet(); client.admin().indices().prepareRefresh().execute().actionGet(); - DecayFunctionBuilder gfb = new CustomDistanceScoreBuilder(); - gfb.setParameters("num1", "2013-05-28", "+1d"); + DecayFunctionBuilder gfb = new CustomDistanceScoreBuilder("num1", "2013-05-28", "+1d"); ActionFuture response = client.search(searchRequest().searchType(SearchType.QUERY_THEN_FETCH).source( 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 CustomDistanceScoreBuilder(String fieldName, Object reference, Object scale) { + super(fieldName, reference, scale); + } + @Override public String getName() { return CustomDistanceScoreParser.NAMES[0];