allow origin not set, defaults to "now" for date fields, exception for all other types

This commit is contained in:
Britta Weber 2013-09-16 14:48:25 +02:00
parent f12fa0c1c4
commit 4938f09d8d
4 changed files with 121 additions and 100 deletions

View File

@ -60,7 +60,9 @@ public abstract class DecayFunctionBuilder implements ScoreFunctionBuilder {
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(ORIGIN, origin); if (origin != null) {
builder.field(ORIGIN, origin);
}
builder.field(SCALE, scale); builder.field(SCALE, scale);
if (decay > 0) { if (decay > 0) {
builder.field(DECAY, decay); builder.field(DECAY, decay);

View File

@ -254,7 +254,7 @@ public abstract class DecayFunctionParser implements ScoreFunctionParser {
} }
if (scaleString == null) { if (scaleString == null) {
throw new ElasticSearchParseException(DecayFunctionBuilder.SCALE + "must be set for geo fields."); throw new ElasticSearchParseException(DecayFunctionBuilder.SCALE + "must be set for date fields.");
} }
TimeValue val = TimeValue.parseTimeValue(scaleString, TimeValue.timeValueHours(24)); TimeValue val = TimeValue.parseTimeValue(scaleString, TimeValue.timeValueHours(24));
double scale = val.getMillis(); double scale = val.getMillis();

View File

@ -29,45 +29,29 @@ import org.elasticsearch.index.query.functionscore.script.ScriptScoreFunctionBui
import java.util.Map; import java.util.Map;
public class ScoreFunctionBuilders { public class ScoreFunctionBuilders {
/**
* A query that match on all documents.
*/
public static ExponentialDecayFunctionBuilder exponentialDecayFunction(String fieldName, Object origin, Object scale) { public static ExponentialDecayFunctionBuilder exponentialDecayFunction(String fieldName, Object origin, Object scale) {
return new ExponentialDecayFunctionBuilder(fieldName, origin, scale); return new ExponentialDecayFunctionBuilder(fieldName, origin, scale);
} }
public static ExponentialDecayFunctionBuilder exponentialDecayFunction(String fieldName, Object origin, Object scale, double decay) { public static ExponentialDecayFunctionBuilder exponentialDecayFunction(String fieldName, Object scale) {
return (ExponentialDecayFunctionBuilder) (new ExponentialDecayFunctionBuilder(fieldName, origin, scale)).setDecay(decay); return new ExponentialDecayFunctionBuilder(fieldName, null, scale);
} }
public static ExponentialDecayFunctionBuilder exponentialDecayFunction(String fieldName, Object origin, Object scale, double decay,
double offset) {
return (ExponentialDecayFunctionBuilder) (new ExponentialDecayFunctionBuilder(fieldName, origin, scale)).setDecay(decay).setOffset(
offset);
}
public static GaussDecayFunctionBuilder gaussDecayFunction(String fieldName, Object origin, Object scale) { public static GaussDecayFunctionBuilder gaussDecayFunction(String fieldName, Object origin, Object scale) {
return new GaussDecayFunctionBuilder(fieldName, origin, scale); return new GaussDecayFunctionBuilder(fieldName, origin, scale);
} }
public static GaussDecayFunctionBuilder gaussDecayFunction(String fieldName, Object origin, Object scale, double decay) { public static GaussDecayFunctionBuilder gaussDecayFunction(String fieldName, Object scale) {
return (GaussDecayFunctionBuilder) (new GaussDecayFunctionBuilder(fieldName, origin, scale)).setDecay(decay); return new GaussDecayFunctionBuilder(fieldName, null, scale);
} }
public static GaussDecayFunctionBuilder gaussDecayFunction(String fieldName, Object origin, Object scale, double decay, double offset) {
return (GaussDecayFunctionBuilder) (new GaussDecayFunctionBuilder(fieldName, origin, scale)).setDecay(decay).setOffset(offset);
}
public static LinearDecayFunctionBuilder linearDecayFunction(String fieldName, Object origin, Object scale) { public static LinearDecayFunctionBuilder linearDecayFunction(String fieldName, Object origin, Object scale) {
return new LinearDecayFunctionBuilder(fieldName, origin, scale); return new LinearDecayFunctionBuilder(fieldName, origin, scale);
} }
public static LinearDecayFunctionBuilder linearDecayFunction(String fieldName, Object origin, Object scale, double decay) { public static LinearDecayFunctionBuilder linearDecayFunction(String fieldName, Object scale) {
return (LinearDecayFunctionBuilder) (new LinearDecayFunctionBuilder(fieldName, origin, scale)).setDecay(decay); return new LinearDecayFunctionBuilder(fieldName, null, scale);
}
public static LinearDecayFunctionBuilder linearDecayFunction(String fieldName, Object origin, Object scale, double decay, double offset) {
return (LinearDecayFunctionBuilder) (new LinearDecayFunctionBuilder(fieldName, origin, scale)).setDecay(decay).setOffset(offset);
} }
public static ScriptScoreFunctionBuilder scriptFunction(String script) { public static ScriptScoreFunctionBuilder scriptFunction(String script) {

View File

@ -29,10 +29,12 @@ import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.common.geo.GeoPoint; import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.lucene.search.function.CombineFunction; import org.elasticsearch.common.lucene.search.function.CombineFunction;
import org.elasticsearch.index.query.MatchAllFilterBuilder; import org.elasticsearch.index.query.MatchAllFilterBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.DecayFunctionBuilder; import org.elasticsearch.index.query.functionscore.DecayFunctionBuilder;
import org.elasticsearch.index.query.functionscore.gauss.GaussDecayFunctionBuilder; import org.elasticsearch.index.query.functionscore.gauss.GaussDecayFunctionBuilder;
import org.elasticsearch.search.SearchHits; import org.elasticsearch.search.SearchHits;
import org.elasticsearch.test.hamcrest.ElasticsearchAssertions; import org.elasticsearch.test.hamcrest.ElasticsearchAssertions;
import org.joda.time.DateTime;
import org.junit.Test; import org.junit.Test;
import java.util.ArrayList; import java.util.ArrayList;
@ -52,11 +54,10 @@ public class DecayFunctionScoreTests extends AbstractSharedClusterTest {
@Test @Test
public void testDistanceScoreGeoLinGaussExp() throws Exception { public void testDistanceScoreGeoLinGaussExp() throws Exception {
assertAcked(prepareCreate("test").addMapping("type1", assertAcked(prepareCreate("test").addMapping(
jsonBuilder().startObject().startObject("type1").startObject("properties") "type1",
.startObject("test").field("type", "string").endObject() jsonBuilder().startObject().startObject("type1").startObject("properties").startObject("test").field("type", "string")
.startObject("loc").field("type", "geo_point").endObject() .endObject().startObject("loc").field("type", "geo_point").endObject().endObject().endObject().endObject()));
.endObject().endObject().endObject()));
ensureYellow(); ensureYellow();
List<IndexRequestBuilder> indexBuilders = new ArrayList<IndexRequestBuilder>(); List<IndexRequestBuilder> indexBuilders = new ArrayList<IndexRequestBuilder>();
@ -154,11 +155,10 @@ public class DecayFunctionScoreTests extends AbstractSharedClusterTest {
@Test @Test
public void testDistanceScoreGeoLinGaussExpWithOffset() throws Exception { public void testDistanceScoreGeoLinGaussExpWithOffset() throws Exception {
assertAcked(prepareCreate("test").addMapping("type1", assertAcked(prepareCreate("test").addMapping(
jsonBuilder().startObject().startObject("type1").startObject("properties") "type1",
.startObject("test").field("type", "string").endObject() jsonBuilder().startObject().startObject("type1").startObject("properties").startObject("test").field("type", "string")
.startObject("num").field("type", "double").endObject() .endObject().startObject("num").field("type", "double").endObject().endObject().endObject().endObject()));
.endObject().endObject().endObject()));
ensureYellow(); ensureYellow();
// add tw docs within offset // add tw docs within offset
@ -235,11 +235,10 @@ public class DecayFunctionScoreTests extends AbstractSharedClusterTest {
@Test @Test
public void testBoostModeSettingWorks() throws Exception { public void testBoostModeSettingWorks() throws Exception {
assertAcked(prepareCreate("test").addMapping("type1", assertAcked(prepareCreate("test").addMapping(
jsonBuilder().startObject().startObject("type1").startObject("properties") "type1",
.startObject("test").field("type", "string").endObject() jsonBuilder().startObject().startObject("type1").startObject("properties").startObject("test").field("type", "string")
.startObject("loc").field("type", "geo_point").endObject() .endObject().startObject("loc").field("type", "geo_point").endObject().endObject().endObject().endObject()));
.endObject().endObject().endObject()));
ensureYellow(); ensureYellow();
List<IndexRequestBuilder> indexBuilders = new ArrayList<IndexRequestBuilder>(); List<IndexRequestBuilder> indexBuilders = new ArrayList<IndexRequestBuilder>();
@ -294,11 +293,10 @@ public class DecayFunctionScoreTests extends AbstractSharedClusterTest {
@Test @Test
public void testParseGeoPoint() throws Exception { public void testParseGeoPoint() throws Exception {
assertAcked(prepareCreate("test").addMapping("type1", assertAcked(prepareCreate("test").addMapping(
jsonBuilder().startObject().startObject("type1").startObject("properties") "type1",
.startObject("test").field("type", "string").endObject() jsonBuilder().startObject().startObject("type1").startObject("properties").startObject("test").field("type", "string")
.startObject("loc").field("type", "geo_point").endObject() .endObject().startObject("loc").field("type", "geo_point").endObject().endObject().endObject().endObject()));
.endObject().endObject().endObject()));
ensureYellow(); ensureYellow();
List<IndexRequestBuilder> indexBuilders = new ArrayList<IndexRequestBuilder>(); List<IndexRequestBuilder> indexBuilders = new ArrayList<IndexRequestBuilder>();
@ -341,11 +339,10 @@ public class DecayFunctionScoreTests extends AbstractSharedClusterTest {
@Test @Test
public void testCombineModes() throws Exception { public void testCombineModes() throws Exception {
assertAcked(prepareCreate("test").addMapping("type1", assertAcked(prepareCreate("test").addMapping(
jsonBuilder().startObject().startObject("type1").startObject("properties") "type1",
.startObject("test").field("type", "string").endObject() jsonBuilder().startObject().startObject("type1").startObject("properties").startObject("test").field("type", "string")
.startObject("num").field("type", "double").endObject() .endObject().startObject("num").field("type", "double").endObject().endObject().endObject().endObject()));
.endObject().endObject().endObject()));
ensureYellow(); ensureYellow();
List<IndexRequestBuilder> indexBuilders = new ArrayList<IndexRequestBuilder>(); List<IndexRequestBuilder> indexBuilders = new ArrayList<IndexRequestBuilder>();
@ -434,11 +431,10 @@ public class DecayFunctionScoreTests extends AbstractSharedClusterTest {
@Test(expected = SearchPhaseExecutionException.class) @Test(expected = SearchPhaseExecutionException.class)
public void testExceptionThrownIfScaleLE0() throws Exception { public void testExceptionThrownIfScaleLE0() throws Exception {
assertAcked(prepareCreate("test").addMapping("type1", assertAcked(prepareCreate("test").addMapping(
jsonBuilder().startObject().startObject("type1").startObject("properties") "type1",
.startObject("test").field("type", "string").endObject() jsonBuilder().startObject().startObject("type1").startObject("properties").startObject("test").field("type", "string")
.startObject("num1").field("type", "date").endObject() .endObject().startObject("num1").field("type", "date").endObject().endObject().endObject().endObject()));
.endObject().endObject().endObject()));
ensureYellow(); ensureYellow();
client().index( client().index(
indexRequest("test").type("type1").id("1") indexRequest("test").type("type1").id("1")
@ -471,12 +467,11 @@ public class DecayFunctionScoreTests extends AbstractSharedClusterTest {
@Test @Test
public void testValueMissingLin() throws Exception { public void testValueMissingLin() throws Exception {
assertAcked(prepareCreate("test").addMapping("type1", assertAcked(prepareCreate("test").addMapping(
jsonBuilder().startObject().startObject("type1").startObject("properties") "type1",
.startObject("test").field("type", "string").endObject() jsonBuilder().startObject().startObject("type1").startObject("properties").startObject("test").field("type", "string")
.startObject("num1").field("type", "date").endObject() .endObject().startObject("num1").field("type", "date").endObject().startObject("num2").field("type", "double")
.startObject("num2").field("type", "double").endObject() .endObject().endObject().endObject().endObject()));
.endObject().endObject().endObject()));
ensureYellow(); ensureYellow();
client().index( client().index(
indexRequest("test") indexRequest("test")
@ -502,8 +497,7 @@ public class DecayFunctionScoreTests extends AbstractSharedClusterTest {
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().explain(false).query( searchSource().explain(false).query(
functionScoreQuery(termQuery("test", "value")) functionScoreQuery(termQuery("test", "value")).add(linearDecayFunction("num1", "2013-05-28", "+3d"))
.add(linearDecayFunction("num1", "2013-05-28", "+3d"))
.add(linearDecayFunction("num2", "0.0", "1")).scoreMode("multiply")))); .add(linearDecayFunction("num2", "0.0", "1")).scoreMode("multiply"))));
SearchResponse sr = response.actionGet(); SearchResponse sr = response.actionGet();
@ -519,15 +513,61 @@ public class DecayFunctionScoreTests extends AbstractSharedClusterTest {
} }
@Test
public void testDateWithoutOrigin() throws Exception {
DateTime dt = new DateTime();
assertAcked(prepareCreate("test").addMapping(
"type1",
jsonBuilder().startObject().startObject("type1").startObject("properties").startObject("test").field("type", "string")
.endObject().startObject("num1").field("type", "date").endObject().endObject().endObject().endObject()));
ensureYellow();
DateTime docDate = dt.minusDays(1);
String docDateString = docDate.getYear() + "-" + docDate.getMonthOfYear() + "-" + docDate.getDayOfMonth();
client().index(
indexRequest("test").type("type1").id("1")
.source(jsonBuilder().startObject().field("test", "value").field("num1", docDateString).endObject())).actionGet();
docDate = dt.minusDays(2);
docDateString = docDate.getYear() + "-" + docDate.getMonthOfYear() + "-" + docDate.getDayOfMonth();
client().index(
indexRequest("test").type("type1").id("2")
.source(jsonBuilder().startObject().field("test", "value").field("num1", docDateString).endObject())).actionGet();
docDate = dt.minusDays(3);
docDateString = docDate.getYear() + "-" + docDate.getMonthOfYear() + "-" + docDate.getDayOfMonth();
client().index(
indexRequest("test").type("type1").id("3")
.source(jsonBuilder().startObject().field("test", "value").field("num1", docDateString).endObject())).actionGet();
refresh();
ActionFuture<SearchResponse> response = client().search(
searchRequest().searchType(SearchType.QUERY_THEN_FETCH).source(
searchSource().explain(false).query(
functionScoreQuery(QueryBuilders.matchAllQuery()).add(linearDecayFunction("num1", "1000w"))
.add(gaussDecayFunction("num1", "1d")).add(exponentialDecayFunction("num1", "1000w"))
.scoreMode("multiply"))));
SearchResponse sr = response.actionGet();
ElasticsearchAssertions.assertNoFailures(sr);
SearchHits sh = sr.getHits();
assertThat(sh.hits().length, equalTo(3));
double[] scores = new double[4];
for (int i = 0; i < sh.hits().length; i++) {
scores[Integer.parseInt(sh.getAt(i).getId()) - 1] = sh.getAt(i).getScore();
}
assertThat(scores[1], lessThan(scores[0]));
assertThat(scores[2], lessThan(scores[1]));
}
@Test @Test
public void testManyDocsLin() throws Exception { public void testManyDocsLin() throws Exception {
assertAcked(prepareCreate("test").addMapping("type", assertAcked(prepareCreate("test").addMapping(
jsonBuilder().startObject().startObject("type").startObject("properties") "type",
.startObject("test").field("type", "string").endObject() jsonBuilder().startObject().startObject("type").startObject("properties").startObject("test").field("type", "string")
.startObject("date").field("type", "date").endObject() .endObject().startObject("date").field("type", "date").endObject().startObject("num").field("type", "double")
.startObject("num").field("type", "double").endObject() .endObject().startObject("geo").field("type", "geo_point").endObject().endObject().endObject().endObject()));
.startObject("geo").field("type", "geo_point").endObject()
.endObject().endObject().endObject()));
ensureYellow(); ensureYellow();
int numDocs = 200; int numDocs = 200;
List<IndexRequestBuilder> indexBuilders = new ArrayList<IndexRequestBuilder>(); List<IndexRequestBuilder> indexBuilders = new ArrayList<IndexRequestBuilder>();
@ -554,13 +594,11 @@ public class DecayFunctionScoreTests extends AbstractSharedClusterTest {
lonlat.add(new Float(110)); lonlat.add(new Float(110));
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().size(numDocs).query(
.size(numDocs) functionScoreQuery(termQuery("test", "value"))
.query(functionScoreQuery(termQuery("test", "value"))
.add(new MatchAllFilterBuilder(), linearDecayFunction("date", "2013-05-30", "+15d")) .add(new MatchAllFilterBuilder(), linearDecayFunction("date", "2013-05-30", "+15d"))
.add(new MatchAllFilterBuilder(), linearDecayFunction("geo", lonlat, "1000km")) .add(new MatchAllFilterBuilder(), linearDecayFunction("geo", lonlat, "1000km"))
.add(new MatchAllFilterBuilder(), .add(new MatchAllFilterBuilder(), linearDecayFunction("num", numDocs, numDocs / 2.0))
linearDecayFunction("num", numDocs, numDocs / 2.0))
.scoreMode("multiply").boostMode(CombineFunction.REPLACE.getName())))); .scoreMode("multiply").boostMode(CombineFunction.REPLACE.getName()))));
SearchResponse sr = response.actionGet(); SearchResponse sr = response.actionGet();
@ -580,11 +618,10 @@ public class DecayFunctionScoreTests extends AbstractSharedClusterTest {
@Test(expected = SearchPhaseExecutionException.class) @Test(expected = SearchPhaseExecutionException.class)
public void testParsingExceptionIfFieldDoesNotExist() throws Exception { public void testParsingExceptionIfFieldDoesNotExist() throws Exception {
assertAcked(prepareCreate("test").addMapping("type", assertAcked(prepareCreate("test").addMapping(
jsonBuilder().startObject().startObject("type").startObject("properties") "type",
.startObject("test").field("type", "string").endObject() jsonBuilder().startObject().startObject("type").startObject("properties").startObject("test").field("type", "string")
.startObject("geo").field("type", "geo_point").endObject() .endObject().startObject("geo").field("type", "geo_point").endObject().endObject().endObject().endObject()));
.endObject().endObject().endObject()));
ensureYellow(); ensureYellow();
int numDocs = 2; int numDocs = 2;
client().index( client().index(
@ -608,11 +645,10 @@ public class DecayFunctionScoreTests extends AbstractSharedClusterTest {
@Test(expected = SearchPhaseExecutionException.class) @Test(expected = SearchPhaseExecutionException.class)
public void testParsingExceptionIfFieldTypeDoesNotMatch() throws Exception { public void testParsingExceptionIfFieldTypeDoesNotMatch() throws Exception {
assertAcked(prepareCreate("test").addMapping("type", assertAcked(prepareCreate("test").addMapping(
jsonBuilder().startObject().startObject("type").startObject("properties") "type",
.startObject("test").field("type", "string").endObject() jsonBuilder().startObject().startObject("type").startObject("properties").startObject("test").field("type", "string")
.startObject("num").field("type", "string").endObject() .endObject().startObject("num").field("type", "string").endObject().endObject().endObject().endObject()));
.endObject().endObject().endObject()));
ensureYellow(); ensureYellow();
client().index( client().index(
indexRequest("test").type("type").source( indexRequest("test").type("type").source(
@ -626,26 +662,25 @@ public class DecayFunctionScoreTests extends AbstractSharedClusterTest {
linearDecayFunction("num", 1.0, 0.5)).scoreMode("multiply")))); linearDecayFunction("num", 1.0, 0.5)).scoreMode("multiply"))));
response.actionGet(); response.actionGet();
} }
@Test @Test
public void testNoQueryGiven() throws Exception { public void testNoQueryGiven() throws Exception {
assertAcked(prepareCreate("test").addMapping("type", assertAcked(prepareCreate("test").addMapping(
jsonBuilder().startObject().startObject("type").startObject("properties") "type",
.startObject("test").field("type", "string").endObject() jsonBuilder().startObject().startObject("type").startObject("properties").startObject("test").field("type", "string")
.startObject("num").field("type", "double").endObject() .endObject().startObject("num").field("type", "double").endObject().endObject().endObject().endObject()));
.endObject().endObject().endObject()));
ensureYellow(); ensureYellow();
client().index( client().index(
indexRequest("test").type("type").source( indexRequest("test").type("type").source(jsonBuilder().startObject().field("test", "value").field("num", 1.0).endObject()))
jsonBuilder().startObject().field("test", "value").field("num", 1.0).endObject())).actionGet(); .actionGet();
refresh(); refresh();
// 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
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().explain(true).query( searchSource().explain(true).query(
functionScoreQuery().add(new MatchAllFilterBuilder(), functionScoreQuery().add(new MatchAllFilterBuilder(), linearDecayFunction("num", 1, 0.5)).scoreMode(
linearDecayFunction("num", 1, 0.5)).scoreMode("multiply")))); "multiply"))));
response.actionGet(); response.actionGet();
} }
} }