package de.danielbasedow.prospecter.core;
import de.danielbasedow.prospecter.core.query.QueryManager;
import de.danielbasedow.prospecter.core.query.QueryNegativeCounter;
import de.danielbasedow.prospecter.core.query.QueryPosting;
import gnu.trove.list.TLongList;
import gnu.trove.map.hash.TIntObjectHashMap;
import gnu.trove.procedure.TIntObjectProcedure;
import gnu.trove.procedure.TLongProcedure;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
/**
* Tracks hits across multiple index fields and applies the bit from the QueryPostings.
*/
public class Matcher {
protected final TIntObjectHashMap<BitSet> hits = new TIntObjectHashMap<BitSet>();
protected final TIntObjectHashMap<QueryNegativeCounter> negativeHits = new TIntObjectHashMap<QueryNegativeCounter>();
protected final QueryManager queryManager;
public Matcher(QueryManager qm) {
queryManager = qm;
}
public void addHits(TLongList postings) {
postings.forEach(new TLongProcedure() {
@Override
public boolean execute(long posting) {
addHit(posting);
return true;
}
});
}
public void addHit(long posting) {
int[] unpacked = QueryPosting.unpack(posting);
int queryId = unpacked[QueryPosting.QUERY_ID_INDEX];
if (unpacked[QueryPosting.QUERY_NOT_INDEX] == 1) {
QueryNegativeCounter counter = negativeHits.get(queryId);
if (counter == null) {
counter = new QueryNegativeCounter();
negativeHits.put(queryId, counter);
}
counter.add(unpacked[QueryPosting.QUERY_BIT_INDEX]);
} else {
BitSet bits = hits.get(queryId);
if (bits == null) {
bits = new BitSet();
hits.put(queryId, bits);
}
bits.set(unpacked[QueryPosting.QUERY_BIT_INDEX]);
}
}
public int getPositiveMatchCount() {
return hits.size();
}
public int getNegativeMatchCount() {
return negativeHits.size();
}
public List<Integer> getMatchedQueries() {
final List<Integer> results = new ArrayList<Integer>();
hits.forEachEntry(new TIntObjectProcedure<BitSet>() {
@Override
public boolean execute(int queryId, BitSet bitSet) {
BitSet mask = queryManager.getMask(queryId);
if (mask != null) {
if (mask.equals(bitSet)) {
results.add(queryId);
} else {
QueryNegativeCounter countMask = queryManager.getQueryNegativeCounter(queryId);
if (countMask != null) {
QueryNegativeCounter actualCount = negativeHits.get(queryId);
if (actualCount == null) {
actualCount = new QueryNegativeCounter();
}
int[] bitPositions = countMask.getBitPositionsToSet(actualCount);
if (bitPositions.length > 0) {
for (int position : bitPositions) {
bitSet.set(position, true);
}
}
if (mask.equals(bitSet)) {
results.add(queryId);
}
}
}
}
return true;
}
});
return results;
}
}