Skip to content

Commit d5397b1

Browse files
authored
Score_functions
Development
2 parents ba8ac44 + 2bb1210 commit d5397b1

File tree

9 files changed

+202
-29
lines changed

9 files changed

+202
-29
lines changed

README.md

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ redisRescore.redisUrl : "YourHostIP"
130130
131131
# Plugin Builder
132132
133-
## 1- First of all pull the git rep into your machine
133+
## 1- First pull the git rep into your machine
134134
<br/>
135135
136136
## 2- Install gradle in your machine
@@ -158,17 +158,18 @@ Once again, in order for the build to work you need to have the **Docker** insta
158158

159159
```bash
160160
$ sudo apt install docker
161+
$ sudo apt install docker-compose
161162
$ sudo docker pull redis
162163
```
163164
<br/>
164165

165166
## 5- Build the Plugin
166-
Finally you are ready to build the Plugin.<br/>
167-
You can run the gradle compiler by using:
167+
Finally, you are ready to build the Plugin.<br/>
168+
You can run the gradle compiler by using in the project folder:
168169
```bash
169-
$ gradle build
170+
$ ./gradlew build
170171
```
171-
However if you are using the <strong>Intelij</strong> IDE, you can simply run the `gradle build` task.
172+
However, if you are using the <strong>Intelij</strong> IDE, you can simply run the `gradle build` task.
172173

173174
<br/>
174175

@@ -178,7 +179,19 @@ There will be 4 files in that dir, you want to take the `.zip` file.
178179

179180
<br/>
180181

181-
## 7- Install the Plugin
182-
See the **Plugin Installer** section
182+
## 7- Install the Plugin
183+
Now you can `cd` into to the `bin` folder in your **ElasticSearch** instalation and run :
184+
```bash
185+
$ ./elasticsearch-plugin install file://dirOfYourPlugin
186+
```
187+
<br/>
188+
189+
## 8- Change the Redis host
190+
By default, the plugin will think that your **Redis** server is running in the `localhost:6379` , that beeing said, you can change the `Host` but not the `Port`.
191+
The `Port` will always be `6379` because that's the default `Port` for the **Redis** server to run on.
192+
<br/>
193+
To change the `Host`, you first need to go to the `config` folder in your **ElasticSearch** dir.
194+
There open the `elasticsearch.yml` file, you want to add the following:
195+
183196

