FunctionScore: RandomScoreFunction now accepts long, as well a strings.

closes #8267
closes #8311
This commit is contained in:
Ryan Ernst 2014-10-31 09:03:41 -07:00
parent f1f50ac423
commit 8aff3b6273
4 changed files with 71 additions and 11 deletions

View File

@ -80,6 +80,14 @@ public class ScoreFunctionBuilders {
public static RandomScoreFunctionBuilder randomFunction(int seed) {
return (new RandomScoreFunctionBuilder()).seed(seed);
}
public static RandomScoreFunctionBuilder randomFunction(long seed) {
return (new RandomScoreFunctionBuilder()).seed(seed);
}
public static RandomScoreFunctionBuilder randomFunction(String seed) {
return (new RandomScoreFunctionBuilder()).seed(seed);
}
public static WeightBuilder weightFactorFunction(float weight) {
return (WeightBuilder)(new WeightBuilder().setWeight(weight));

View File

@ -28,7 +28,7 @@ import java.io.IOException;
*/
public class RandomScoreFunctionBuilder extends ScoreFunctionBuilder {
private Integer seed = null;
private Object seed = null;
public RandomScoreFunctionBuilder() {
}
@ -49,11 +49,31 @@ public class RandomScoreFunctionBuilder extends ScoreFunctionBuilder {
return this;
}
/**
* seed variant taking a long value.
* @see {@link #seed(int)}
*/
public RandomScoreFunctionBuilder seed(long seed) {
this.seed = seed;
return this;
}
/**
* seed variant taking a String value.
* @see {@link #seed(int)}
*/
public RandomScoreFunctionBuilder seed(String seed) {
this.seed = seed;
return this;
}
@Override
public void doXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(getName());
if (seed != null) {
builder.field("seed", seed.intValue());
if (seed instanceof Number) {
builder.field("seed", ((Number)seed).longValue());
} else if (seed != null) {
builder.field("seed", seed.toString());
}
builder.endObject();
}

View File

@ -20,6 +20,7 @@
package org.elasticsearch.index.query.functionscore.random;
import com.google.common.primitives.Longs;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.lucene.search.function.RandomScoreFunction;
import org.elasticsearch.common.lucene.search.function.ScoreFunction;
@ -59,7 +60,19 @@ public class RandomScoreFunctionParser implements ScoreFunctionParser {
currentFieldName = parser.currentName();
} else if (token.isValue()) {
if ("seed".equals(currentFieldName)) {
seed = parser.intValue();
if (token == XContentParser.Token.VALUE_NUMBER) {
if (parser.numberType() == XContentParser.NumberType.INT) {
seed = parser.intValue();
} else if (parser.numberType() == XContentParser.NumberType.LONG) {
seed = Longs.hashCode(parser.longValue());
} else {
throw new QueryParsingException(parseContext.index(), "random_score seed must be an int, long or string, not '" + token.toString() + "'");
}
} else if (token == XContentParser.Token.VALUE_STRING) {
seed = parser.text().hashCode();
} else {
throw new QueryParsingException(parseContext.index(), "random_score seed must be an int/long or string, not '" + token.toString() + "'");
}
} else {
throw new QueryParsingException(parseContext.index(), NAMES[0] + " query does not support [" + currentFieldName + "]");
}
@ -73,7 +86,7 @@ public class RandomScoreFunctionParser implements ScoreFunctionParser {
}
if (seed == -1) {
seed = (int)parseContext.nowInMillis();
seed = Longs.hashCode(parseContext.nowInMillis());
}
final ShardId shardId = SearchContext.current().indexShard().shardId();
final int salt = (shardId.index().name().hashCode() << 10) | shardId.id();

View File

@ -25,7 +25,6 @@ import org.elasticsearch.search.SearchHit;
import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.hamcrest.CoreMatchers;
import org.junit.Ignore;
import org.junit.Test;
import java.util.Arrays;
import java.util.Comparator;
@ -41,7 +40,6 @@ import static org.hamcrest.Matchers.*;
public class RandomScoreFunctionTests extends ElasticsearchIntegrationTest {
@Test
public void testConsistentHitsWithSameSeed() throws Exception {
createIndex("test");
ensureGreen(); // make sure we are done otherwise preference could change?
@ -103,7 +101,6 @@ public class RandomScoreFunctionTests extends ElasticsearchIntegrationTest {
}
}
@Test
public void testScoreAccessWithinScript() throws Exception {
assertAcked(prepareCreate("test")
.addMapping("type", "body", "type=string", "index", "type=" + randomFrom(new String[]{"short", "float", "long", "integer", "double"})));
@ -170,7 +167,6 @@ public class RandomScoreFunctionTests extends ElasticsearchIntegrationTest {
assertThat(firstHit.getScore(), greaterThan(1f));
}
@Test
public void testSeedReportedInExplain() throws Exception {
createIndex("test");
ensureGreen();
@ -201,7 +197,6 @@ public class RandomScoreFunctionTests extends ElasticsearchIntegrationTest {
assertEquals(0, resp.getHits().totalHits());
}
@Test
public void testScoreRange() throws Exception {
// all random scores should be in range [0.0, 1.0]
createIndex("test");
@ -227,8 +222,32 @@ public class RandomScoreFunctionTests extends ElasticsearchIntegrationTest {
}
}
}
public void testSeeds() throws Exception {
createIndex("test");
ensureGreen();
final int docCount = randomIntBetween(100, 200);
for (int i = 0; i < docCount; i++) {
index("test", "type", "" + i, jsonBuilder().startObject().endObject());
}
flushAndRefresh();
assertNoFailures(client().prepareSearch()
.setSize(docCount) // get all docs otherwise we are prone to tie-breaking
.setQuery(functionScoreQuery(matchAllQuery(), randomFunction(randomInt())))
.execute().actionGet());
assertNoFailures(client().prepareSearch()
.setSize(docCount) // get all docs otherwise we are prone to tie-breaking
.setQuery(functionScoreQuery(matchAllQuery(), randomFunction(randomLong())))
.execute().actionGet());
assertNoFailures(client().prepareSearch()
.setSize(docCount) // get all docs otherwise we are prone to tie-breaking
.setQuery(functionScoreQuery(matchAllQuery(), randomFunction(randomRealisticUnicodeOfLengthBetween(10, 20))))
.execute().actionGet());
}
@Test
@Ignore
public void checkDistribution() throws Exception {
int count = 10000;