Search in sources :

Example 1 with Rule

use of org.knime.base.node.rules.engine.Rule in project knime-core by knime.

the class RuleEngine2PortsSimpleNodeDialog method updateErrorsAndWarnings.

/**
 * Updates the errors table, the warning text area and the computed outcome type.
 */
protected void updateErrorsAndWarnings() {
    m_errorsModel.setRowCount(0);
    hideErrors();
    m_warnings.setText("");
    m_outcomeType.setIcon(DataType.getMissingCell().getType().getIcon());
    // Checking data from second input port
    final int ruleIdx = getRules() == null ? -1 : getRules().getSpec().findColumnIndex(m_ruleColumn.getSelectedColumn());
    final int outcomeIdx = getRules() == null ? -1 : getRules().getSpec().findColumnIndex(m_outcomeColumn.getSelectedColumn());
    if (getRules() != null && isSpecAvailable() && ruleIdx >= 0) {
        RuleFactory factory = ruleFactory();
        long lineNo = 0;
        boolean wasCatchAll = false;
        final boolean firstHit = isFirstHit();
        List<Rule> rules = new ArrayList<>();
        for (DataRow dataRow : getRules()) {
            ++lineNo;
            DataCell ruleCell = dataRow.getCell(ruleIdx);
            if (ruleCell.isMissing()) {
                // String cellValue = "?";
                // if (ruleCell instanceof MissingValue) {
                // cellValue += " (" + ((MissingValue)ruleCell).getError() + ")";
                // }
                m_errorsModel.addRow(new Object[] { dataRow.getKey(), ruleCell, "Missing cell" });
                showErrors();
            }
            if (ruleCell instanceof StringValue) {
                StringValue ruleSV = (StringValue) ruleCell;
                String ruleText = ruleSV.getStringValue().replaceAll("[\r\n]+", " ");
                if (outcomeIdx >= 0) {
                    DataCell outcome = dataRow.getCell(outcomeIdx);
                    String outcomeString;
                    try {
                        outcomeString = m_settings.asStringFailForMissing(outcome);
                    } catch (InvalidSettingsException e) {
                        outcomeString = "?";
                    }
                    if (m_ruleType.onlyBooleanOutcome()) {
                        if ("\"TRUE\"".equalsIgnoreCase(outcomeString)) {
                            outcomeString = "TRUE";
                        } else if ("\"FALSE\"".equalsIgnoreCase(outcomeString)) {
                            outcomeString = "FALSE";
                        }
                    }
                    ruleText += " => " + outcomeString;
                }
                try {
                    Rule rule = factory.parse(ruleText, getDataSpec(), getAvailableFlowVariables());
                    rules.add(rule);
                    String origWarning = !m_warnings.getText().isEmpty() ? m_warnings.getText() + "\n" : "";
                    Condition cond = rule.getCondition();
                    if (cond.isEnabled()) {
                        // not comment
                        if (cond.isCatchAll() && !wasCatchAll && firstHit && lineNo < getRules().size()) {
                            m_warnings.setText(origWarning + "No rules will match after line " + lineNo + " (" + dataRow.getKey() + "). Because of rule: " + ruleText);
                        }
                        wasCatchAll |= cond.isCatchAll() && firstHit;
                        if (!wasCatchAll && cond.isConstantFalse()) {
                            m_warnings.setText(origWarning + "The rule in line " + lineNo + " (" + dataRow.getKey() + ") will never match: " + ruleText);
                        }
                    }
                } catch (ParseException e) {
                    m_errorsModel.addRow(new Object[] { dataRow.getKey(), ruleText, e.getMessage() });
                    showErrors();
                }
            } else {
                // Missings were handled previously
                if (!ruleCell.isMissing()) {
                    m_errorsModel.addRow(new Object[] { dataRow.getKey(), ruleCell.toString(), "Wrong type: " + ruleCell.getType() });
                }
            }
        }
        final DataColumnSpec outcomeSpec = m_outcomeColumn.getSelectedColumnAsSpec();
        DataType dataType = RuleEngineNodeModel.computeOutputType(rules, outcomeSpec == null ? StringCell.TYPE : outcomeSpec.getType(), m_ruleType, getSettings().isDisallowLongOutputForCompatibility());
        if (dataType != null) {
            m_outcomeType.setIcon(dataType.getIcon());
        }
    }
}
Also used : Condition(org.knime.base.node.rules.engine.Condition) RuleFactory(org.knime.base.node.rules.engine.RuleFactory) ArrayList(java.util.ArrayList) DataRow(org.knime.core.data.DataRow) DataColumnSpec(org.knime.core.data.DataColumnSpec) InvalidSettingsException(org.knime.core.node.InvalidSettingsException) DataCell(org.knime.core.data.DataCell) DataType(org.knime.core.data.DataType) PortObject(org.knime.core.node.port.PortObject) Rule(org.knime.base.node.rules.engine.Rule) ParseException(java.text.ParseException) StringValue(org.knime.core.data.StringValue)

