/* * Ivory: A Hadoop toolkit for web-scale information retrieval * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You may * obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. */ package ivory.ltr; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @author Don Metzler * */ public class NDCGMeasure extends Measure { private final Map<String, Double> idealGainLookup = new HashMap<String,Double>(); // query id -> ideal gain mapping public NDCGMeasure() { idealGainLookup.clear(); } @Override public double evaluate(ScoreTable table) { String [] qids = table.getQids(); float [] grades = table.getGrades(); float [] scores = table.getScores(); float err = 0; int numQueries = 0; String lastQid = null; List<ScoreGradePair> items = new ArrayList<ScoreGradePair>(); for(int i = 0; i < qids.length; i++) { String curQid = qids[i]; float curGrade = grades[i]; float curScore = scores[i]; if(lastQid == null || !lastQid.equals(curQid)) { //System.out.println("Computing ERR for: " + lastQid); if(lastQid != null) { err += computeQueryNDCG(curQid, items); numQueries++; } lastQid = curQid; items = new ArrayList<ScoreGradePair>(); } items.add(new ScoreGradePair(curScore, curGrade)); } err += computeQueryNDCG(qids[qids.length-1], items); numQueries++; if(numQueries == 0) { return 0; } return err / numQueries; } private double computeQueryNDCG(String qid, List<ScoreGradePair> items) { // get ideal gain Double idealGain = idealGainLookup.get(qid); if(idealGain == null) { List<ScoreGradePair> newList = new ArrayList<ScoreGradePair>(items); Collections.sort(newList, new GradeComparator()); double idcg = 0.0; for(int i = 0; i < newList.size(); i++) { idcg += (Math.pow(2.0, newList.get(i).grade) - 1.0) / Math.log(i + 2.0); } idealGain = idcg; idealGainLookup.put(qid, idealGain); } // rank documents for this query Collections.sort(items, new ScoreComparator()); // compute err for query double dcg = 0.0; for(int i = 0; i < items.size(); i++) { dcg += (Math.pow(2.0, items.get(i).grade) - 1.0) / Math.log(i + 2.0); } if(idealGain == 0.0) { return 0.0; } return dcg / idealGain; } }