001: package it.unimi.dsi.mg4j.search.score;
002:
003: /*
004: * MG4J: Managing Gigabytes for Java
005: *
006: * Copyright (C) 2004-2007 Paolo Boldi and Sebastiano Vigna
007: *
008: * This library is free software; you can redistribute it and/or modify it
009: * under the terms of the GNU Lesser General Public License as published by the Free
010: * Software Foundation; either version 2.1 of the License, or (at your option)
011: * any later version.
012: *
013: * This library is distributed in the hope that it will be useful, but
014: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
015: * or FITfNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
016: * for more details.
017: *
018: * You should have received a copy of the GNU Lesser General Public License
019: * along with this program; if not, write to the Free Software
020: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
021: *
022: */
023:
024: import it.unimi.dsi.fastutil.Hash;
025: import it.unimi.dsi.fastutil.doubles.DoubleIterator;
026: import it.unimi.dsi.fastutil.objects.ObjectIterator;
027: import it.unimi.dsi.fastutil.objects.Reference2DoubleMap;
028: import it.unimi.dsi.fastutil.objects.Reference2DoubleOpenHashMap;
029: import it.unimi.dsi.mg4j.index.Index;
030: import it.unimi.dsi.mg4j.search.DocumentIterator;
031:
032: import java.io.IOException;
033: import java.util.Map.Entry;
034:
035: import org.apache.log4j.Logger;
036:
037: /** An abstract subsclass of {@link it.unimi.dsi.mg4j.search.score.AbstractIndexScorer}
038: * providing internal storage and copy of the weight map, faster array-based
039: * access to the latter, and a default implementation of {@link #score()}.
040: *
041: * <p><strong>Warning:</strong> implementing subclasses <strong>must</strong> implement
042: * {@link it.unimi.dsi.mg4j.search.score.Scorer#copy()} so that the state of the
043: * weight map is replicated, too.
044: */
045: public abstract class AbstractWeightedScorer extends
046: AbstractIndexScorer {
047: private static final Logger LOGGER = Logger
048: .getLogger(AbstractWeightedScorer.class);
049:
050: /** A map associating a weight with each index. */
051: protected Reference2DoubleOpenHashMap<Index> index2Weight = new Reference2DoubleOpenHashMap<Index>(
052: 1, Hash.VERY_FAST_LOAD_FACTOR);
053: {
054: // We leave it empty, but with default value 1, so all indices are peers.
055: index2Weight.defaultReturnValue(1);
056: }
057: /** An array parallel to {@link #currIndex} containing the current corresponding values in {@link #index2Weight};
058: * it is set up by {@link #wrap(DocumentIterator)}. */
059: protected double currWeight[];
060:
061: /** Copies the argument internally, rescaling weights so they sum up to one.
062: *
063: * @param index2Weight the new map from indices to weights.
064: * @return true.
065: */
066: public synchronized boolean setWeights(
067: final Reference2DoubleMap<Index> index2Weight) {
068: this .index2Weight.clear();
069: this .index2Weight.defaultReturnValue(0); // Since we're setting up values, we must assume missing indices have weight 0.
070:
071: double weightSum = 0;
072: for (DoubleIterator i = index2Weight.values().iterator(); i
073: .hasNext();)
074: weightSum += i.nextDouble();
075: if (weightSum == 0)
076: weightSum = 1; // No positive weights.
077: for (ObjectIterator<Entry<Index, Double>> i = index2Weight
078: .entrySet().iterator(); i.hasNext();) {
079: Reference2DoubleMap.Entry<Index> e = (Reference2DoubleMap.Entry<Index>) i
080: .next();
081: this .index2Weight.put(e.getKey(), e.getDoubleValue()
082: / weightSum);
083: }
084:
085: this .index2Weight.rehash();
086: LOGGER.debug("New weight map for " + this + ": "
087: + this .index2Weight);
088: return true;
089: }
090:
091: /** Computes a score by calling {@link #score(Index)} for
092: * each index in the current index map, and summing the weighted results.
093: *
094: * @return the combined weighted score.
095: */
096: public double score() throws IOException {
097: final double weight[] = this .currWeight;
098: final Index index[] = this .currIndex;
099: double result = 0;
100: for (int i = n; i-- != 0;)
101: result += weight[i] * score(index[i]);
102: return result;
103: }
104:
105: /** Wraps the given document iterator.
106: *
107: * <p>Besides the services provided by {@link AbstractIndexScorer#wrap(DocumentIterator)},
108: * this method sets up {@link #currWeight}.
109: *
110: * @param documentIterator the document iterator that will be used in subsequent calls to
111: * {@link #score()} and {@link #score(Index)}.
112: */
113:
114: public void wrap(final DocumentIterator documentIterator)
115: throws IOException {
116: super .wrap(documentIterator);
117: this .documentIterator = documentIterator;
118: currWeight = new double[n];
119: for (int i = n; i-- != 0;)
120: currWeight[i] = index2Weight.getDouble(currIndex[i]);
121: }
122:
123: }
|