package de.danielbasedow.prospecter.core.query;
import aima.core.logic.propositional.parsing.ast.Connective;
import aima.core.logic.propositional.parsing.ast.Sentence;
import aima.core.logic.propositional.visitors.ConvertToCNF;
import de.danielbasedow.prospecter.core.MatchCondition;
import de.danielbasedow.prospecter.core.Token;
import de.danielbasedow.prospecter.core.query.build.*;
import java.util.*;
/**
* represents a Query (a tuple of queryId, bitmask and a list of conditions)
*/
public class Query {
protected final int queryId;
protected final int bits;
protected final QueryNegativeCounter negativeMask = new QueryNegativeCounter();
protected final ClauseNode clauseNode;
protected final Map<Condition, Long> postings = new HashMap<Condition, Long>();
public int getQueryId() {
return queryId;
}
public Query(int queryId, ClauseNode clauseNode) {
this.clauseNode = clauseNode;
this.queryId = queryId;
Sentence cnf = getCNF(clauseNode);
int tmpBits = 0;
for (int bit = 0; bit < cnf.getNumberSimplerSentences(); bit++) {
tmpBits++;
Sentence disjunction = cnf.getSimplerSentence(bit);
for (int p = 0; p < disjunction.getNumberSimplerSentences(); p++) {
Sentence sentence = disjunction.getSimplerSentence(p);
boolean isNegativeCondition = false;
if (sentence.isNotSentence()) {
sentence = sentence.getSimplerSentence(0);
isNegativeCondition = true;
}
Condition condition = ((PropositionSymbol) sentence).getCondition();
if (condition.getToken().getCondition() == MatchCondition.IN) {
//If this is an IN query we're dealing with a Token containing a List<Token>
Object t = condition.getToken().getToken();
if (t instanceof List) {
for (Token token : (List<Token>) t) {
Condition tmpCondition = new Condition(condition.getFieldName(), token, isNegativeCondition);
postings.put(tmpCondition, QueryPosting.pack(queryId, bit, isNegativeCondition));
}
}
} else {
condition.setNot(isNegativeCondition);
long posting = QueryPosting.pack(queryId, bit, isNegativeCondition);
if (isNegativeCondition) {
negativeMask.add(bit);
}
postings.put(condition, posting);
}
}
}
bits = tmpBits;
}
public static Sentence getCNF(Sentence sentence) {
Conjunction conjunction = new Conjunction();
flatten(conjunction, ConvertToCNF.convert(sentence));
return conjunction;
}
public static Sentence getCNF(ClauseNode clauseNode) {
return getCNF(PropositionalSentenceMapper.map(clauseNode));
}
public static void flatten(Conjunction conjunctionCollector, Sentence sentence) {
if (sentence.getNumberSimplerSentences() > 0 && sentence.getConnective() == Connective.AND) {
for (int i = 0; i < sentence.getNumberSimplerSentences(); i++) {
flatten(conjunctionCollector, sentence.getSimplerSentence(i));
}
} else {
Disjunction disjunctionCollector = new Disjunction();
flatten(disjunctionCollector, sentence);
conjunctionCollector.add(disjunctionCollector);
}
}
public static void flatten(Disjunction disjunctionCollector, Sentence sentence) {
if (sentence.getNumberSimplerSentences() > 0 && sentence.getConnective() == Connective.OR) {
for (int i = 0; i < sentence.getNumberSimplerSentences(); i++) {
flatten(disjunctionCollector, sentence.getSimplerSentence(i));
}
} else {
disjunctionCollector.add(sentence);
}
}
/**
* Get QueryPostings for every Condition
*
* @return map of Condition -> QueryPosting
*/
public Map<Condition, Long> getPostings() {
return postings;
}
public ClauseNode getClauses() {
return clauseNode;
}
public int getBits() {
return bits;
}
public QueryNegativeCounter getNegativeMask() {
return negativeMask;
}
public boolean hasNegatives() {
return negativeMask.size() > 0;
}
}