random_score function - Added the index name and shard id to the randomization, and improved the PRNG itself

Closes #3559
This commit is contained in:
uboness 2013-08-23 02:46:01 +02:00
parent 109e2944f2
commit 4b3a883111
3 changed files with 30 additions and 10 deletions

View File

@ -64,9 +64,10 @@ public class RandomScoreFunction implements ScoreFunction {
return exp; return exp;
} }
/** /**
* Algorithm based on {@link java.util.Random} except this one is not * Algorithm largely based on {@link java.util.Random} except this one is not
* thread safe * thread safe and it incorporates the doc id on next();
*/ */
static class PRNG { static class PRNG {
@ -84,15 +85,20 @@ public class RandomScoreFunction implements ScoreFunction {
public float random(int doc) { public float random(int doc) {
if (doc == 0) { if (doc == 0) {
doc = -17; doc = 0xCAFEBAB;
} }
return nextFloat() * (doc ^ 0xCAFEBAB);
long rand = doc;
rand |= rand << 32;
rand ^= rand;
return nextFloat(rand);
} }
public float nextFloat() { public float nextFloat(long rand) {
seed = (seed * multiplier + addend) & mask; seed = (seed * multiplier + addend) & mask;
int r = (int)(seed >>> 24); rand ^= seed;
return r / ((float)(1 << 24)); double result = rand / (double)(1L << 54);
return (float) result;
} }
} }

View File

@ -24,15 +24,14 @@ package org.elasticsearch.index.query.functionscore.random;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.lucene.search.function.RandomScoreFunction; import org.elasticsearch.common.lucene.search.function.RandomScoreFunction;
import org.elasticsearch.common.lucene.search.function.ScoreFunction; import org.elasticsearch.common.lucene.search.function.ScoreFunction;
import org.elasticsearch.common.lucene.search.function.ScriptScoreFunction;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.QueryParseContext; import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.index.query.QueryParsingException; import org.elasticsearch.index.query.QueryParsingException;
import org.elasticsearch.index.query.functionscore.ScoreFunctionParser; import org.elasticsearch.index.query.functionscore.ScoreFunctionParser;
import org.elasticsearch.script.SearchScript; import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.search.internal.SearchContext;
import java.io.IOException; import java.io.IOException;
import java.util.Map;
/** /**
* *
@ -73,6 +72,17 @@ public class RandomScoreFunctionParser implements ScoreFunctionParser {
seed = parseContext.nowInMillis(); seed = parseContext.nowInMillis();
} }
ShardId shardId = SearchContext.current().indexShard().shardId();
seed = salt(seed, shardId.index().name(), shardId.id());
return new RandomScoreFunction(seed); return new RandomScoreFunction(seed);
} }
public static long salt(long seed, String index, int shardId) {
long salt = index.hashCode();
salt = salt << 32;
salt |= shardId;
return salt^seed;
}
} }

View File

@ -107,15 +107,19 @@ public class RandomScoreFunctionTests extends AbstractSharedClusterTest {
int filled = 0; int filled = 0;
int maxRepeat = 0; int maxRepeat = 0;
int sumRepeat = 0;
for (int i = 0; i < matrix.length; i++) { for (int i = 0; i < matrix.length; i++) {
int value = matrix[i]; int value = matrix[i];
sumRepeat += value;
maxRepeat = Math.max(maxRepeat, value); maxRepeat = Math.max(maxRepeat, value);
if (value > 0) { if (value > 0) {
filled++; filled++;
} }
} }
System.out.println(); System.out.println();
System.out.println("max repeat: " + maxRepeat); System.out.println("max repeat: " + maxRepeat);
System.out.println("avg repeat: " + sumRepeat / (double)filled);
System.out.println("distribution: " + filled/(double)count); System.out.println("distribution: " + filled/(double)count);
int percentile50 = filled / 2; int percentile50 = filled / 2;