184197

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ ext {
3333

3434
repositories {
3535
jcenter()
36+
mavenCentral()
3637
}
3738

3839
configurations.all {

src/main/java/com/bigdataboutique/elasticsearch/plugin/RedisRescoreBuilder.java

Lines changed: 84 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.bigdataboutique.elasticsearch.plugin;
22

3+
import com.bigdataboutique.elasticsearch.plugin.exceptions.ScoreFunctionParseException;
34
import com.bigdataboutique.elasticsearch.plugin.exceptions.ScoreOperatorException;// Exceptions
45

56
import org.apache.logging.log4j.LogManager;
@@ -49,6 +50,8 @@ public class RedisRescoreBuilder extends RescorerBuilder<RedisRescoreBuilder> {
4950
private static final String SCORE_OPERATOR_DEFAULT = "ADD";
5051
private static final String BOOST_OPERATOR_DEFAULT = "ADD";
5152
private static final float BOOST_WEIGHT_DEFAULT = 1f;
53+
54+
5255
//------------------------------------------------------------------------------------------------------
5356

5457
protected static final Logger log = LogManager.getLogger(RedisRescoreBuilder.class);
@@ -60,6 +63,7 @@ public class RedisRescoreBuilder extends RescorerBuilder<RedisRescoreBuilder> {
6063
private final String boostOperator;
6164
private final Float boostWeight;
6265
private final Float[] scoreWeights;
66+
private final String[] scoreFunctions;
6367

6468

6569

@@ -106,7 +110,8 @@ public static Float[] GetFloatArray(@Nullable ArrayList<?> arr) { // Transforms
106110
// Constructors--------------------------------------------------------------------------------------------------
107111
public RedisRescoreBuilder(final String keyField, @Nullable String keyPrefix, @Nullable String scoreOperator,
108112
@Nullable String[] keyPrefixes, @Nullable String boostOperator,
109-
@Nullable Float boostWeight, @Nullable Float[] scoreWeights)
113+
@Nullable Float boostWeight, @Nullable Float[] scoreWeights,
114+
@Nullable String[] scoreFunctions)
110115
throws ScoreOperatorException {
111116

112117
this.keyField = keyField;
@@ -116,6 +121,7 @@ public RedisRescoreBuilder(final String keyField, @Nullable String keyPrefix, @N
116121
this.keyPrefixes = keyPrefixes;
117122
this.boostWeight = boostWeight == null ? BOOST_WEIGHT_DEFAULT : boostWeight;
118123
this.scoreWeights = scoreWeights;
124+
this.scoreFunctions = scoreFunctions;
119125

120126

121127
if (!checkOperator(this.scoreOperator))
@@ -136,6 +142,8 @@ public RedisRescoreBuilder(StreamInput in) throws IOException {
136142
boostOperator = BOOST_OPERATOR_DEFAULT;
137143
boostWeight = BOOST_WEIGHT_DEFAULT;
138144
scoreWeights = null;
145+
scoreFunctions = null;
146+
139147

140148
}
141149
//--------------------------------------------------------------------------------------------------
@@ -163,6 +171,8 @@ public RescorerBuilder<RedisRescoreBuilder> rewrite(QueryRewriteContext ctx) thr
163171
private static final ParseField BOOST_OPERATOR = new ParseField("boost_operator");
164172
private static final ParseField BOOST_WEIGHT = new ParseField("boost_weight");
165173
private static final ParseField SCORE_WEIGHTS = new ParseField("score_weights");
174+
private static final ParseField SCORE_FUNCTIONS = new ParseField("score_functions");
175+
166176

167177
@Override
168178
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
@@ -180,15 +190,20 @@ protected void doXContent(XContentBuilder builder, Params params) throws IOExcep
180190

181191
builder.field(SCORE_WEIGHTS.getPreferredName(), scoreWeights);
182192

193+
builder.field(SCORE_FUNCTIONS.getPreferredName(), scoreFunctions);
194+
195+
196+
183197
}
184198

199+
185200
private static final ConstructingObjectParser<RedisRescoreBuilder, Void> PARSER =
186201
new ConstructingObjectParser<RedisRescoreBuilder, Void>(NAME,
187202
args -> {
188203
try {
189204
return new RedisRescoreBuilder((String) args[0], (String) args[1], (String) args[2],
190205
GetStringArray((ArrayList<?>) args[3]) , (String) args[4],
191-
(Float) args[5], GetFloatArray((ArrayList<?>) args[6]));
206+
(Float) args[5], GetFloatArray((ArrayList<?>) args[6]), GetStringArray((ArrayList<?>) args[7]));
192207

193208
} catch (IOException e) {
194209
throw new IllegalArgumentException(e);
@@ -203,6 +218,7 @@ protected void doXContent(XContentBuilder builder, Params params) throws IOExcep
203218
PARSER.declareString(optionalConstructorArg(), BOOST_OPERATOR);
204219
PARSER.declareFloat(optionalConstructorArg(), BOOST_WEIGHT);
205220
PARSER.declareFloatArray(optionalConstructorArg(), SCORE_WEIGHTS);
221+
PARSER.declareStringArray(optionalConstructorArg(),SCORE_FUNCTIONS);
206222
}
207223
public static RedisRescoreBuilder fromXContent(XContentParser parser) {
208224
return PARSER.apply(parser, null);
@@ -213,7 +229,7 @@ public RescoreContext innerBuildContext(int windowSize, QueryShardContext contex
213229
IndexFieldData<?> keyField =
214230
this.keyField == null ? null : context.getForField(context.fieldMapper(this.keyField));
215231
return new RedisRescoreContext(windowSize, keyPrefix, keyField, scoreOperator,
216-
keyPrefixes, boostOperator, boostWeight, scoreWeights);
232+
keyPrefixes, boostOperator, boostWeight, scoreWeights, scoreFunctions);
217233
}
218234

219235
@Override
@@ -267,18 +283,25 @@ Float[] scoreWeights(){
267283
return scoreWeights;
268284
}
269285

286+
@Nullable
287+
String[] scoreFunctions(){
288+
return scoreFunctions;
289+
}
290+
291+
270292
private static class RedisRescoreContext extends RescoreContext {
271293
private final String keyPrefix;
272294
private final String[] keyPrefixes;
273295
private final String scoreOperator;
274296
private final String boostOperator;
275297
private final Float boostWeight;
276298
private final Float[] scoreWeights;
299+
private final String[] scoreFunctions;
277300
@Nullable
278301
private final IndexFieldData<?> keyField;
279302

280303
RedisRescoreContext(int windowSize, String keyPrefix, @Nullable IndexFieldData<?> keyField, String scoreOperator,
281-
String[] keyPrefixes, String boostOperator, Float boostWeight, Float[] scoreWeights) {
304+
String[] keyPrefixes, String boostOperator, Float boostWeight, Float[] scoreWeights, String[] scoreFunctions) {
282305
super(windowSize, RedisRescorer.INSTANCE);
283306
this.keyPrefix = keyPrefix;
284307
this.keyField = keyField;
@@ -287,6 +310,7 @@ private static class RedisRescoreContext extends RescoreContext {
287310
this.boostOperator = boostOperator;
288311
this.boostWeight = boostWeight;
289312
this.scoreWeights = scoreWeights;
313+
this.scoreFunctions = scoreFunctions;
290314

291315
}
292316
}
@@ -382,21 +406,25 @@ public TopDocs rescore(TopDocs topDocs, IndexSearcher searcher, RescoreContext r
382406
float scoreWeight = getScoreWeight(context.scoreWeights, j);
383407

384408
if (redisScore == 0)
385-
redisScore = getScoreFactor(term, prefix, scoreWeight);
409+
redisScore = getRescore(term, prefix, scoreWeight, j, context.scoreFunctions);
386410

387411
else {
388412
switch (context.scoreOperator) {
389413
case "ADD":
390-
redisScore += getScoreFactor(term, prefix, scoreWeight);
414+
redisScore += getRescore(term, prefix, scoreWeight,
415+
j, context.scoreFunctions);
391416
break;
392417
case "MULTIPLY":
393-
redisScore *= getScoreFactor(term, prefix, scoreWeight);
418+
redisScore *= getRescore(term, prefix, scoreWeight,
419+
j, context.scoreFunctions);
394420
break;
395421
case "SUBTRACT":
396-
redisScore -= getScoreFactor(term, prefix, scoreWeight);
422+
redisScore -= getRescore(term, prefix, scoreWeight,
423+
j, context.scoreFunctions);
397424
break;
398425
case "SET":
399-
redisScore = getScoreFactor(term, prefix, scoreWeight);
426+
redisScore = getRescore(term, prefix, scoreWeight,
427+
j, context.scoreFunctions);
400428
break;
401429
}
402430
}
@@ -426,25 +454,25 @@ else if (numericDocValues != null) {
426454
float scoreWeight = getScoreWeight(context.scoreWeights, j);
427455

428456
if (redisScore == 0)
429-
redisScore = getScoreFactor(String.valueOf(numericDocValues.nextValue()),
430-
prefix, scoreWeight);
457+
redisScore = getRescore(String.valueOf(numericDocValues.nextValue()),
458+
prefix, scoreWeight, j, context.scoreFunctions);
431459
else {
432460
switch (context.scoreOperator) {
433461
case "ADD":
434-
redisScore += getScoreFactor(String.valueOf(numericDocValues.nextValue()),
435-
prefix, scoreWeight);
462+
redisScore += getRescore(String.valueOf(numericDocValues.nextValue()),
463+
prefix, scoreWeight, j, context.scoreFunctions);
436464
break;
437465
case "MULTIPLY":
438-
redisScore *= getScoreFactor(String.valueOf(numericDocValues.nextValue()),
439-
prefix, scoreWeight);
466+
redisScore *= getRescore(String.valueOf(numericDocValues.nextValue()),
467+
prefix, scoreWeight, j, context.scoreFunctions);
440468
break;
441469
case "SUBTRACT":
442-
redisScore -= getScoreFactor(String.valueOf(numericDocValues.nextValue()),
443-
prefix, scoreWeight);
470+
redisScore -= getRescore(String.valueOf(numericDocValues.nextValue()),
471+
prefix, scoreWeight, j, context.scoreFunctions);
444472
break;
445473
case "SET":
446-
redisScore = getScoreFactor(String.valueOf(numericDocValues.nextValue()),
447-
prefix, scoreWeight);
474+
redisScore = getRescore(String.valueOf(numericDocValues.nextValue()),
475+
prefix, scoreWeight, j, context.scoreFunctions);
448476
break;
449477
}
450478
}
@@ -490,6 +518,41 @@ else if (numericDocValues != null) {
490518
});
491519
return topDocs;
492520
}
521+
522+
private static float getRescore(final String key, @Nullable final String keyPrefix, @Nullable float scoreWeight,
523+
@Nullable int keyPrefixesIndex, @Nullable String[] scoreFunctions)
524+
throws ScoreFunctionParseException {
525+
526+
if (scoreFunctions == null || scoreFunctions.length == 0)
527+
return getScoreFactor(key, keyPrefix, scoreWeight);
528+
//add exception here
529+
float scoreFactor = getScoreFactor(key, keyPrefix,1);
530+
Float res = null;
531+
532+
if( keyPrefixesIndex >= scoreFunctions.length || Objects.equals(scoreFunctions[keyPrefixesIndex], "null")){
533+
return scoreFactor * scoreWeight;
534+
}
535+
536+
try {
537+
String[] parsed = ScoreFunctionParser.getScoreFunctionParser().parse(scoreFunctions[keyPrefixesIndex],
538+
String.valueOf(scoreFactor));
539+
540+
541+
//--------------------------------------------Functions---------------------------------------------------
542+
switch (parsed[0]) {
543+
case "pow":
544+
res = ScoreFunctionsObj.get().pow(Float.parseFloat(parsed[1]), Float.parseFloat(parsed[2]));
545+
break;
546+
}
547+
//--------------------------------------------------------------------------------------------------------
548+
} catch(Exception e){
549+
throw new ScoreFunctionParseException(scoreFunctions[keyPrefixesIndex]);
550+
}
551+
552+
return res == null ? scoreFactor * scoreWeight : res * scoreWeight ;
553+
}
554+
555+
493556
//ScoreWeight Default Value must be 1
494557
private static float getScoreFactor(final String key, @Nullable final String keyPrefix,float scoreWeight) {
495558
assert key != null;
@@ -502,8 +565,9 @@ private static float getScoreFactor(final String key, @Nullable final String key
502565
return 1.0f;
503566
}
504567

505-
try {
568+
try { // Here
506569
return Float.parseFloat(factor) * scoreWeight;
570+
507571
} catch (NumberFormatException ignored_e) {
508572
log.warn("Redis rescore factor NumberFormatException for key " + fullKey);
509573
return 1.0f;
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.bigdataboutique.elasticsearch.plugin;
2+
import java.util.ArrayList;
3+
import java.util.List;
4+
5+
public class ScoreFunctionParser {
6+
private static ScoreFunctionParser _scoreFunctionParser;
7+
private ScoreFunctionParser(){}
8+
9+
public static ScoreFunctionParser getScoreFunctionParser(){
10+
if(_scoreFunctionParser == null)
11+
_scoreFunctionParser = new ScoreFunctionParser();
12+
return _scoreFunctionParser;
13+
}
14+
15+
public String[] parse(String toParse, String replacer){
16+
List<String> res = new ArrayList<>();
17+
String function;
18+
int i = 0;
19+
StringBuilder builder = new StringBuilder();
20+
21+
while (toParse.charAt(i) != '(') { // GET THE FUNCTION
22+
builder.append(toParse.charAt(i));
23+
i++;
24+
}
25+
res.add(builder.toString());
26+
builder.setLength(0);
27+
i++;
28+
while (i < toParse.length()){ // params
29+
char current = toParse.charAt(i);
30+
if (current == ',' || current == ')'){
31+
res.add(builder.toString());
32+
builder.setLength(0);
33+
}
34+
else if (current == '_'){
35+
res.add(replacer);
36+
builder.setLength(0);
37+
i++;
38+
}
39+
else
40+
builder.append(current);
41+
i++;
42+
}
43+
return res.toArray(new String[0]);
44+
}
45+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.bigdataboutique.elasticsearch.plugin;
2+
//import java.lang.Math;
3+
4+
public class ScoreFunctionsObj {
5+
private static ScoreFunctionsObj _scoreFunctions;
6+
private ScoreFunctionsObj(){}
7+
8+
public static ScoreFunctionsObj get(){
9+
if (_scoreFunctions == null )
10+
_scoreFunctions = new ScoreFunctionsObj();
11+
return _scoreFunctions;
12+
}
13+
14+
//----------------------Functions-------------------------------------
15+
public float pow(float base, float exponent){
16+
return (float) Math.pow(base,exponent);
17+
}
18+
//-------------------------------------------------------------
19+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.bigdataboutique.elasticsearch.plugin.exceptions;
2+
import java.io.IOException;
3+
4+
public class ScoreFunctionParseException extends IOException{
5+
public ScoreFunctionParseException(String func){
6+
super("Bad function body: "+ func);
7+
}
8+
}

0 commit comments

Comments
 (0)