Example 2 with Rule

use of org.knime.base.node.rules.engine.Rule in project knime-core by knime.

the class RuleEngineFilter2PortsNodeModel method parseRules.

/**
 * Parses all rules in the from the table (assuming {@link #rules()} is safe to call, like
 * {@link #createStreamableOperator(PartitionInfo, PortObjectSpec[])} or
 * {@link #execute(BufferedDataTable[], ExecutionContext)} was called before).
 *
 * @param spec the spec of the table on which the rules are applied.
 * @param nodeType The type of the node from this method is called.
 * @return a list of parsed rules
 * @throws ParseException if a rule cannot be parsed
 * @since 2.12
 */
@Override
protected List<Rule> parseRules(final DataTableSpec spec, final RuleNodeSettings nodeType) throws ParseException {
    ArrayList<Rule> rules = new ArrayList<Rule>();
    final Map<String, FlowVariable> availableFlowVariables = getAvailableFlowVariables();
    // SimpleRuleParser ruleParser = new SimpleRuleParser(spec, availableFlowVariables);
    RuleFactory factory = RuleFactory.getInstance(nodeType).cloned();
    factory.disableMissingComparisons();
    factory.disableNaNComparisons();
    int line = 0;
    for (String s : rules()) {
        ++line;
        try {
            final Rule rule = factory.parse(s, spec, availableFlowVariables);
            if (rule.getCondition().isEnabled()) {
                rules.add(rule);
            }
        } catch (ParseException e) {
            throw Util.addContext(e, s, line);
        }
    }
    return rules;
}
Also used : RuleFactory(org.knime.base.node.rules.engine.RuleFactory) ArrayList(java.util.ArrayList) Rule(org.knime.base.node.rules.engine.Rule) ParseException(java.text.ParseException) FlowVariable(org.knime.core.node.workflow.FlowVariable)

Example 3 with Rule

use of org.knime.base.node.rules.engine.Rule in project knime-core by knime.

the class RuleEngineFilter2PortsNodeModel method createStreamableOperator.

/**
 * {@inheritDoc}
 */
