diff --git a/engine-extensions/src/main/java/io/nosqlbench/engine/extensions/computefunctions/ComputeFunctions.java b/engine-extensions/src/main/java/io/nosqlbench/engine/extensions/computefunctions/ComputeFunctions.java index 44c8cd0f0..94d26d9f7 100644 --- a/engine-extensions/src/main/java/io/nosqlbench/engine/extensions/computefunctions/ComputeFunctions.java +++ b/engine-extensions/src/main/java/io/nosqlbench/engine/extensions/computefunctions/ComputeFunctions.java @@ -189,4 +189,33 @@ public class ComputeFunctions { return 2.0d * ((recallAtK * precisionAtK) / (recallAtK + precisionAtK)); } + /** + * Reciprocal Rank - The multiplicative inverse of the first rank which is relevant. + */ + public static double RR(long[] reference, long[] sample, int limit) { + int firstRank = Intersections.firstMatchingIndex(reference, sample, limit); + if (firstRank >= 0) { + return 1.0d / (firstRank+1); + } else { + return 0.0; + } + } + + public static double RR(long[] reference, long[] sample) { + return RR(reference, sample, reference.length); + } + + public static double RR(int[] reference, int[] sample, int limit) { + int firstRank = Intersections.firstMatchingIndex(reference, sample, limit); + if (firstRank >= 0) { + return 1.0d / (firstRank+1); + } else { + return 0.0; + } + } + + public static double RR(int[] reference, int[] sample) { + return RR(reference, sample, reference.length); + } + } diff --git a/engine-extensions/src/main/java/io/nosqlbench/engine/extensions/computefunctions/Intersections.java b/engine-extensions/src/main/java/io/nosqlbench/engine/extensions/computefunctions/Intersections.java index 97fe5699b..290cb4419 100644 --- a/engine-extensions/src/main/java/io/nosqlbench/engine/extensions/computefunctions/Intersections.java +++ b/engine-extensions/src/main/java/io/nosqlbench/engine/extensions/computefunctions/Intersections.java @@ -20,6 +20,32 @@ import java.util.Arrays; public class Intersections { + /** + * Return a non-negative index of the first value in the sample array which is present in the reference array, + * OR, return a negative number. This returns array index which start at 0, not rank, which is starts at 1. + */ + public static int firstMatchingIndex(long[] reference, long[] sample, int limit) { + Arrays.sort(reference); + int maxIndex = Math.min(sample.length, limit); + int foundAt=-1; + for (int index = 0; index < maxIndex; index++) { + foundAt = Arrays.binarySearch(reference, sample[index]); + if (foundAt>=0) break; + } + return foundAt; + } + + public static int firstMatchingIndex(int[] reference, int[] sample, int limit) { + Arrays.sort(reference); + int maxIndex = Math.min(sample.length, limit); + int foundAt=-1; + for (int index = 0; index < maxIndex; index++) { + foundAt = Arrays.binarySearch(reference, sample[index]); + if (foundAt>=0) break; + } + return foundAt; + } + public static int count(int[] reference, int[] sample) { return count(reference,sample,reference.length); } diff --git a/engine-extensions/src/test/java/io/nosqlbench/engine/extensions/computefunctions/ComputeFunctionsTest.java b/engine-extensions/src/test/java/io/nosqlbench/engine/extensions/computefunctions/ComputeFunctionsTest.java index 15d7700e7..546b5d911 100644 --- a/engine-extensions/src/test/java/io/nosqlbench/engine/extensions/computefunctions/ComputeFunctionsTest.java +++ b/engine-extensions/src/test/java/io/nosqlbench/engine/extensions/computefunctions/ComputeFunctionsTest.java @@ -78,4 +78,15 @@ class ComputeFunctionsTest { } } + + @Test + public void testReciprocalRank() { + assertThat(ComputeFunctions.RR(intsBy3_369,highInts56789)) + .as("relevant results in rank 2 should yield RR=0.5") + .isCloseTo(0.5d,offset); + + assertThat(ComputeFunctions.RR(highInts56789,lowInts01234)) + .as("no relevant results should yield RR=0.0") + .isCloseTo(0.0d,offset); + } }