private static PrintableNode convertTermNode(final ExpressionTerm oldNode, final Set<String> fieldBlackList) {
        PrintableNode newNode;

        if (fieldBlackList != null && fieldBlackList.contains(oldNode.getField())) {
            // this term is black listed so ignore it
            newNode = null;
        } else {
            // TODO we could convert a CONTAINS ExpressionTerm to multiple
            // TermNodes contained within an OR
            // OperatorNode. e.g. if the ExpressionTerm is 'CONTAINS "apache"'
            // then we go to the UID cache to find
            // all
            // tag values that contain apache and included them all as OR
            // TermNodes. We cannot propagate partial
            // matches
            // any further down the stack as we can only filter on distinct UIDs

            if (oldNode.getCondition().equals(Condition.EQUALS)) {
                newNode = new TermNode(oldNode.getField(), Condition.EQUALS, oldNode.getValue());
            } else if (oldNode.getCondition().equals(Condition.NOT_EQUALS)) {
                newNode = new TermNode(oldNode.getField(), Condition.NOT_EQUALS, oldNode.getValue());
            } else if (oldNode.getCondition().equals(Condition.IN)) {
                if (oldNode.getValue() == null) {
                    newNode = new TermNode(oldNode.getField(), Condition.EQUALS, null);
                } else {
                    final String[] values = oldNode.getValue().split(Condition.IN_CONDITION_DELIMITER);

                    if (values.length == 1) {
                        // only one value so just convert it like it is EQUALS
                        newNode = new TermNode(oldNode.getField(), Condition.EQUALS, oldNode.getValue());
                    } else {
                        // multiple values in the IN list so convert it into a
                        // set of EQUALS terms under and OR node
                        final List<PrintableNode> orTermNodes = new ArrayList<>();

                        for (final String value : values) {
                            orTermNodes.add(convertTermNode(
                                    ExpressionTerm
                                            .builder()
                                            .field(oldNode.getField())
                                            .condition(Condition.EQUALS)
                                            .value(value)
                                            .build(),
                                    fieldBlackList));
                        }
                        newNode = new OperatorNode(FilterOperationMode.OR, orTermNodes);
                    }
                }
            } else {
                throw new UnsupportedOperationException("Only EQUALS, NOT_EQUALS and IN are currently supported");
            }
        }
        return newNode;
    }
Converts a tree of {@link ExpressionItem} objects into a
{@link FilterTermsTree}. Conversion is not exact as some features of the
{@link ExpressionItem} tree are not supported so it may throw a
{@link RuntimeException}.

@param rootItem The {@link ExpressionItem} object that is the root of the tree
@return A {@link FilterTermsTree} object containing a tree of
{@link PrintableNode} objects
stroom-statistics/stroom-statistics-impl-sql/src/main/java/stroom/statistics/impl/sql/search/FilterTermsTreeBuilder.java