@Override
public StreamableOperator createStreamableOperator(final PartitionInfo partitionInfo, final PortObjectSpec[] inSpecs) throws InvalidSettingsException {
    return new StreamableOperator() {

        private SimpleStreamableOperatorInternals m_internals;

        /**
         * {@inheritDoc}
         */
        @Override
        public void loadInternals(final StreamableOperatorInternals internals) {
            m_internals = (SimpleStreamableOperatorInternals) internals;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void runIntermediate(final PortInput[] inputs, final ExecutionContext exec) throws Exception {
            // count number of rows
            long count = 0;
            RowInput rowInput = (RowInput) inputs[DATA_PORT];
            while (rowInput.poll() != null) {
                count++;
            }
            m_internals.getConfig().addLong(CFG_ROW_COUNT, count);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public StreamableOperatorInternals saveInternals() {
            return m_internals;
        }

        @Override
        public void runFinal(final PortInput[] inputs, final PortOutput[] outputs, final ExecutionContext exec) throws Exception {
            long rowCount = -1L;
            if (m_internals.getConfig().containsKey(CFG_ROW_COUNT)) {
                rowCount = m_internals.getConfig().getLong(CFG_ROW_COUNT);
            }
            m_rulesList.clear();
            final PortInput rulePort = inputs[RULE_PORT];
            if (rulePort instanceof PortObjectInput) {
                PortObjectInput poRule = (PortObjectInput) rulePort;
                m_rulesList.addAll(RuleEngineVariable2PortsNodeModel.rules((BufferedDataTable) poRule.getPortObject(), m_settings, RuleNodeSettings.RuleFilter));
            } else if (rulePort instanceof RowInput) {
                RowInput riRule = (RowInput) rulePort;
                m_rulesList.addAll(RuleEngineVariable2PortsNodeModel.rules(riRule, m_settings, RuleNodeSettings.RuleFilter));
            }
            final DataTableSpec spec = (DataTableSpec) inSpecs[DATA_PORT];
            try {
                parseRules(spec, RuleNodeSettings.RuleSplitter);
            } catch (final ParseException e) {
                throw new InvalidSettingsException(e);
            }
            final RowInput inputPartitions = (RowInput) inputs[DATA_PORT];
            final List<Rule> rules = parseRules(inputPartitions.getDataTableSpec(), RuleNodeSettings.RuleFilter);
            final RowOutput first = (RowOutput) outputs[0];
            final int nrOutPorts = getNrOutPorts();
            final RowOutput second = nrOutPorts > 1 ? (RowOutput) outputs[1] : new RowOutput() {

                @Override
                public void push(final DataRow row) throws InterruptedException {
                // do nothing
                }

                @Override
                public void close() throws InterruptedException {
                // do nothing
                }
            };
            final RowOutput[] containers = new RowOutput[] { first, second };
            final int matchIndex = m_includeOnMatch ? 0 : 1;
            final int otherIndex = 1 - matchIndex;
            try {
                final MutableLong rowIdx = new MutableLong(0L);
                final long rows = rowCount;
                final VariableProvider provider = new VariableProvider() {

                    @Override
                    public Object readVariable(final String name, final Class<?> type) {
                        return RuleEngineFilter2PortsNodeModel.this.readVariable(name, type);
                    }

                    @Override
                    @Deprecated
                    public int getRowCount() {
                        throw new UnsupportedOperationException();
                    }

                    @Override
                    public long getRowCountLong() {
                        return rows;
                    }

                    @Override
                    @Deprecated
                    public int getRowIndex() {
                        throw new UnsupportedOperationException();
                    }

                    @Override
                    public long getRowIndexLong() {
                        return rowIdx.longValue();
                    }
                };
                DataRow row;
                while ((row = inputPartitions.poll()) != null) {
                    rowIdx.increment();
                    if (rows > 0) {
                        exec.setProgress(rowIdx.longValue() / (double) rows, () -> "Adding row " + rowIdx.longValue() + " of " + rows);
                    } else {
                        exec.setMessage(() -> "Adding row " + rowIdx.longValue() + " of " + rows);
                    }
                    exec.checkCanceled();
                    boolean wasMatch = false;
                    for (Rule r : rules) {
                        if (r.getCondition().matches(row, provider).getOutcome() == MatchState.matchedAndStop) {
                            // r.getSideEffect().perform(row, provider);
                            DataValue value = r.getOutcome().getComputedResult(row, provider);
                            if (value instanceof BooleanValue) {
                                final BooleanValue bv = (BooleanValue) value;
                                containers[bv.getBooleanValue() ? matchIndex : otherIndex].push(row);
                            } else {
                                containers[matchIndex].push(row);
                            }
                            wasMatch = true;
                            break;
                        }
                    }
                    if (!wasMatch) {
                        containers[otherIndex].push(row);
                    }
                }
            } finally {
                try {
                    second.close();
                } finally {
                    first.close();
                }
            }
        }
    };
}
Also used : DataTableSpec(org.knime.core.data.DataTableSpec) DataValue(org.knime.core.data.DataValue) StreamableOperator(org.knime.core.node.streamable.StreamableOperator) StreamableOperatorInternals(org.knime.core.node.streamable.StreamableOperatorInternals) SimpleStreamableOperatorInternals(org.knime.core.node.streamable.simple.SimpleStreamableOperatorInternals) DataTableRowInput(org.knime.core.node.streamable.DataTableRowInput) RowInput(org.knime.core.node.streamable.RowInput) DataRow(org.knime.core.data.DataRow) PortObjectInput(org.knime.core.node.streamable.PortObjectInput) RowAppenderRowOutput(org.knime.base.node.rules.engine.RowAppenderRowOutput) BufferedDataTableRowOutput(org.knime.core.node.streamable.BufferedDataTableRowOutput) RowOutput(org.knime.core.node.streamable.RowOutput) VariableProvider(org.knime.base.node.rules.engine.VariableProvider) BooleanValue(org.knime.core.data.BooleanValue) BufferedDataTable(org.knime.core.node.BufferedDataTable) PortInput(org.knime.core.node.streamable.PortInput) SimpleStreamableOperatorInternals(org.knime.core.node.streamable.simple.SimpleStreamableOperatorInternals) MutableLong(org.apache.commons.lang3.mutable.MutableLong) ExecutionContext(org.knime.core.node.ExecutionContext) InvalidSettingsException(org.knime.core.node.InvalidSettingsException) ParseException(java.text.ParseException) Rule(org.knime.base.node.rules.engine.Rule)

Example 4 with Rule

use of org.knime.base.node.rules.engine.Rule in project knime-core by knime.

the class RuleEngineVariable2PortsNodeModel method computeOutputType.

/**
 * Computes the result's {@link DataType}.
 *
 * @param rules The rules.
 * @return The common base type of the outcomes.
 */
static DataType computeOutputType(final List<Rule> rules, final DataType columnType) {
    // determine output type
    List<DataType> types = new ArrayList<DataType>();
    // add outcome column types
    for (Rule r : rules) {
        types.add(r.getOutcome().getType());
    }
    final DataType outType;
    if (types.size() > 0) {
        DataType temp = types.get(0);
        for (int i = 1; i < types.size(); i++) {
            temp = DataType.getCommonSuperType(temp, types.get(i));
        }
        if ((temp.getValueClasses().size() == 1) && temp.getValueClasses().contains(DataValue.class)) {
            // a non-native type, we replace it with string
            temp = StringCell.TYPE;
        }
        outType = temp;
    } else {
        outType = columnType;
    }
    return outType;
}
Also used : DataValue(org.knime.core.data.DataValue) ArrayList(java.util.ArrayList) DataType(org.knime.core.data.DataType) Rule(org.knime.base.node.rules.engine.Rule)

Example 5 with Rule

use of org.knime.base.node.rules.engine.Rule in project knime-core by knime.

the class RuleEngineVariable2PortsNodeModel method performExecute.

/**
 * Creates the flow variable according to the computed value.
 *
 * @param rules The rules to check for match.
 * @throws InvalidSettingsException When there is an error in the settings.
 */
private void performExecute(final List<Rule> rules, final DataType outcomeColumnType) throws InvalidSettingsException {
    String newFlowVar = m_newVariableName;
    if (newFlowVar == null || newFlowVar.isEmpty()) {
        newFlowVar = DEFAULT_VARIABLE_NAME;
    }
    final DataType outType = computeOutputType(rules, outcomeColumnType);
    final VariableProvider provider = new VariableProvider() {

        @Override
        public Object readVariable(final String name, final Class<?> type) {
            return RuleEngineVariable2PortsNodeModel.this.readVariable(name, type);
        }

        @Override
        @Deprecated
        public int getRowCount() {
            throw new IllegalStateException("Row count is not available.");
        }

        @Override
        public long getRowCountLong() {
            throw new IllegalStateException("Row count is not available.");
        }

        @Override
        @Deprecated
        public int getRowIndex() {
            throw new IllegalStateException("Row index is not available.");
        }

        @Override
        public long getRowIndexLong() {
            throw new IllegalStateException("Row index is not available.");
        }
    };
    boolean wasMatch = false;
    for (Rule r : rules) {
        if (r.getCondition().matches(null, provider).getOutcome() == MatchState.matchedAndStop) {
            Outcome outcome2 = r.getOutcome();
            // r.getSideEffect().perform(row, this);
            final DataCell cell = (DataCell) outcome2.getComputedResult(null, provider);
            wasMatch = true;
            if (outType.equals(StringCell.TYPE) && !cell.isMissing() && !cell.getType().equals(StringCell.TYPE)) {
                pushFlowVariableString(newFlowVar, cell.toString());
                break;
            } else {
                if (cell.isMissing()) {
                    throw new UnsupportedOperationException("Missing result, TODO");
                }
                if (outType.equals(IntCell.TYPE)) {
                    pushFlowVariableInt(newFlowVar, ((IntValue) cell).getIntValue());
                    break;
                } else if (outType.equals(DoubleCell.TYPE)) {
                    pushFlowVariableDouble(newFlowVar, ((DoubleValue) cell).getDoubleValue());
                    break;
                } else if (outType.equals(StringCell.TYPE)) {
                    pushFlowVariableString(newFlowVar, ((StringValue) cell).getStringValue());
                    break;
                } else {
                    // TODO
                    throw new UnsupportedOperationException("Wrong type: " + cell.getClass());
                }
            }
        }
    }
    if (!wasMatch) {
        if (outType.equals(StringCell.TYPE)) {
            pushFlowVariableString(newFlowVar, "");
        } else if (outType.equals(IntCell.TYPE)) {
            pushFlowVariableInt(newFlowVar, 0);
        } else {
            pushFlowVariableDouble(newFlowVar, 0.0);
        }
    }
}
Also used : DoubleValue(org.knime.core.data.DoubleValue) VariableProvider(org.knime.base.node.rules.engine.VariableProvider) FlowVariableProvider(org.knime.ext.sun.nodes.script.calculator.FlowVariableProvider) Outcome(org.knime.base.node.rules.engine.Rule.Outcome) DataType(org.knime.core.data.DataType) DataCell(org.knime.core.data.DataCell) Rule(org.knime.base.node.rules.engine.Rule)

Aggregations

Rule (org.knime.base.node.rules.engine.Rule)8 ParseException (java.text.ParseException)5 ArrayList (java.util.ArrayList)5 RuleFactory (org.knime.base.node.rules.engine.RuleFactory)4 DataType (org.knime.core.data.DataType)4 VariableProvider (org.knime.base.node.rules.engine.VariableProvider)3 DataCell (org.knime.core.data.DataCell)3 DataRow (org.knime.core.data.DataRow)3 InvalidSettingsException (org.knime.core.node.InvalidSettingsException)3 PortObject (org.knime.core.node.port.PortObject)3 MutableLong (org.apache.commons.lang3.mutable.MutableLong)2 DataTableSpec (org.knime.core.data.DataTableSpec)2 DataValue (org.knime.core.data.DataValue)2 StringValue (org.knime.core.data.StringValue)2 BufferedDataTable (org.knime.core.node.BufferedDataTable)2 FlowVariable (org.knime.core.node.workflow.FlowVariable)2 FlowVariableProvider (org.knime.ext.sun.nodes.script.calculator.FlowVariableProvider)2 SimpleRule (org.dmg.pmml.SimpleRuleDocument.SimpleRule)1 Condition (org.knime.base.node.rules.engine.Condition)1 RowAppenderRowOutput (org.knime.base.node.rules.engine.RowAppenderRowOutput)1