blob: 96b4dbf491b9e9ef1114036a11429387ca38923c [file] [log] [blame]
package org.apache.nifi.pql;
import static org.apache.nifi.pql.ProvenanceQueryParser.*;
import java.text.SimpleDateFormat;
import java.util.regex.Pattern;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.RegexpQuery;
import org.apache.lucene.search.TermQuery;
import org.apache.nifi.pql.evaluation.OperandEvaluator;
import org.apache.nifi.pql.evaluation.RecordEvaluator;
import org.apache.nifi.pql.evaluation.comparison.EqualsEvaluator;
import org.apache.nifi.pql.evaluation.comparison.GreaterThanEvaluator;
import org.apache.nifi.pql.evaluation.comparison.LessThanEvaluator;
import org.apache.nifi.pql.evaluation.comparison.MatchesEvaluator;
import org.apache.nifi.pql.evaluation.comparison.StartsWithEvaluator;
import org.apache.nifi.pql.evaluation.extraction.AttributeEvaluator;
import org.apache.nifi.pql.evaluation.literals.LongLiteralEvaluator;
import org.apache.nifi.pql.evaluation.literals.StringLiteralEvaluator;
import org.apache.nifi.pql.evaluation.logic.AndEvaluator;
import org.apache.nifi.pql.evaluation.logic.OrEvaluator;
import org.apache.nifi.provenance.SearchableFields;
public class LuceneTranslator {
public static Query toLuceneQuery(final RecordEvaluator<Boolean> whereClause) {
if ( whereClause == null ) {
return new MatchAllDocsQuery();
}
final BooleanQuery query = new BooleanQuery();
switch (whereClause.getEvaluatorType()) {
case AND:
final AndEvaluator and = (AndEvaluator) whereClause;
query.add(toLuceneQuery(and.getLHS()), Occur.MUST);
query.add(toLuceneQuery(and.getRHS()), Occur.MUST);
break;
case OR:
final OrEvaluator or = (OrEvaluator) whereClause;
query.add(toLuceneQuery(or.getLHS()), Occur.SHOULD);
query.add(toLuceneQuery(or.getRHS()), Occur.SHOULD);
query.setMinimumNumberShouldMatch(1);
break;
case GT: {
final GreaterThanEvaluator gt = (GreaterThanEvaluator) whereClause;
final OperandEvaluator<?> lhs = gt.getLHS();
final OperandEvaluator<?> rhs = gt.getRHS();
final String fieldName = getFieldName(lhs);
if ( fieldName != null ) {
Long rhsValue = null;
if ( rhs.getEvaluatorType() == NUMBER ) {
rhsValue = ((LongLiteralEvaluator) rhs).evaluate(null);
} else if ( rhs.getEvaluatorType() == STRING_LITERAL ) {
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
try {
rhsValue = sdf.parse(((StringLiteralEvaluator) rhs).evaluate(null)).getTime();
} catch (final Exception e) {
}
}
if ( rhsValue != null ) {
query.add(NumericRangeQuery.newLongRange(fieldName, rhsValue, Long.MAX_VALUE, true, true), Occur.MUST);
}
}
}
break;
case LT: {
final LessThanEvaluator lt = (LessThanEvaluator) whereClause;
final OperandEvaluator<?> lhs = lt.getLHS();
final OperandEvaluator<?> rhs = lt.getRHS();
final String fieldName = getFieldName(lhs);
if ( fieldName != null ) {
Long rhsValue = null;
if ( rhs.getEvaluatorType() == NUMBER ) {
rhsValue = ((LongLiteralEvaluator) rhs).evaluate(null);
} else if ( rhs.getEvaluatorType() == STRING_LITERAL ) {
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
try {
rhsValue = sdf.parse(((StringLiteralEvaluator) rhs).evaluate(null)).getTime();
} catch (final Exception e) {
}
}
if ( rhsValue != null ) {
query.add(NumericRangeQuery.newLongRange(fieldName, Long.MIN_VALUE, rhsValue, true, true), Occur.MUST);
}
}
}
break;
case MATCHES: {
final MatchesEvaluator me = (MatchesEvaluator) whereClause;
final OperandEvaluator<?> lhs = me.getLHS();
final OperandEvaluator<?> rhs = me.getRHS();
addMatches(lhs, rhs, query);
}
break;
case STARTS_WITH: {
final StartsWithEvaluator startsWith = (StartsWithEvaluator) whereClause;
final OperandEvaluator<?> lhs = startsWith.getLHS();
final OperandEvaluator<?> rhs = startsWith.getRHS();
if ( rhs.getEvaluatorType() == STRING_LITERAL ) {
final String base = rhs.evaluate(null).toString();
final StringLiteralEvaluator regexEval = new StringLiteralEvaluator(Pattern.quote(base) + ".*");
addMatches(lhs, regexEval, query);
}
}
break;
case EQUALS: {
final EqualsEvaluator equals = (EqualsEvaluator) whereClause;
final OperandEvaluator<?> lhs = equals.getLHS();
final OperandEvaluator<?> rhs = equals.getRHS();
final String fieldName = getFieldName(lhs);
if ( fieldName != null && rhs.getEvaluatorType() == STRING_LITERAL ) {
query.add(new TermQuery(new Term(fieldName, toLower(rhs.evaluate(null).toString()))), Occur.MUST);
}
}
break;
}
return query;
}
private static String toLower(final String value) {
return value == null ? null : value.toLowerCase();
}
private static String getFieldName(final OperandEvaluator<?> eval) {
switch (eval.getEvaluatorType()) {
case TIMESTAMP:
return SearchableFields.EventTime.getSearchableFieldName();
case FILESIZE:
return SearchableFields.FileSize.getSearchableFieldName();
case ATTRIBUTE:
return ((AttributeEvaluator) eval).getAttributeNameEvaluator().evaluate(null).toLowerCase();
case TRANSIT_URI:
return SearchableFields.TransitURI.getSearchableFieldName();
case RELATIONSHIP:
return SearchableFields.Relationship.getSearchableFieldName();
case TYPE:
return SearchableFields.EventType.getSearchableFieldName();
case COMPONENT_ID:
return SearchableFields.ComponentID.getSearchableFieldName();
case UUID:
return SearchableFields.FlowFileUUID.getSearchableFieldName();
}
return null;
}
private static void addMatches(final OperandEvaluator<?> lhs, final OperandEvaluator<?> rhs, final BooleanQuery query) {
String field = null;
switch (lhs.getEvaluatorType()) {
case ATTRIBUTE:
final AttributeEvaluator attr = (AttributeEvaluator) lhs;
final OperandEvaluator<?> attrEval = attr.getAttributeNameEvaluator();
if ( attrEval.getEvaluatorType() == STRING_LITERAL ) {
field = (String) attrEval.evaluate(null);
}
break;
case COMPONENT_ID:
case TRANSIT_URI:
case TYPE:
field = lhs.evaluate(null).toString();
break;
}
String regex = null;
if ( rhs.getEvaluatorType() == STRING_LITERAL ) {
regex = rhs.evaluate(null).toString();
}
if ( field != null && regex != null ) {
query.add(new RegexpQuery(new Term(field, regex)), Occur.MUST);
}
}
}