/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.lucene.codecs;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.SortedSet;
import java.util.TreeSet;
import org.apache.lucene.index.Impact;
This class accumulates the (freq, norm) pairs that may produce competitive scores.
/**
* This class accumulates the (freq, norm) pairs that may produce competitive scores.
*/
public final class CompetitiveImpactAccumulator {
// We speed up accumulation for common norm values by first computing
// the max freq for all norms in -128..127
private final int[] maxFreqs;
private boolean dirty;
private final TreeSet<Impact> freqNormPairs;
Sole constructor. /** Sole constructor. */
public CompetitiveImpactAccumulator() {
maxFreqs = new int[256];
Comparator<Impact> comparator = new Comparator<Impact>() {
@Override
public int compare(Impact o1, Impact o2) {
// greater freqs compare greater
int cmp = Integer.compare(o1.freq, o2.freq);
if (cmp == 0) {
// greater norms compare lower
cmp = Long.compareUnsigned(o2.norm, o1.norm);
}
return cmp;
}
};
freqNormPairs = new TreeSet<>(comparator);
}
Reset to the same state it was in after creation. /** Reset to the same state it was in after creation. */
public void clear() {
Arrays.fill(maxFreqs, 0);
dirty = false;
freqNormPairs.clear();
}
Accumulate a (freq,norm) pair, updating this structure if there is no
equivalent or more competitive entry already. /** Accumulate a (freq,norm) pair, updating this structure if there is no
* equivalent or more competitive entry already. */
public void add(int freq, long norm) {
if (norm >= Byte.MIN_VALUE && norm <= Byte.MAX_VALUE) {
int index = Byte.toUnsignedInt((byte) norm);
maxFreqs[index] = Math.max(maxFreqs[index], freq);
dirty = true;
} else {
add(new Impact(freq, norm));
}
}
Merge acc
into this. /** Merge {@code acc} into this. */
public void addAll(CompetitiveImpactAccumulator acc) {
for (Impact entry : acc.getCompetitiveFreqNormPairs()) {
add(entry);
}
}
Get the set of competitive freq and norm pairs, orderer by increasing freq and norm. /** Get the set of competitive freq and norm pairs, orderer by increasing freq and norm. */
public SortedSet<Impact> getCompetitiveFreqNormPairs() {
if (dirty) {
for (int i = 0; i < maxFreqs.length; ++i) {
if (maxFreqs[i] > 0) {
add(new Impact(maxFreqs[i], (byte) i));
maxFreqs[i] = 0;
}
}
dirty = false;
}
return Collections.unmodifiableSortedSet(freqNormPairs);
}
private void add(Impact newEntry) {
Impact next = freqNormPairs.ceiling(newEntry);
if (next == null) {
// nothing is more competitive
freqNormPairs.add(newEntry);
} else if (Long.compareUnsigned(next.norm, newEntry.norm) <= 0) {
// we already have this entry or more competitive entries in the tree
return;
} else {
// some entries have a greater freq but a less competitive norm, so we
// don't know which one will trigger greater scores, still add to the tree
freqNormPairs.add(newEntry);
}
for (Iterator<Impact> it = freqNormPairs.headSet(newEntry, false).descendingIterator(); it.hasNext(); ) {
Impact entry = it.next();
if (Long.compareUnsigned(entry.norm, newEntry.norm) >= 0) {
// less competitive
it.remove();
} else {
// lesser freq but better norm, further entries are not comparable
break;
}
}
}
@Override
public String toString() {
return getCompetitiveFreqNormPairs().toString();
}
}