├── .gitignore
├── LICENSE
├── pom.xml
├── readme.md
└── src
├── main
├── assemblies
│ └── plugin.xml
├── java
│ └── org
│ │ └── bkatwal
│ │ └── elasticsearch
│ │ └── plugin
│ │ ├── helper
│ │ ├── MinMaxNormalizer.java
│ │ ├── Normalizer.java
│ │ ├── NormalizerServiceLocator.java
│ │ └── ZScoreNormalizer.java
│ │ └── rescorer
│ │ ├── MinMaxSameScoreStrategy.java
│ │ ├── NormalizerFactorMathOp.java
│ │ ├── NormalizerRescorerBuilder.java
│ │ ├── NormalizerType.java
│ │ ├── ScoreNormalizerRescorer.java
│ │ └── ScoreNormalizerRescorerPlugin.java
└── resources
│ └── plugin-descriptor.properties
└── test
└── java
└── org
└── bkatwal
└── elasticsearch
└── plugin
└── helper
├── MinMaxNormalizerTest.java
└── ZScoreNormalizerTest.java
/.gitignore:
--------------------------------------------------------------------------------
1 | #
2 | # Project specific excludes
3 | #
4 |
5 | tomcat
6 |
7 | #
8 | # Default excludes
9 | #
10 |
11 | # Binaries
12 | *.7z
13 | *.dmg
14 | *.gz
15 | *.iso
16 | *.jar
17 | *.rar
18 | *.tar
19 | *.zip
20 | *.war
21 | *.ear
22 | *.sar
23 | *.class
24 |
25 | # Maven
26 | target/
27 |
28 | # IntelliJ project files
29 | *.iml
30 | *.iws
31 | *.ipr
32 | .idea/
33 |
34 | # eclipse project file
35 | .settings/
36 | .classpath
37 | .project
38 |
39 | # NetBeans specific
40 | nbproject/private/
41 | build/
42 | nbbuild/
43 | dist/
44 | nbdist/
45 | nbactions.xml
46 | nb-configuration.xml
47 |
48 |
49 | # OS
50 | .DS_Store
51 |
52 | # Misc
53 | *.swp
54 | release.properties
55 | pom.xml.releaseBackup
56 | pom.xml.tag
57 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) Bikas Katwal - bikas.katwal10@gmail.com
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 | 4.0.0
6 |
7 | org.bkatwal.elasticsearch.plugin
8 | elasticsearch-score-normalizer-rescorer
9 | 1.0-SNAPSHOT
10 |
11 | elasticsearch-score-normalizer-rescorer
12 |
13 |
14 | UTF-8
15 | 1.8
16 | 1.8
17 | 7.4.0
18 | 3.5.1
19 | ${basedir}/src/main/assemblies/plugin.xml
20 |
21 |
22 |
23 |
24 | org.elasticsearch
25 | elasticsearch
26 | ${elasticsearch.version}
27 | provided
28 |
29 |
30 |
31 | junit
32 | junit
33 | 4.12
34 | test
35 |
36 |
37 |
38 |
39 |
40 |
41 | org.apache.maven.plugins
42 | maven-compiler-plugin
43 | ${maven.compiler.plugin.version}
44 |
45 | ${maven.compiler.target}
46 | ${maven.compiler.target}
47 |
48 |
49 |
50 | org.apache.maven.plugins
51 | maven-assembly-plugin
52 |
53 | false
54 | ${project.build.directory}/releases/
55 |
56 | ${elasticsearch.assembly.descriptor}
57 |
58 |
59 |
60 |
61 | package
62 |
63 | attached
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Elasticsearch Score Normalizer
2 | Plugin to normalize score using Min Max or Z Score normalizer and updates normalized score by a
3 | given `factor` and `factor_mode`.
4 | This plugin is built on top of elasticsearch's rescorer feature and normalizes the top docs.
5 |
6 | If page `size` is 10 and `from` offset is 20. Then all 30 docs will be normalized.
7 |
8 | ### Common Attributes
9 | #### normalizer_type (Optional)
10 | Type of the normalizer. Accepts `z_score` or `min_max`, if nothing passed defaults to z_score.
11 |
12 | #### factor (Optional)
13 | A float value. If passed updates the normalized score using this factor and given operation
14 | (`factor_mode`)
15 | #### factor_mode (Optional)
16 | Tells how to combine normalized score and the `factor`. Accepted values are `sum`, `multiply`
17 | and `increase_by_percent`. `increase_by_percent` increases the score by given factor(values
18 | from 0 to 1)
19 |
20 |
21 | ### Min Max Normalizer
22 |
23 | #### Attributes
24 | `min_score` - minimum score value of the returned top docs. Default is 1.
25 |
26 | `max_score` - maximum score value of the returned top docs. Default is 5.
27 |
28 | `on_score_same` - Normalize strategy when all docs score are same. Accepted values are `avg`
29 | (average of max and min), `max`(maximum value), `min`(minimum value)
30 |
31 | Normalize scores between given `max_score` and `min_score`. If no `min_score` and `max_score` is
32 | passed, defaults to 1 and 5 respectively.
33 |
34 | Example:
35 | ```json
36 |
37 | {
38 | "query": {
39 | ... some query
40 | },
41 | "from" : 0,
42 | "size" : 50,
43 | "rescore" : {
44 | "score_normalizer" : {
45 | "normalizer_type" : "min_max",
46 | "min_score" : 1,
47 | "max_score" : 10
48 | }
49 | }
50 | }
51 | ```
52 |
53 | ### Z Score Normalizer
54 | Normalize scores using Z Score.
55 |
56 | Below example first normalizes the scores using z-score and then increase the score by 60 percent.
57 | Example:
58 | ```json
59 | {
60 | "query": {
61 | ... some query
62 | },
63 | "from" : 0,
64 | "size" : 50,
65 | "rescore" : {
66 | "score_normalizer" : {
67 | "normalizer_type" : "z_score",
68 | "min_score" : 1,
69 | "factor" : 0.6,
70 | "factor_mode" : "increase_by_percent"
71 | }
72 | }
73 | }
74 | ```
75 | ### Installation
76 | 0. Change the elasticsearch version in pom.xml with your Elasticsearch server version. You can safely change the version between 7.0 to 7.12 without any code changes.
77 | 1. Build using: `mvn clean install`
78 | 2. Install the zip file generated in folder:
79 | `/project/target/releases/elasticsearch-score-normalizer-rescorer-1.0-SNAPSHOT.zip`
80 |
81 | To install, go to ES bin folder and type command:
82 | ```shell
83 | ./elasticsearch-plugin install file:
84 | ```
85 |
86 | ### License
87 | The MIT License (MIT)
88 |
89 | Copyright (c) Bikas Katwal - bikas.katwal10@gmail.com
90 |
91 | Permission is hereby granted, free of charge, to any person obtaining a copy
92 | of this software and associated documentation files (the "Software"), to deal
93 | in the Software without restriction, including without limitation the rights
94 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
95 | copies of the Software, and to permit persons to whom the Software is
96 | furnished to do so, subject to the following conditions:
97 |
98 | The above copyright notice and this permission notice shall be included in all
99 | copies or substantial portions of the Software.
100 |
101 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
102 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
103 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
104 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
105 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
106 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
107 | SOFTWARE.
108 |
109 |
110 |
--------------------------------------------------------------------------------
/src/main/assemblies/plugin.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | plugin
4 |
5 | zip
6 |
7 | false
8 |
9 |
10 | target
11 | /
12 |
13 | *.jar
14 |
15 |
16 |
17 |
18 |
19 | ${project.basedir}/src/main/resources/plugin-descriptor.properties
20 | /
21 | true
22 |
23 |
24 |
25 |
26 | /
27 | false
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/main/java/org/bkatwal/elasticsearch/plugin/helper/MinMaxNormalizer.java:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) Bikas Katwal - bikas.katwal10@gmail.com
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | package org.bkatwal.elasticsearch.plugin.helper;
25 |
26 | import org.apache.lucene.search.TopDocs;
27 | import org.bkatwal.elasticsearch.plugin.rescorer.MinMaxSameScoreStrategy;
28 | import org.bkatwal.elasticsearch.plugin.rescorer.NormalizerFactorMathOp;
29 | import org.bkatwal.elasticsearch.plugin.rescorer.ScoreNormalizerRescorer;
30 |
31 | public class MinMaxNormalizer implements Normalizer {
32 |
33 | @Override
34 | public TopDocs normalize(
35 | TopDocs topDocs, ScoreNormalizerRescorer.ScoreNormalizerRescorerContext context) {
36 |
37 | if (context.getMinScore() >= context.getMaxScore()) {
38 | throw new IllegalArgumentException(
39 | "max_score can not be lesser than or equal to " + "min_score");
40 | }
41 | if (topDocs.scoreDocs.length == 0) {
42 | return topDocs;
43 | }
44 | if (topDocs.scoreDocs.length == 1) {
45 | topDocs.scoreDocs[0].score =
46 | getFinalScore(context.getFactorMode(), context.getFactor(), context.getMaxScore());
47 | return topDocs;
48 | }
49 |
50 | float oldMax = topDocs.scoreDocs[0].score;
51 | float oldMin = topDocs.scoreDocs[topDocs.scoreDocs.length - 1].score;
52 |
53 | if (Float.compare(oldMax, oldMin) == 0) {
54 | for (int i = 0; i < topDocs.scoreDocs.length; i++) {
55 | if (context.getOnScoresSame().equals(MinMaxSameScoreStrategy.avg.name())) {
56 | topDocs.scoreDocs[i].score = (context.getMaxScore() + context.getMinScore()) / 2;
57 | } else if (context.getOnScoresSame().equals(MinMaxSameScoreStrategy.min.name())) {
58 | topDocs.scoreDocs[i].score = context.getMinScore();
59 | } else if (context.getOnScoresSame().equals(MinMaxSameScoreStrategy.max.name())) {
60 | topDocs.scoreDocs[i].score = context.getMaxScore();
61 | } else {
62 | topDocs.scoreDocs[i].score = (context.getMaxScore() + context.getMinScore()) / 2;
63 | }
64 | }
65 | return topDocs;
66 | }
67 |
68 | for (int i = 0; i < topDocs.scoreDocs.length; i++) {
69 | float normalizedScore =
70 | calculate(
71 | topDocs.scoreDocs[i].score,
72 | oldMin,
73 | oldMax,
74 | context.getMaxScore(),
75 | context.getMinScore());
76 |
77 | topDocs.scoreDocs[i].score =
78 | getFinalScore(context.getFactorMode(), context.getFactor(), normalizedScore);
79 | }
80 | if (topDocs.scoreDocs.length > 2) {
81 | topDocs.scoreDocs[0].score =
82 | topDocs.scoreDocs[0].score + (topDocs.scoreDocs[0].score - topDocs.scoreDocs[1].score);
83 | }
84 | return topDocs;
85 | }
86 |
87 | private static float calculate(float v, float oldMin, float oldMax, float newMax, float newMin) {
88 | return ((v - oldMin) / (oldMax - oldMin)) * (newMax - newMin) + newMin;
89 | }
90 |
91 | private static float getFinalScore(String factorMode, float factor, float normalizedValue) {
92 |
93 | if (factorMode.equals(NormalizerFactorMathOp.sum.name())) {
94 | normalizedValue = normalizedValue + factor;
95 | } else if (factorMode.equals(NormalizerFactorMathOp.multiply.name())) {
96 | normalizedValue = normalizedValue * factor;
97 | } else {
98 | if (normalizedValue == 0.0f) {
99 | normalizedValue = factor;
100 | } else {
101 | if (factor < 0 || factor > 1) {
102 | throw new IllegalArgumentException(
103 | "Invalid `factor` for `factor_mode` "
104 | + "increase_by_percent, "
105 | + "allowed "
106 | + "factor "
107 | + "range "
108 | + "0-1 "
109 | + "including 0 and 1.");
110 | }
111 | normalizedValue = normalizedValue + normalizedValue * factor;
112 | }
113 | }
114 | return normalizedValue;
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/src/main/java/org/bkatwal/elasticsearch/plugin/helper/Normalizer.java:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) Bikas Katwal - bikas.katwal10@gmail.com
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | package org.bkatwal.elasticsearch.plugin.helper;
25 |
26 | import org.apache.lucene.search.TopDocs;
27 | import org.bkatwal.elasticsearch.plugin.rescorer.ScoreNormalizerRescorer;
28 |
29 | public interface Normalizer {
30 |
31 | TopDocs normalize(
32 | TopDocs topDocs, ScoreNormalizerRescorer.ScoreNormalizerRescorerContext rescoreContext);
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/org/bkatwal/elasticsearch/plugin/helper/NormalizerServiceLocator.java:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) Bikas Katwal - bikas.katwal10@gmail.com
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | package org.bkatwal.elasticsearch.plugin.helper;
25 |
26 | import org.bkatwal.elasticsearch.plugin.rescorer.NormalizerType;
27 |
28 | public final class NormalizerServiceLocator {
29 |
30 | private NormalizerServiceLocator() {}
31 |
32 | private static final Normalizer minMaxNormalizer = new MinMaxNormalizer();
33 | private static final Normalizer zScoreNormalizer = new ZScoreNormalizer();
34 |
35 | public static Normalizer getInstance(NormalizerType normalizerType) {
36 | if (normalizerType == NormalizerType.min_max) {
37 | return minMaxNormalizer;
38 | }
39 | if (normalizerType == NormalizerType.z_score) {
40 | return zScoreNormalizer;
41 | }
42 |
43 | return zScoreNormalizer;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/org/bkatwal/elasticsearch/plugin/helper/ZScoreNormalizer.java:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) Bikas Katwal - bikas.katwal10@gmail.com
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | package org.bkatwal.elasticsearch.plugin.helper;
25 |
26 | import org.apache.lucene.search.ScoreDoc;
27 | import org.apache.lucene.search.TopDocs;
28 | import org.bkatwal.elasticsearch.plugin.rescorer.NormalizerFactorMathOp;
29 | import org.bkatwal.elasticsearch.plugin.rescorer.ScoreNormalizerRescorer;
30 |
31 | public class ZScoreNormalizer implements Normalizer {
32 | @Override
33 | public TopDocs normalize(
34 | TopDocs topDocs, ScoreNormalizerRescorer.ScoreNormalizerRescorerContext rescoreContext) {
35 |
36 | if (topDocs.scoreDocs.length == 0) {
37 | return topDocs;
38 | }
39 |
40 | ScoreDoc[] scoreDocs = topDocs.scoreDocs;
41 | float mean = meanScore(scoreDocs);
42 | float sd = standardDeviation(scoreDocs, mean);
43 |
44 | if (sd == 0.0f) {
45 | sd = 1.0f;
46 | }
47 | for (ScoreDoc scoreDoc : scoreDocs) {
48 | float normalizedScore = zScore(scoreDoc.score, mean, sd);
49 |
50 | scoreDoc.score =
51 | getFinalScore(
52 | rescoreContext.getFactorMode(), rescoreContext.getFactor(), normalizedScore);
53 | }
54 | return topDocs;
55 | }
56 |
57 | private float meanScore(ScoreDoc[] scoreDocs) {
58 |
59 | float total = 0.0f;
60 |
61 | for (ScoreDoc scoreDoc : scoreDocs) {
62 | total = total + scoreDoc.score;
63 | }
64 |
65 | return total / scoreDocs.length;
66 | }
67 |
68 | private float standardDeviation(ScoreDoc[] scoreDocs, float mean) {
69 |
70 | float totalVariance = 0.0f;
71 | for (ScoreDoc scoreDoc : scoreDocs) {
72 | float delta = scoreDoc.score - mean;
73 | float deltaSq = delta * delta;
74 | totalVariance = totalVariance + deltaSq;
75 | }
76 | return (float) Math.sqrt(totalVariance / scoreDocs.length);
77 | }
78 |
79 | private float zScore(float val, float mean, float sd) {
80 |
81 | return (val - mean) / sd;
82 | }
83 |
84 | private static float getFinalScore(String factorMode, float factor, float normalizedValue) {
85 |
86 | if (factorMode.equals(NormalizerFactorMathOp.sum.name())) {
87 | normalizedValue = normalizedValue + factor;
88 | } else {
89 | float v = normalizedValue + Math.abs(normalizedValue) * factor;
90 | if (factorMode.equals(NormalizerFactorMathOp.multiply.name())) {
91 | normalizedValue = normalizedValue >= 0 ? normalizedValue * factor : v;
92 | } else {
93 | if (normalizedValue == 0.0f) {
94 | normalizedValue = factor;
95 | } else {
96 | if (factor < 0 || factor > 1) {
97 | throw new IllegalArgumentException(
98 | "Invalid `factor` for `factor_mode` "
99 | + "increase_by_percent, "
100 | + "allowed "
101 | + "factor "
102 | + "range "
103 | + "0-1 "
104 | + "including 0 and 1.");
105 | }
106 | normalizedValue = v;
107 | }
108 | }
109 | }
110 | return normalizedValue;
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/src/main/java/org/bkatwal/elasticsearch/plugin/rescorer/MinMaxSameScoreStrategy.java:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) Bikas Katwal - bikas.katwal10@gmail.com
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | package org.bkatwal.elasticsearch.plugin.rescorer;
25 |
26 | public enum MinMaxSameScoreStrategy {
27 | avg,
28 | max,
29 | min
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/org/bkatwal/elasticsearch/plugin/rescorer/NormalizerFactorMathOp.java:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) Bikas Katwal - bikas.katwal10@gmail.com
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | package org.bkatwal.elasticsearch.plugin.rescorer;
25 |
26 | public enum NormalizerFactorMathOp {
27 | sum,
28 | multiply,
29 | increase_by_percent
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/org/bkatwal/elasticsearch/plugin/rescorer/NormalizerRescorerBuilder.java:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) Bikas Katwal - bikas.katwal10@gmail.com
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | package org.bkatwal.elasticsearch.plugin.rescorer;
25 |
26 | import org.elasticsearch.common.ParseField;
27 | import org.elasticsearch.common.io.stream.StreamInput;
28 | import org.elasticsearch.common.io.stream.StreamOutput;
29 | import org.elasticsearch.common.xcontent.ObjectParser;
30 | import org.elasticsearch.common.xcontent.XContentBuilder;
31 | import org.elasticsearch.common.xcontent.XContentParser;
32 | import org.elasticsearch.index.query.QueryRewriteContext;
33 | import org.elasticsearch.index.query.QueryShardContext;
34 | import org.elasticsearch.search.rescore.RescoreContext;
35 | import org.elasticsearch.search.rescore.RescorerBuilder;
36 |
37 | import java.io.IOException;
38 |
39 | import static org.bkatwal.elasticsearch.plugin.rescorer.NormalizerType.isValid;
40 |
41 | public class NormalizerRescorerBuilder extends RescorerBuilder {
42 | public static final String NAME = "score_normalizer";
43 |
44 | private static final ParseField NORMALIZER_TYPE = new ParseField("normalizer_type");
45 | private static final ParseField MIN_SCORE = new ParseField("min_score");
46 | private static final ParseField MAX_SCORE = new ParseField("max_score");
47 | private static final ParseField FACTOR = new ParseField("factor");
48 | private static final ParseField FACTOR_MODE = new ParseField("factor_mode");
49 | private static final ParseField ON_SCORES_SAME = new ParseField("on_score_same");
50 | private static final float DEFAULT_MIN_SCORE_V = 1.0f;
51 | private static final float DEFAULT_MAX_SCORE_V = 5.0f;
52 | private static final float DEFAULT_FACTOR = 0.0f;
53 | private static final String DEFAULT_ON_SCORES_SAME = MinMaxSameScoreStrategy.avg.name();
54 |
55 | private static final NormalizerType DEFAULT_NORMALIZER_TYPE = NormalizerType.z_score;
56 | private static final String DEFAULT_FACTOR_MODE =
57 | NormalizerFactorMathOp.increase_by_percent.name();
58 |
59 | private float minScore;
60 | private float maxScore;
61 | private String normalizerType;
62 | private float factor;
63 | private String factorMode;
64 | private String onScoresSame;
65 |
66 | private static final ObjectParser NORMALIZER_RESCORER_PARSER =
67 | new ObjectParser<>(NAME, null);
68 |
69 | static {
70 | NORMALIZER_RESCORER_PARSER.declareString(
71 | NormalizerRescorerBuilder.NRCoreBuilder::setNormalizerType, NORMALIZER_TYPE);
72 | NORMALIZER_RESCORER_PARSER.declareFloat(
73 | NormalizerRescorerBuilder.NRCoreBuilder::setMinScore, MIN_SCORE);
74 | NORMALIZER_RESCORER_PARSER.declareFloat(
75 | NormalizerRescorerBuilder.NRCoreBuilder::setMaxScore, MAX_SCORE);
76 | NORMALIZER_RESCORER_PARSER.declareFloat(
77 | NormalizerRescorerBuilder.NRCoreBuilder::setFactor, FACTOR);
78 | NORMALIZER_RESCORER_PARSER.declareString(
79 | NormalizerRescorerBuilder.NRCoreBuilder::setFactorMode, FACTOR_MODE);
80 | NORMALIZER_RESCORER_PARSER.declareString(
81 | NormalizerRescorerBuilder.NRCoreBuilder::setOnScoresSame, ON_SCORES_SAME);
82 | }
83 |
84 | public NormalizerRescorerBuilder() {}
85 |
86 | public NormalizerRescorerBuilder(StreamInput in) throws IOException {
87 | super(in);
88 | normalizerType = in.readOptionalString();
89 | minScore = in.readOptionalFloat();
90 | maxScore = in.readOptionalFloat();
91 | factor = in.readOptionalFloat();
92 | factorMode = in.readOptionalString();
93 | onScoresSame = in.readOptionalString();
94 | }
95 |
96 | @Override
97 | protected void doWriteTo(StreamOutput out) throws IOException {
98 | out.writeString(normalizerType);
99 | out.writeFloat(minScore);
100 | out.writeFloat(maxScore);
101 | out.writeFloat(factor);
102 | out.writeString(factorMode);
103 | out.writeString(onScoresSame);
104 | }
105 |
106 | @Override
107 | protected void doXContent(XContentBuilder builder, Params params) throws IOException {
108 | builder.startObject(NAME);
109 | builder.field(NORMALIZER_TYPE.getPreferredName(), normalizerType);
110 | builder.field(MIN_SCORE.getPreferredName(), minScore);
111 | builder.field(MAX_SCORE.getPreferredName(), maxScore);
112 | builder.field(FACTOR.getPreferredName(), factor);
113 | builder.field(FACTOR_MODE.getPreferredName(), factorMode);
114 | builder.field(ON_SCORES_SAME.getPreferredName(), onScoresSame);
115 | builder.endObject();
116 | }
117 |
118 | @Override
119 | protected RescoreContext innerBuildContext(int windowSize, QueryShardContext context)
120 | throws IOException {
121 | ScoreNormalizerRescorer.ScoreNormalizerRescorerContext scoreNormalizerRescorerContext =
122 | new ScoreNormalizerRescorer.ScoreNormalizerRescorerContext(
123 | windowSize, normalizerType, minScore, maxScore, factor, factorMode, onScoresSame);
124 | // query is rewritten at this point already
125 | scoreNormalizerRescorerContext.setNormalizerType(normalizerType);
126 | scoreNormalizerRescorerContext.setMinScore(minScore);
127 | scoreNormalizerRescorerContext.setMaxScore(maxScore);
128 | scoreNormalizerRescorerContext.setFactor(factor);
129 | scoreNormalizerRescorerContext.setFactorMode(factorMode);
130 | scoreNormalizerRescorerContext.setOnScoresSame(onScoresSame);
131 | return scoreNormalizerRescorerContext;
132 | }
133 |
134 | public static NormalizerRescorerBuilder fromXContent(XContentParser parser) throws IOException {
135 | NormalizerRescorerBuilder.NRCoreBuilder nrCoreBuilder =
136 | NORMALIZER_RESCORER_PARSER.parse(
137 | parser, new NormalizerRescorerBuilder.NRCoreBuilder(), null);
138 | return nrCoreBuilder.build();
139 | }
140 |
141 | @Override
142 | public String getWriteableName() {
143 | return NAME;
144 | }
145 |
146 | @Override
147 | public RescorerBuilder rewrite(QueryRewriteContext ctx)
148 | throws IOException {
149 | return this;
150 | }
151 |
152 | public NormalizerRescorerBuilder setMinScore(float minScore) {
153 | this.minScore = minScore;
154 | return this;
155 | }
156 |
157 | public NormalizerRescorerBuilder setFactor(float factor) {
158 | this.factor = factor;
159 | return this;
160 | }
161 |
162 | public NormalizerRescorerBuilder setFactorMode(String factorMode) {
163 | this.factorMode = factorMode;
164 | return this;
165 | }
166 |
167 | public NormalizerRescorerBuilder setMaxScore(float maxScore) {
168 | this.maxScore = maxScore;
169 | return this;
170 | }
171 |
172 | public NormalizerRescorerBuilder setNormalizerType(String normalizerType) {
173 | this.normalizerType = normalizerType;
174 | return this;
175 | }
176 |
177 | public NormalizerRescorerBuilder setOnScoresSame(String onScoresSame) {
178 | this.onScoresSame = onScoresSame;
179 | return this;
180 | }
181 |
182 | private static class NRCoreBuilder {
183 |
184 | private float minScore = DEFAULT_MIN_SCORE_V;
185 | private float maxScore = DEFAULT_MAX_SCORE_V;
186 | private String normalizerType = DEFAULT_NORMALIZER_TYPE.name();
187 | private float factor = DEFAULT_FACTOR;
188 | private String factorMode = DEFAULT_FACTOR_MODE;
189 | private String onScoresSame = DEFAULT_ON_SCORES_SAME;
190 |
191 | NormalizerRescorerBuilder build() {
192 | NormalizerRescorerBuilder normalizerRescorerBuilder = new NormalizerRescorerBuilder();
193 | normalizerRescorerBuilder.setNormalizerType(normalizerType);
194 | normalizerRescorerBuilder.setMinScore(minScore);
195 | normalizerRescorerBuilder.setMaxScore(maxScore);
196 | normalizerRescorerBuilder.setFactor(factor);
197 | normalizerRescorerBuilder.setFactorMode(factorMode);
198 | normalizerRescorerBuilder.setOnScoresSame(onScoresSame);
199 | return normalizerRescorerBuilder;
200 | }
201 |
202 | public void setMinScore(float minScore) {
203 | this.minScore = minScore;
204 | }
205 |
206 | public void setMaxScore(float maxScore) {
207 | this.maxScore = maxScore;
208 | }
209 |
210 | public void setFactor(float factor) {
211 | this.factor = factor;
212 | }
213 |
214 | public void setFactorMode(String factorMode) {
215 | this.factorMode = factorMode;
216 | }
217 |
218 | public void setOnScoresSame(String onScoresSame) {
219 | this.onScoresSame = onScoresSame;
220 | }
221 |
222 | public void setNormalizerType(String normalizerType) {
223 | if (normalizerType == null) {
224 | return;
225 | }
226 | if (isValid(normalizerType)) {
227 | this.normalizerType = normalizerType;
228 | }
229 | }
230 | }
231 | }
232 |
--------------------------------------------------------------------------------
/src/main/java/org/bkatwal/elasticsearch/plugin/rescorer/NormalizerType.java:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) Bikas Katwal - bikas.katwal10@gmail.com
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | package org.bkatwal.elasticsearch.plugin.rescorer;
25 |
26 | public enum NormalizerType {
27 | min_max,
28 | z_score;
29 |
30 | public static boolean isValid(String normalizerType) {
31 | try {
32 | NormalizerType.valueOf(normalizerType);
33 | } catch (IllegalArgumentException e) {
34 | return false;
35 | }
36 | return true;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/org/bkatwal/elasticsearch/plugin/rescorer/ScoreNormalizerRescorer.java:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) Bikas Katwal - bikas.katwal10@gmail.com
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | package org.bkatwal.elasticsearch.plugin.rescorer;
25 |
26 | import org.apache.lucene.search.Explanation;
27 | import org.apache.lucene.search.IndexSearcher;
28 | import org.apache.lucene.search.TopDocs;
29 | import org.bkatwal.elasticsearch.plugin.helper.NormalizerServiceLocator;
30 | import org.elasticsearch.common.Nullable;
31 | import org.elasticsearch.search.rescore.RescoreContext;
32 | import org.elasticsearch.search.rescore.Rescorer;
33 |
34 | import static java.util.Collections.singletonList;
35 |
36 | public class ScoreNormalizerRescorer implements Rescorer {
37 |
38 | public static final Rescorer INSTANCE = new ScoreNormalizerRescorer();
39 |
40 | /**
41 | * this function returns the top k normalized docs from each shard.
42 | *
43 | * @param topDocs top docs matched for given query
44 | * @param searcher Index Searcher
45 | * @param rescoreContext Context/params needed for rescore function.
46 | * @return return top k normalized docs from each shard
47 | */
48 | @Override
49 | public TopDocs rescore(TopDocs topDocs, IndexSearcher searcher, RescoreContext rescoreContext) {
50 |
51 | assert rescoreContext != null;
52 | if (topDocs == null || topDocs.scoreDocs.length == 0) {
53 | return topDocs;
54 | }
55 |
56 | ScoreNormalizerRescorerContext context = (ScoreNormalizerRescorerContext) rescoreContext;
57 | String normalizerType = context.normalizerType;
58 |
59 | topDocs =
60 | NormalizerServiceLocator.getInstance(NormalizerType.valueOf(normalizerType))
61 | .normalize(topDocs, context);
62 | return topDocs;
63 | }
64 |
65 | @Override
66 | public Explanation explain(
67 | int topLevelDocId,
68 | IndexSearcher searcher,
69 | RescoreContext rescoreContext,
70 | Explanation sourceExplanation) {
71 |
72 | ScoreNormalizerRescorerContext context = (ScoreNormalizerRescorerContext) rescoreContext;
73 | String factorMode = context.getFactorMode();
74 | float factor = context.factor;
75 | String operation = factorMode + " using " + factor + " on:";
76 |
77 | return Explanation.match(
78 | 0.0f,
79 | "Final score -> normalize using, " + context.getNormalizerType() + " and then " + operation,
80 | singletonList(sourceExplanation));
81 | }
82 |
83 | public static class ScoreNormalizerRescorerContext extends RescoreContext {
84 | private String normalizerType;
85 | private float minScore;
86 | private float maxScore;
87 | private float factor;
88 | private String factorMode;
89 | private String onScoresSame;
90 |
91 | public ScoreNormalizerRescorerContext(
92 | int windowSize,
93 | @Nullable String normalizerType,
94 | @Nullable float minScore,
95 | @Nullable float maxScore,
96 | @Nullable float factor,
97 | @Nullable String factorMode,
98 | @Nullable String onScoresSame) {
99 | super(windowSize, INSTANCE);
100 | this.minScore = minScore;
101 | this.maxScore = maxScore;
102 | this.normalizerType = normalizerType;
103 | this.factorMode = factorMode;
104 | this.factor = factor;
105 | this.onScoresSame = onScoresSame;
106 | }
107 |
108 | public void setFactor(float factor) {
109 | this.factor = factor;
110 | }
111 |
112 | public void setFactorMode(String factorMode) {
113 | this.factorMode = factorMode;
114 | }
115 |
116 | public String getNormalizerType() {
117 | return normalizerType;
118 | }
119 |
120 | public void setNormalizerType(String normalizerType) {
121 | this.normalizerType = normalizerType;
122 | }
123 |
124 | public float getMinScore() {
125 | return minScore;
126 | }
127 |
128 | public float getFactor() {
129 | return factor;
130 | }
131 |
132 | public String getOnScoresSame() {
133 | return onScoresSame;
134 | }
135 |
136 | public void setOnScoresSame(String onScoresSame) {
137 | this.onScoresSame = onScoresSame;
138 | }
139 |
140 | public String getFactorMode() {
141 | return factorMode;
142 | }
143 |
144 | public void setMinScore(float minScore) {
145 | this.minScore = minScore;
146 | }
147 |
148 | public float getMaxScore() {
149 | return maxScore;
150 | }
151 |
152 | public void setMaxScore(float maxScore) {
153 | this.maxScore = maxScore;
154 | }
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/src/main/java/org/bkatwal/elasticsearch/plugin/rescorer/ScoreNormalizerRescorerPlugin.java:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) Bikas Katwal - bikas.katwal10@gmail.com
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | package org.bkatwal.elasticsearch.plugin.rescorer;
25 |
26 | import org.elasticsearch.plugins.Plugin;
27 | import org.elasticsearch.plugins.SearchPlugin;
28 |
29 | import java.util.List;
30 |
31 | import static java.util.Collections.singletonList;
32 |
33 | public class ScoreNormalizerRescorerPlugin extends Plugin implements SearchPlugin {
34 | @Override
35 | public List> getRescorers() {
36 | return singletonList(
37 | new SearchPlugin.RescorerSpec<>(
38 | NormalizerRescorerBuilder.NAME,
39 | NormalizerRescorerBuilder::new,
40 | NormalizerRescorerBuilder::fromXContent));
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/resources/plugin-descriptor.properties:
--------------------------------------------------------------------------------
1 | description=${project.description}
2 | version=${project.version}
3 | name=${project.artifactId}
4 | classname=org.bkatwal.elasticsearch.plugin.rescorer.ScoreNormalizerRescorerPlugin
5 | java.version=1.8
6 | elasticsearch.version=${elasticsearch.version}
7 |
--------------------------------------------------------------------------------
/src/test/java/org/bkatwal/elasticsearch/plugin/helper/MinMaxNormalizerTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) Bikas Katwal - bikas.katwal10@gmail.com
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | package org.bkatwal.elasticsearch.plugin.helper;
25 |
26 | import org.apache.lucene.search.ScoreDoc;
27 | import org.apache.lucene.search.TopDocs;
28 | import org.apache.lucene.search.TotalHits;
29 | import org.bkatwal.elasticsearch.plugin.rescorer.MinMaxSameScoreStrategy;
30 | import org.bkatwal.elasticsearch.plugin.rescorer.ScoreNormalizerRescorer;
31 | import org.junit.Assert;
32 | import org.junit.Before;
33 | import org.junit.Test;
34 |
35 | public class MinMaxNormalizerTest {
36 |
37 | private Normalizer minMaxNormalizer;
38 |
39 | @Before
40 | public void init() {
41 | minMaxNormalizer = new MinMaxNormalizer();
42 | }
43 |
44 | @Test
45 | public void assertMinMaxNormalizer() {
46 | TotalHits totalHits = new TotalHits(5, TotalHits.Relation.EQUAL_TO);
47 | ScoreDoc[] scoreDocs = new ScoreDoc[5];
48 | scoreDocs[0] = new ScoreDoc(1, 10.5f);
49 | scoreDocs[1] = new ScoreDoc(2, 9);
50 | scoreDocs[2] = new ScoreDoc(3, 8);
51 | scoreDocs[3] = new ScoreDoc(4, 6.5f);
52 | scoreDocs[4] = new ScoreDoc(5, 2f);
53 | TopDocs topDocs = new TopDocs(totalHits, scoreDocs);
54 |
55 | ScoreNormalizerRescorer.ScoreNormalizerRescorerContext context =
56 | new ScoreNormalizerRescorer.ScoreNormalizerRescorerContext(
57 | 3, "min_max", 1, 4, .6f, "increase_by_percent", null);
58 |
59 | topDocs = minMaxNormalizer.normalize(topDocs, context);
60 | Assert.assertEquals(7.2f, topDocs.scoreDocs[0].score, 0.1f);
61 | Assert.assertEquals(5.5, topDocs.scoreDocs[1].score, 0.1f);
62 | Assert.assertEquals(4.9, topDocs.scoreDocs[2].score, 0.1f);
63 | Assert.assertEquals(4.1f, topDocs.scoreDocs[3].score, 0.1f);
64 | Assert.assertEquals(1.6f, topDocs.scoreDocs[4].score, 0.1f);
65 | }
66 |
67 | @Test
68 | public void assertMinMaxNormalizerZeroDocs() {
69 | TotalHits totalHits = new TotalHits(0, TotalHits.Relation.EQUAL_TO);
70 | ScoreDoc[] scoreDocs = new ScoreDoc[0];
71 | TopDocs topDocs = new TopDocs(totalHits, scoreDocs);
72 |
73 | ScoreNormalizerRescorer.ScoreNormalizerRescorerContext context =
74 | new ScoreNormalizerRescorer.ScoreNormalizerRescorerContext(
75 | 3, "min_max", 1, 4, .6f, "increase_by_percent", null);
76 |
77 | topDocs = minMaxNormalizer.normalize(topDocs, context);
78 | Assert.assertNotNull(topDocs);
79 | }
80 |
81 | @Test
82 | public void assertMinMaxNormalizerOneDocs() {
83 | TotalHits totalHits = new TotalHits(1, TotalHits.Relation.EQUAL_TO);
84 | ScoreDoc[] scoreDocs = new ScoreDoc[1];
85 | TopDocs topDocs = new TopDocs(totalHits, scoreDocs);
86 | scoreDocs[0] = new ScoreDoc(1, 10.5f);
87 |
88 | ScoreNormalizerRescorer.ScoreNormalizerRescorerContext context =
89 | new ScoreNormalizerRescorer.ScoreNormalizerRescorerContext(
90 | 3, "min_max", 1, 4, .6f, "increase_by_percent", null);
91 |
92 | topDocs = minMaxNormalizer.normalize(topDocs, context);
93 | Assert.assertEquals(6.4f, topDocs.scoreDocs[0].score, 0.0f);
94 | }
95 |
96 | @Test
97 | public void assertSameScoreDocs() {
98 | TotalHits totalHits = new TotalHits(5, TotalHits.Relation.EQUAL_TO);
99 | ScoreDoc[] scoreDocs = new ScoreDoc[5];
100 | scoreDocs[0] = new ScoreDoc(1, 4f);
101 | scoreDocs[1] = new ScoreDoc(2, 4f);
102 | scoreDocs[2] = new ScoreDoc(3, 4f);
103 | scoreDocs[3] = new ScoreDoc(4, 4f);
104 | scoreDocs[4] = new ScoreDoc(5, 4f);
105 | TopDocs topDocs = new TopDocs(totalHits, scoreDocs);
106 |
107 | ScoreNormalizerRescorer.ScoreNormalizerRescorerContext context =
108 | new ScoreNormalizerRescorer.ScoreNormalizerRescorerContext(
109 | 3, "min_max", 1, 5, .6f, "increase_by_percent", MinMaxSameScoreStrategy.avg.name());
110 |
111 | topDocs = minMaxNormalizer.normalize(topDocs, context);
112 | Assert.assertEquals(3f, topDocs.scoreDocs[0].score, 0.0f);
113 | Assert.assertEquals(3f, topDocs.scoreDocs[1].score, 0.0f);
114 | Assert.assertEquals(3f, topDocs.scoreDocs[2].score, 0.0f);
115 | Assert.assertEquals(3f, topDocs.scoreDocs[3].score, 0.0f);
116 | Assert.assertEquals(3f, topDocs.scoreDocs[4].score, 0.0f);
117 | }
118 |
119 | @Test
120 | public void assertValueSameAsNewMin() {
121 | TotalHits totalHits = new TotalHits(2, TotalHits.Relation.EQUAL_TO);
122 | ScoreDoc[] scoreDocs = new ScoreDoc[2];
123 | TopDocs topDocs = new TopDocs(totalHits, scoreDocs);
124 | scoreDocs[0] = new ScoreDoc(1, 10);
125 | scoreDocs[1] = new ScoreDoc(2, 5);
126 |
127 | ScoreNormalizerRescorer.ScoreNormalizerRescorerContext context =
128 | new ScoreNormalizerRescorer.ScoreNormalizerRescorerContext(
129 | 2, "min_max", 5, 20, 0.0f, "increase_by_percent", null);
130 |
131 | topDocs = minMaxNormalizer.normalize(topDocs, context);
132 | Assert.assertEquals(20f, topDocs.scoreDocs[0].score, 0.0f);
133 | Assert.assertEquals(5f, topDocs.scoreDocs[1].score, 0.0f);
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/src/test/java/org/bkatwal/elasticsearch/plugin/helper/ZScoreNormalizerTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) Bikas Katwal - bikas.katwal10@gmail.com
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 | package org.bkatwal.elasticsearch.plugin.helper;
25 |
26 | import org.apache.lucene.search.ScoreDoc;
27 | import org.apache.lucene.search.TopDocs;
28 | import org.apache.lucene.search.TotalHits;
29 | import org.bkatwal.elasticsearch.plugin.rescorer.ScoreNormalizerRescorer;
30 | import org.junit.Assert;
31 | import org.junit.Before;
32 | import org.junit.Test;
33 |
34 | public class ZScoreNormalizerTest {
35 | private Normalizer zScoreNormalizer;
36 |
37 | @Before
38 | public void init() {
39 | zScoreNormalizer = new ZScoreNormalizer();
40 | }
41 |
42 | @Test
43 | public void assertNormalization() {
44 | TotalHits totalHits = new TotalHits(5, TotalHits.Relation.EQUAL_TO);
45 | ScoreDoc[] scoreDocs = new ScoreDoc[5];
46 | scoreDocs[0] = new ScoreDoc(1, 10f);
47 | scoreDocs[1] = new ScoreDoc(2, 6f);
48 | scoreDocs[2] = new ScoreDoc(3, 4f);
49 | scoreDocs[3] = new ScoreDoc(4, 3.5f);
50 | scoreDocs[4] = new ScoreDoc(5, 3f);
51 | TopDocs topDocs = new TopDocs(totalHits, scoreDocs);
52 |
53 | ScoreNormalizerRescorer.ScoreNormalizerRescorerContext context =
54 | new ScoreNormalizerRescorer.ScoreNormalizerRescorerContext(
55 | 5, "z_score", 1, 4, 0.0f, "increase_by_percent", null);
56 |
57 | topDocs = zScoreNormalizer.normalize(topDocs, context);
58 | Assert.assertEquals(1.8f, topDocs.scoreDocs[0].score, 0.1f);
59 | Assert.assertEquals(0.27f, topDocs.scoreDocs[1].score, 0.1f);
60 | Assert.assertEquals(-0.5f, topDocs.scoreDocs[2].score, 0.1f);
61 | Assert.assertEquals(-0.7f, topDocs.scoreDocs[3].score, 0.1f);
62 | Assert.assertEquals(-0.89, topDocs.scoreDocs[4].score, 0.1f);
63 | }
64 |
65 | @Test
66 | public void assertNormalizeSameScore() {
67 | TotalHits totalHits = new TotalHits(5, TotalHits.Relation.EQUAL_TO);
68 | ScoreDoc[] scoreDocs = new ScoreDoc[3];
69 | scoreDocs[0] = new ScoreDoc(1, 10f);
70 | scoreDocs[1] = new ScoreDoc(2, 10f);
71 | scoreDocs[2] = new ScoreDoc(3, 10f);
72 | TopDocs topDocs = new TopDocs(totalHits, scoreDocs);
73 |
74 | ScoreNormalizerRescorer.ScoreNormalizerRescorerContext context =
75 | new ScoreNormalizerRescorer.ScoreNormalizerRescorerContext(
76 | 3, "z_score", 1, 4, 0.0f, "increase_by_percent", null);
77 |
78 | topDocs = zScoreNormalizer.normalize(topDocs, context);
79 | Assert.assertEquals(0.0f, topDocs.scoreDocs[0].score, 0.1f);
80 | Assert.assertEquals(0.0f, topDocs.scoreDocs[1].score, 0.1f);
81 | Assert.assertEquals(0.0f, topDocs.scoreDocs[2].score, 0.1f);
82 | }
83 |
84 | @Test
85 | public void assertFactorWithNormalization() {
86 | TotalHits totalHits = new TotalHits(3, TotalHits.Relation.EQUAL_TO);
87 | ScoreDoc[] scoreDocs = new ScoreDoc[5];
88 | scoreDocs[0] = new ScoreDoc(1, 10f);
89 | scoreDocs[1] = new ScoreDoc(2, 6f);
90 | scoreDocs[2] = new ScoreDoc(3, 4f);
91 | scoreDocs[3] = new ScoreDoc(4, 3.5f);
92 | scoreDocs[4] = new ScoreDoc(5, 3f);
93 | TopDocs topDocs = new TopDocs(totalHits, scoreDocs);
94 |
95 | ScoreNormalizerRescorer.ScoreNormalizerRescorerContext context =
96 | new ScoreNormalizerRescorer.ScoreNormalizerRescorerContext(
97 | 5, "z_score", 1, 4, 0.5f, "increase_by_percent", null);
98 |
99 | topDocs = zScoreNormalizer.normalize(topDocs, context);
100 | Assert.assertEquals(2.7f, topDocs.scoreDocs[0].score, 0.1f);
101 | Assert.assertEquals(0.405f, topDocs.scoreDocs[1].score, 0.1f);
102 | Assert.assertEquals(-0.25f, topDocs.scoreDocs[2].score, 0.1f);
103 | }
104 | }
105 |
--------------------------------------------------------------------------------