首页 > 其他分享 >使用IKExpression自定义函数

使用IKExpression自定义函数

时间:2022-12-09 15:33:45浏览次数:72  
标签:java 函数 自定义 int IKExpression List return variables String

背景

  • 通过字符串匹配业务表每一条记录的部分字段,来对记录打上标签

要求

  • 规则可以配置调整
  • 规则支持复合运算、逻辑运算

开始

实现

  • 将规则放到数据库中维护
  • 从数据库中读出规则,将规则与参数作为输入到规则引擎进行计
  • 规则引擎选用IKExpression

流程

img


依赖

<!-- IKExpression -->
<dependency>
    <groupId>org.wltea.expression</groupId>
    <artifactId>IKExpression</artifactId>
    <version>2.1.2</version>
</dependency>

配置

  • IKExpression.cfg.xml:函数配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    
    <function-configuration>
    	
        <!-- 自定义字符串匹配函数 -->
        <bean class="com.wf.dev.common.util.DevStringUtils">
            <function name="CONTAINS" method="contains">
                <parameter-type>java.lang.String</parameter-type>
                <parameter-type>java.lang.String</parameter-type>
            </function>
        </bean>
    
        <!-- 系统函数默认配置 -->
        <bean class="org.wltea.expression.function.SystemFunctions">
            <function name="STARTSWITH" method="startsWith">
                <parameter-type>java.lang.String</parameter-type>
                <parameter-type>java.lang.String</parameter-type>
            </function>
            <function name="ENDSWITH" method="endsWith">
                <parameter-type>java.lang.String</parameter-type>
                <parameter-type>java.lang.String</parameter-type>
            </function>
            <function name="CALCDATE" method="calcDate">
                <parameter-type>java.util.Date</parameter-type>
                <parameter-type>int</parameter-type>
                <parameter-type>int</parameter-type>
                <parameter-type>int</parameter-type>
                <parameter-type>int</parameter-type>
                <parameter-type>int</parameter-type>
                <parameter-type>int</parameter-type>
            </function>
    
            <function name="SYSDATE" method="sysDate"/>
    
            <function name="DAYEQUALS" method="dayEquals">
                <parameter-type>java.util.Date</parameter-type>
                <parameter-type>java.util.Date</parameter-type>
            </function>
        </bean>
    
        <!-- 用户函数配置  ,请在这里定制您自己的函数-->
        <bean class="com.wf.dev.common.util.MyIkMethods">
            <function name="POWER" method="power">
                <parameter-type>double</parameter-type>
                <parameter-type>double</parameter-type>
            </function>
    
            <function name="MAX" method="max">
                <parameter-type>java.util.List</parameter-type>
            </function>
    
            <function name="MIN" method="min">
                <parameter-type>java.util.List</parameter-type>
            </function>
    
            <function name="AVERAGE" method="average">
                <parameter-type>java.util.List</parameter-type>
            </function>
    
            <function name="SUM" method="sum">
                <parameter-type>java.util.List</parameter-type>
            </function>
        </bean>
    
    </function-configuration>
    

KMP字符串匹配算法

  • 空间复杂度O(m),m表示模式串的长度。

  • 时间复杂度O(m+n),n表示子串长度。

    package com.wf.dev.common.util;
    
    /**
     * @author wf
     * @date 2022年12月08日 15:36
     * @description
     */
    public class DevStringUtils {
    
        public boolean contains(String s1, String s2) {
            if (s1 != null && s2 != null) {
                return kmp(s1.toCharArray(), s1.length(), s2.toCharArray(), s2.length()) >= 0;
            } else {
                throw new NullPointerException("函数\"CONTAINS\"参数为空");
            }
        }
    
        /**
         * a, b分别是主串和模式串;n, m分别是主串和模式串的长度。
         */
        public static int kmp(char[] a, int n, char[] b, int m) {
            int[] next = getNexts(b, m);
            int j = 0;
            for (int i = 0; i < n; ++i) {
                while (j > 0 && a[i] != b[j]) {
                    // 一直找到a[i]和b[j]
                    j = next[j - 1] + 1;
                }
                if (a[i] == b[j]) {
                    ++j;
                }
                if (j == m) {
                    // 找到匹配模式串的了
                    return i - m + 1;
                }
            }
            return -1;
        }
    
        private static int[] getNexts(char[] b, int m) {
            int[] next = new int[m];
            next[0] = -1;
            int k = -1;
            for (int i = 1; i < m; ++i) {
                while (k != -1 && b[k + 1] != b[i]) {
                    k = next[k];
                }
                if (b[k + 1] == b[i]) {
                    ++k;
                }
                next[i] = k;
            }
            return next;
        }
    }
    

代码

/**
如:【事件标题】字段中含有“暂不解决”“不处理”“没有时间”;
表达式:$CONTAINS(title, "暂不解决") || $CONTAINS(title, "不处理") || $CONTAINS(title, "没有时间")
*/

public static List<Variable> buildVariableWithMap(Map<String, Object> o) {
    if (o == null) {
        return Lists.newArrayList();
    }
    List<Variable> variables = Lists.newArrayList();

    for (String key : o.keySet()) {
        Object value = o.get(key);
        if (value instanceof Number) {
            variables.add(new Variable(key, BaseDataMeta.DataType.DATATYPE_DOUBLE, value));
        } else {
            if (value == null) {
                value = StringUtils.EMPTY;
            }
            variables.add(Variable.createVariable(key, value));
        }
    }
    return variables;
}

private boolean hit(String expression, List<Variable> variables) {
    if (StringUtils.isBlank(expression) || CollectionUtils.isEmpty(variables)) {
        return false;
    }
    try {
        return (Boolean) ExpressionEvaluator.evaluate(expression, variables);
    } catch (Exception e) {
        log.error("异常数据", e);
    }
    return false;
}

private List<Map<String, Object>> handle(List<Map<String, Object>> details, List<RuleEntity> rules) {
    for (Map<String, Object> eventDtl : details) {
        List<Variable> variables = buildVariableWithMap(eventDtl);
        for (RuleEntity ruleEntity : rules) {
            if (hit(ruleEntity.getExpression(), variables)) {
          		// do something
                break;
            }
        }
    }
}

小结

  • 自定义函数要求效率尽量高

标签:java,函数,自定义,int,IKExpression,List,return,variables,String
From: https://www.cnblogs.com/wftop1/p/16969052.html

相关文章