use of datawave.query.jexl.lookups.ValueSet in project datawave by NationalSecurityAgency.
the class JexlNodeFactory method createNodeTreeFromFieldsToValues.
/**
* Expand a node given a mapping of fields to values. If the list is empty, then the original regex should be used.
*
* @param containerType
* should we create OR nodes or AND nodes
* @param node
* @param fieldsToValues
* A mapping of fields to values. If the values for a field is empty, then the original regex should be used.
* @param expandFields
* Expand fields if true
* @param expandValues
* Expand values if true
* @param keepOriginalNode
* Keep the original node along with any expansions
* @return A new sub query
*/
public static JexlNode createNodeTreeFromFieldsToValues(ContainerType containerType, JexlNode node, JexlNode orgNode, IndexLookupMap fieldsToValues, boolean expandFields, boolean expandValues, boolean keepOriginalNode) {
// do nothing if not expanding fields or values
if (!expandFields && !expandValues) {
return orgNode;
}
// no expansions needed if the fieldname threshold is exceeded
if (fieldsToValues.isKeyThresholdExceeded()) {
return new ExceededTermThresholdMarkerJexlNode(orgNode);
}
// collapse the value sets if not expanding fields
if (!expandFields) {
ValueSet allValues = new ValueSet(-1);
for (ValueSet values : fieldsToValues.values()) {
allValues.addAll(values);
}
fieldsToValues.clear();
for (String identifier : JexlASTHelper.getIdentifierNames(orgNode)) {
fieldsToValues.put(identifier, allValues);
}
}
Set<String> fields = fieldsToValues.keySet();
JexlNode parentNode = (containerType.equals(ContainerType.OR_NODE) ? new ASTOrNode(ParserTreeConstants.JJTORNODE) : new ASTAndNode(ParserTreeConstants.JJTANDNODE));
int parentNodeChildCount = 0;
if (keepOriginalNode) {
JexlNodes.ensureCapacity(parentNode, fields.size() + 1);
JexlNode child = RebuildingVisitor.copy(orgNode);
parentNode.jjtAddChild(child, parentNodeChildCount);
child.jjtSetParent(parentNode);
parentNodeChildCount++;
// remove this entry from the fieldsToValues to avoid duplication
for (String identifier : JexlASTHelper.getIdentifierNames(orgNode)) {
for (Object value : JexlASTHelper.getLiteralValues(orgNode)) {
fieldsToValues.remove(identifier, value);
}
}
} else {
JexlNodes.ensureCapacity(parentNode, fields.size());
}
for (String field : fields) {
ValueSet valuesForField = fieldsToValues.get(field);
// if not expanding values, then reuse the original node with simply a new field name (anyfield only)
if (!expandValues) {
JexlNode child = RebuildingVisitor.copy(orgNode);
for (ASTIdentifier identifier : JexlASTHelper.getIdentifiers(child)) {
if (identifier.image.equals(Constants.ANY_FIELD)) {
identifier.image = field;
}
}
parentNode.jjtAddChild(child, parentNodeChildCount);
child.jjtSetParent(parentNode);
parentNodeChildCount++;
} else // node with a new fieldname, wrapped with a marker node
if (valuesForField.isThresholdExceeded()) {
// create a set of nodes wrapping each pattern
List<String> patterns = new ArrayList<>(fieldsToValues.getPatterns() == null ? new ArrayList<>() : fieldsToValues.getPatterns());
if (patterns.isEmpty()) {
JexlNode child = new ExceededValueThresholdMarkerJexlNode(buildUntypedNode(orgNode, field));
parentNode.jjtAddChild(child, parentNodeChildCount);
child.jjtSetParent(parentNode);
parentNodeChildCount++;
} else if (patterns.size() == 1) {
JexlNode child = new ExceededValueThresholdMarkerJexlNode(buildUntypedNode(orgNode, field, patterns.get(0)));
parentNode.jjtAddChild(child, parentNodeChildCount);
child.jjtSetParent(parentNode);
parentNodeChildCount++;
} else {
int childNodeChildCount = 0;
JexlNode childNode = (containerType.equals(ContainerType.OR_NODE) ? new ASTOrNode(ParserTreeConstants.JJTORNODE) : new ASTAndNode(ParserTreeConstants.JJTANDNODE));
JexlNodes.ensureCapacity(childNode, patterns.size());
for (String pattern : patterns) {
JexlNode child = new ExceededValueThresholdMarkerJexlNode(buildUntypedNode(orgNode, field, pattern));
childNode.jjtAddChild(child, childNodeChildCount);
child.jjtSetParent(childNode);
childNodeChildCount++;
}
if (0 < childNodeChildCount) {
JexlNode wrappedChildNode = wrap(childNode);
childNode.jjtSetParent(wrappedChildNode);
parentNode.jjtAddChild(wrappedChildNode, parentNodeChildCount);
childNode.jjtSetParent(childNode);
parentNodeChildCount++;
}
}
} else // Don't create an OR if we have only one value, directly attach it
if (1 == valuesForField.size()) {
JexlNode child = buildUntypedNode(node, field, valuesForField.iterator().next());
parentNode.jjtAddChild(child, parentNodeChildCount);
child.jjtSetParent(parentNode);
parentNodeChildCount++;
} else {
int childNodeChildCount = 0;
JexlNode childNode = (containerType.equals(ContainerType.OR_NODE) ? new ASTOrNode(ParserTreeConstants.JJTORNODE) : new ASTAndNode(ParserTreeConstants.JJTANDNODE));
JexlNodes.ensureCapacity(childNode, valuesForField.size());
for (String value : valuesForField) {
JexlNode child = buildUntypedNode(node, field, value);
childNode.jjtAddChild(child, childNodeChildCount);
child.jjtSetParent(childNode);
childNodeChildCount++;
}
if (0 < childNodeChildCount) {
JexlNode wrappedChildNode = wrap(childNode);
childNode.jjtSetParent(wrappedChildNode);
parentNode.jjtAddChild(wrappedChildNode, parentNodeChildCount);
childNode.jjtSetParent(childNode);
parentNodeChildCount++;
}
}
}
switch(parentNodeChildCount) {
case 0:
// in this case we had no matches for the range, so this expression gets replaced with a FALSE node.
return new ASTFalseNode(ParserTreeConstants.JJTFALSENODE);
case 1:
JexlNode child = parentNode.jjtGetChild(0);
JexlNodes.promote(parentNode, child);
return child;
default:
JexlNode wrappedParentNode = wrap(parentNode);
parentNode.jjtSetParent(wrappedParentNode);
return wrappedParentNode;
}
}
Aggregations