Rhythmix(流式数据规则表达式),一行就够了!

Rhythmix(流式数据规则表达式),一行就够了!

今天给大家分享一个我最近开源的 Java 库 ------ Rhythmix,一个简单而强大的流式数据规则表达式库。如果你正在做实时数据监控、异常检测、IoT 数据处理等场景,这个库绝对能帮你省下不少代码!

视频概览讲解:www.bilibili.com/video/BV1S3...

详细文档(有疑问可以看看这个):github.com/MFinnnne/rh...

🎵 什么是 Rhythmix?

在实际开发中,我们经常会遇到这样的需求:

  • 🌡️ 温度监控:当温度连续 3 次超过 30°C 时触发告警
  • 🏭 生产线质量控制:检测产品重量是否在 [95,105] 克范围内
  • 🌐 网络监控:API 响应时间连续 5 次超过 1000ms 时发送通知
  • 💰 金融风控:检测异常交易模式,如金额突然从低到高的状态转换

让我们看看这个复杂的状态机需求:某个数值依次要满足 先大于1 → 然后累计3次小于1 → 最后等于3

传统的做法是什么?写一堆 if-else,维护各种状态变量,代码又臭又长。

java 复制代码
// 传统写法:需要维护多个状态变量和复杂的状态机逻辑
enum State { INIT, HIGH_LOAD, COUNTING_LOW, STABLE }
State currentState = State.INIT;
int lowLoadCount = 0;

for (Data data : dataList) {
    double value = data.getValue();

    switch (currentState) {
        case INIT:
            if (value > 1) {
                currentState = State.HIGH_LOAD;
            }
            break;
        case HIGH_LOAD:
            if (value < 1) {
                currentState = State.COUNTING_LOW;
                lowLoadCount = 1;
            }
            break;
        case COUNTING_LOW:
            if (value < 1) {
                lowLoadCount++;
                if (lowLoadCount >= 3) {
                    currentState = State.STABLE;
                }
            } else {
                // 中断了,回到高负载状态
                currentState = State.HIGH_LOAD;
                lowLoadCount = 0;
            }
            break;
        case STABLE:
            if (value == 3) {
                // 检测成功!
                return true;
            }
            break;
    }
}

// Rhythmix 写法:一行表达式搞定复杂状态机!
String expression = "{>1}->{count(<1,3)}->{==3}";
RhythmixExecutor executor = RhythmixCompiler.compile(expression);
boolean result = executor.execute(dataList);

表达式解读

  • {>1} → 第一个状态单元:值大于 1(高负载)

  • {count(<1,3)} → 第二个状态单元:累计 3 次值小于 1(低负载计数)

  • {==3} → 第三个状态单元:值等于 3(稳定状态)

    看到了吗?40+ 行的复杂状态机代码,用 Rhythmix 一行表达式就搞定了! 这就是 Rhythmix 的魅力所在!下面的动图展示了表达式的运行过程:

💡 什么是"状态单元"?

在 Rhythmix 中,状态单元(State Unit) 是表达式的基本组成部分。每个用 {} 包裹的条件就是一个状态单元。

Rhythmix 的灵活性在于:你既可以使用完整的状态转换表达式,也可以使用单个状态单元!

java 复制代码
// 方式一:使用单个状态单元(简单场景)
String expression1 = ">30";                                   // 基础比较状态单元
String expression2 = "count!(>30,3)";                         // 计数状态单元
String expression3 = "[95,105]";                              // 区间状态单元
String expression4 = "filter(>0).window(5).avg().meet(>50)"; // 链式表达式状态单元

// 方式二:使用状态转换表达式(组合多个状态单元)
String expression5 = "{>1}->{count(<1,3)}->{==3}";           // 三个状态单元的转换
String expression6 = "{<=40}->{>80}";                         // 两个状态单元的转换
String expression7 = "{[95,105]}->{(0,95)||(105,200)}";     // 组合逻辑运算的状态单元
String expression8 = "{>0}->{filter(>5).window(3).avg().meet(>10)}"; // 组合链式表达式状态单元

状态单元的类型

  • 📌 基础比较>30<10==5<=,>=
  • 📌 区间表达式[95,105](20,30)
  • 📌 逻辑运算<10||>40>=20&&<=30
  • 📌 状态函数count(>4,3)count!(>4,3)
  • 📌 链式表达式filter().window().avg().meet()

选择建议

  • 🎯 简单判断 → 使用单个状态单元(如 >30
  • 🔄 状态转换 → 组合多个状态单元(如 {>1}->{<1}
  • 📊 复杂数据处理 → 使用链式表达式状态单元(如 filter().window().avg()

🚀 快速上手

1. 添加依赖

在你的 pom.xml 中添加:

xml 复制代码
<dependency>
    <groupId>io.github.mfinnnne</groupId>
    <artifactId>rhythmix</artifactId>
    <version>1.0.1</version>
</dependency>

2. 三步走,轻松使用

java 复制代码
// 第一步:编译表达式
String expression = "count(>4,3)";
RhythmixExecutor executor = RhythmixCompiler.compile(expression);

// 第二步:创建事件数据
RhythmixEventData data1 = new RhythmixEventData("event1", "5", new Timestamp(System.currentTimeMillis()));
RhythmixEventData data2 = new RhythmixEventData("event2", "6", new Timestamp(System.currentTimeMillis()));
RhythmixEventData data3 = new RhythmixEventData("event3", "7", new Timestamp(System.currentTimeMillis()));

// 第三步:执行表达式
boolean result = executor.execute(data1); // 返回 false
boolean result = executor.execute(data2); // 返回 false
boolean result = executor.execute(data3); // 返回 true

就这么简单!三步搞定一个规则判断。

💡 核心功能详解

1. 基础比较运算符(最简单的状态单元)

支持所有常见的比较操作:

java 复制代码
">30"           // 大于 30
"<10"           // 小于 10
">=100"         // 大于等于 100
"<=50"          // 小于等于 50
"==25"          // 等于 25
"!=0"           // 不等于 0

实际应用场景

  • 温度监控:>30 检测高温告警
  • 库存管理:<10 检测库存不足
  • 错误过滤:!=0 排除错误值

2. 区间表达式

支持四种区间类型:

java 复制代码
"(20,25)"       // 开区间:20 < x < 25
"(20,25]"       // 左开右闭:20 < x ≤ 25
"[20,25)"       // 左闭右开:20 ≤ x < 25
"[20,25]"       // 闭区间:20 ≤ x ≤ 25

实际应用场景

  • 质量控制:[95,105] 产品重量规格检测
  • 网络延迟:[0,500) 正常响应时间范围
  • 温度控制:(20,30) 舒适温度区间

3. 逻辑运算符

组合多个条件,实现复杂逻辑:

java 复制代码
"<10||>40"                  // 或:太冷或太热
">=20&&<=30"                // 与:正常范围
"((1,7]||>10)&&!=5"         // 复杂组合

实际应用场景

  • 异常检测:<10||>40 温度异常(过冷或过热)
  • 正常范围:>=20&&<=30 温度在正常范围内
  • 排除错误码:!=0&&!=(-1) 排除多个错误值

4. 状态单元函数

count() - 非连续计数

计数器会持续累加,即使条件不满足也不会重置:

java 复制代码
"count(>4,3)"   // 统计 3 次大于 4 的值(可以不连续)

行为示例

arduino 复制代码
数据流:5, 2, 6, 1, 7
计数:  1, 1, 2, 2, 3 ✓  (第 5 个数据时返回 true)
count!() - 连续计数

计数器在条件不满足时会重置为 0:

java 复制代码
"count!(>4,3)"  // 统计连续 3 次大于 4 的值

行为示例

arduino 复制代码
数据流:5, 2, 6, 7, 8
计数:  1, 0, 1, 2, 3 ✓  (需要连续 3 次才返回 true)

5. 链式表达式(特殊的状态单元)

链式表达式本身也是一种状态单元!它可以构建复杂的数据处理管道:

java 复制代码
"filter(>0).window(3).avg().meet(>50)"
// 过滤正值 → 取最近 3 个 → 计算平均值 → 检查是否大于 50

链式组件详解

  • filter(): 数据过滤

    java 复制代码
    "filter(>0)"              // 保留正值
    "filter([0,100])"         // 保留范围内的值
  • limit(): 队列管理

    java 复制代码
    "limit(10)"               // 保留最近 10 个值
    "limit(100ms)"            // 保留最近 100 毫秒的数据
    "limit(5s)"               // 保留最近 5 秒的数据

    ⚠️ 与 window 函数的使用限制: 不可以用同时使用 limit 和 window 函数

  • window(): 滑动窗口

    java 复制代码
    "window(5)"               // 5 个值的滑动窗口
    "window(100ms)"           // 100 毫秒的时间窗口

    🔄 自动 limit 函数添加:

    • 当表达式中只有 window 函数而没有 limit 函数时,系统会自动添加一个与 window 参数相同的 limit 函数
    • 这确保了数据队列管理的一致性和内存使用的优化
  • 计算器: 聚合计算

    java 复制代码
    "sum()"                   // 求和
    "avg()"                   // 平均值
    "count()"                 // 计数
    "stddev()"                // 标准差
  • meet(): 条件检查

    java 复制代码
    "meet(>10)"               // 结果大于 10
    "meet([5,50])"            // 结果在范围内

实际应用场景

java 复制代码
// 温度监控:最近 5 个正值的平均温度是否超过 50°C
"filter(>0).window(5).avg().meet(>50)"

// 质量控制:最近 20 个产品中,取最近 10 个的平均重量是否在 [98,102] 范围内
"filter([95,105]).limit(20).window(10).avg().meet([98,102])"

// 网络监控:最近 100ms 内正值的总和是否大于等于 7
"filter(>0).window(100ms).sum().meet(>=7)"

🔧 自定义函数(扩展链式表达式)

Rhythmix 支持自定义函数来扩展链式表达式的能力,让你可以实现特定业务逻辑!

三种自定义函数类型

1. 自定义过滤器(FilterUDF)

实现自己的数据过滤逻辑:

java 复制代码
public class TemperatureFilterUDF implements ChainFilterUDF {
    @Override
    public String getName() {
        return "tempFilter"; // 函数名称
    }

    @Override
    public boolean filter(EventData event) {
        double temp = Double.parseDouble(event.getValue());
        return temp >= 20.0 && temp <= 80.0; // 保留 20-80 度的数据
    }
}

// 在表达式中使用
"tempFilter().sum().meet(>100)"

2. 自定义计算器(CalculatorUDF)

实现自己的数据计算逻辑:

java 复制代码
public class MaxCalculator implements ChainCalculatorUDF {
    @Override
    public String getName() {
        return "myMax"; // 函数名称
    }

    @Override
    public Number calculate(List<EventData> values) {
        // 找出最大值
        return values.stream()
            .mapToDouble(v -> Double.parseDouble(v.getValue()))
            .max()
            .orElse(0);
    }
}

// 在表达式中使用
"filter(>0).myMax().meet(>100)"

3. 自定义条件判断(MeetUDF)

实现自己的条件判断逻辑:

java 复制代码
public class CustomThresholdMeetUDF implements ChainMeetUDF {
    @Override
    public String getName() {
        return "customMeet"; // 函数名称
    }

    @Override
    public boolean meet(Number calculatedValue) {
        double value = calculatedValue.doubleValue();
        // 自定义判断:值必须是偶数且大于 10
        return value > 10 && value % 2 == 0;
    }
}

// 在表达式中使用
"filter(>0).sum().customMeet()"

💡 使用说明

  • 自定义函数会被系统自动发现和注册,无需手动配置
  • 函数名称必须唯一
  • 可以在链式表达式的任意位置使用自定义函数
  • 支持与内置函数混合使用

实际应用示例

java 复制代码
// 组合使用:自定义过滤 + 内置计算 + 自定义判断
"tempFilter().window(5).avg().customMeet()"

// 复杂业务逻辑:多个自定义函数组合
"tempFilter().limit(10).myMax().customMeet()"

🔄 状态单元的使用方式

前面介绍了 5 种类型的状态单元,现在来看看如何使用它们:

方式一:单独使用状态单元

最简单的方式,直接使用一个状态单元进行判断:

java 复制代码
// 基础比较
String expression1 = ">30";

// 区间判断
String expression2 = "[95,105]";

// 计数判断
String expression3 = "count!(>30,3)";

// 链式表达式
String expression4 = "filter(>0).window(5).avg().meet(>50)";

方式二:状态转换(组合多个状态单元)

这是 Rhythmix 最强大的功能!通过 -> 连接多个状态单元,构建复杂的状态机。

语法格式{状态单元1}->{状态单元2}->{状态单元3}...

java 复制代码
// 两个状态的转换
"{<=40}->{>80}"                     // 从正常温度到过热

// 三个状态的转换
"{>1}->{count(<1,3)}->{==3}"       // 高负载 → 3次低负载 → 稳定

// 复杂状态单元的组合
"{==0}->{count!(>4,3)}"             // 从空闲到活跃(连续3次高值)
"{[95,105]}->{(0,95)||(105,200)}"  // 从合格到不合格(带逻辑运算)

// 链式表达式也可以作为状态单元
"{>0}->{filter(>5).window(3).avg().meet(>10)}"

核心概念

  • 每个 {} 包裹的条件都是一个状态单元
  • 使用 -> 连接状态单元,表示状态转换
  • 只有当前状态满足后,才会进入下一个状态
  • 最后一个状态满足时,整个表达式返回 true

实际应用场景

  • 设备监控:检测设备从正常状态突然进入异常状态
  • 生产线:检测从空闲状态进入生产状态
  • 质量控制:检测产品质量从合格变为不合格
  • 用户行为:检测用户从浏览到购买的转化路径

🌟 真实场景应用

我在项目中准备了 15+ 个真实场景的测试用例,涵盖了各行各业:

1. 智能家居 - 温度控制

java 复制代码
// 场景:温度连续 3 次超过 26°C 时开启空调
String expression = "count!(>26,3)";

2. 制造业 - 生产线质量控制

java 复制代码
// 场景:产品重量从合格范围突然变为不合格
String expression = "{[95,105]}->{(0,95)||(105,200)}";

3. 网络监控 - API 响应时间

java 复制代码
// 场景:检测 2 次慢响应(>1000ms)
String expression = "count(>1000,2)";

4. 医疗健康 - 心率监控

java 复制代码
// 场景:心率从正常范围突然进入异常范围
String expression = "{[60,100]}->{<50||>120}";

5. 金融风控 - 欺诈检测

java 复制代码
// 场景:交易金额从小额突然变为大额
String expression = "{<100}->{>10000}";

6. 环境监测 - 空气质量

java 复制代码
// 场景:PM2.5 连续 5 次超标(>75)
String expression = "count!(>75,5)";

7. 数据中心 - CPU 监控

java 复制代码
// 场景:最近 5 个 CPU 使用率的平均值超过 80%
String expression = "filter(>0).window(5).avg().meet(>80)";

📊 性能与优势

为什么选择 Rhythmix?

  1. 简洁优雅:一行表达式替代几十行代码
  2. 易于维护:规则变更只需修改表达式字符串
  3. 功能强大:支持复杂的状态转换和链式处理
  4. 零依赖:轻量级,不引入额外依赖

对比传统方案

特性 传统代码 Rhythmix
代码量 N 行 1 行
可读性 优秀
维护性 困难 简单
灵活性
学习成本

🎯 最佳实践

1. 选择合适的表达式类型

  • 简单阈值检测 → 使用基础比较运算符
  • 范围验证 → 使用区间表达式
  • 模式检测 → 使用计数函数
  • 复杂聚合 → 使用链式表达式

2. 性能优化建议

  • 使用 limit() 防止内存占用过大
  • 使用 window() 进行滑动窗口计算
  • 在链式表达式中尽早使用 filter() 过滤数据

3. 测试建议

  • 测试边界值(临界情况)
  • 测试状态转换
  • 使用真实数据模式进行测试

📦 项目资源

🚀 未来计划

Rhythmix 还在持续进化中!以下是我们计划中的新特性,欢迎大家提出建议和反馈!

1. 🎨 状态单元函数自定义

目标:让用户可以自定义状态单元级别的函数,而不仅仅是链式表达式中的函数。

应用场景

java 复制代码
// 自定义状态单元函数
"customStateFunc(>10,3)" // 类似 count,但有自己的逻辑

// 在状态转换中使用
"{customStateFunc(>10,3)}->{<5}"

预期收益

  • ✅ 更灵活的状态检测逻辑
  • ✅ 可复用的业务规则封装
  • ✅ 更强的表达能力

2. 🔗 多事件源支持

目标:支持同时监控多个数据源,实现跨传感器的复杂规则判断。

语法设计(征求意见中):

方案一:使用花括号嵌套

java 复制代码
// a 和 b 是不同传感器的别名
{{a:==0}&&{b:==1}}

// 实际应用:温度传感器正常且湿度传感器异常
{{temp:<30}&&{humidity:>80}}

方案二:使用竖线分隔

java 复制代码
// 使用 | 作为事件源标识符
{|a:==0|&&|b:==1|}

// 实际应用
{|temp:<30|&&|humidity:>80|}

💬 你更喜欢哪种语法?欢迎在评论区留言!

应用场景

  • 🏭 工业监控:同时监控温度、压力、振动多个传感器
  • 🏠 智能家居:联动多个设备的状态(门窗、烟雾、温度)
  • 🌐 网络监控:关联多个服务的健康状态
  • 💰 金融风控:综合多个指标判断风险

示例

java 复制代码
// 当温度传感器超标且压力传感器异常时触发告警
{{temp:>80}&&{pressure:>150}}

// 门窗打开且烟雾检测到异常
{{door:==1}&&{smoke:>50}}

// 三个传感器的复杂组合
{{a:>10}&&{b:<5}||{c:[20,30]}}

3. 🛡️ 高可用支持

目标:确保系统在故障恢复后能够继续正确工作,不丢失状态。

实现方案

  • 📮 消息队列集成:接入 Kafka、RabbitMQ 等消息队列
  • 💾 状态持久化:使用 Redis 或数据库保存表达式执行状态
  • 🔄 故障恢复:系统重启后自动恢复到故障前的状态

应用场景

java 复制代码
// 生产环境中的关键监控
// 即使系统重启,也能继续追踪"连续3次异常"的状态
count!(>80, 3)

// 复杂状态转换不会因为宕机而重置
{[20,30]}->{count!(>50,5)}->{<10}

预期收益

  • ✅ 生产环境可靠性大幅提升
  • ✅ 支持分布式部署
  • ✅ 数据不丢失,状态可恢复

4. 🎯 其他规划中的特性

  • 📈 性能监控面板:实时查看表达式执行情况
  • 🔌 更多内置函数:中位数、百分位数、移动平均等

💡 你的想法很重要!

如果你有任何建议或想法,欢迎:

  • 💬 在评论区留言讨论
  • 🐛 在 GitHub 提交 Issue
  • 🤝 提交 Pull Request 参与贡献

让我们一起让 Rhythmix 变得更强大!🎵

🎉 总结

Rhythmix 是一个专为流式数据处理设计的规则表达式引擎,它让复杂的事件处理变得简单而优雅。无论你是在做 IoT 数据处理、实时监控、异常检测,还是质量控制,Rhythmix 都能帮你大幅简化代码,提高开发效率。

如果你觉得这个项目对你有帮助,欢迎:

  • ⭐ 给项目点个 Star
  • 🐛 提交 Issue 和 PR
  • 💬 分享给更多的开发者

最后,附上项目地址:github.com/MFinnnne/rh...

让我们一起用 Rhythmix 让代码更优雅! 🎵

我不知道我开源这个玩意可以干嘛,思考再三还是开源了出来,或许只是自我感动吧,毕竟工作中你写了这些也不会有人买单,但是自我感动也算是感动吧。愿各位猿真的能心有花朵吧


作者:MFine GitHub: @MFinnnne 标签:#Java #开源 #流式处理 #规则引擎 #实时监控

相关推荐
FREE技术7 分钟前
山区农产品售卖系统
java·spring boot
亚远景aspice32 分钟前
亚远景热烈祝贺保隆科技通过ASPICE CL2评估
大数据·人工智能·物联网
星光一影38 分钟前
Java医院管理系统HIS源码带小程序和安装教程
java·开发语言·小程序
塔能物联运维1 小时前
物联网系统数字孪生驱动的预测性维护技术解析
物联网
YA3331 小时前
java设计模式七、代理模式
java·设计模式·代理模式
helloworddm1 小时前
Orleans 自定义二进制协议在 TCP 上层实现的完整过程
java·网络协议·tcp/ip
qqxhb2 小时前
系统架构设计师备考第55天——数据库设计融合&物联网层次架构&案例分析
数据库·物联网·系统架构·orm·网络层·感知层·平台应用层
单片机专业性2 小时前
硬件电路5V过压保护分析
单片机·嵌入式硬件·物联网·电路设计
超级大只老咪2 小时前
蓝桥杯知识点大纲(JavaC组)
java·算法·蓝桥杯
Yiii_x2 小时前
如何使用IntelliJ IDEA进行Java编程
java·课程设计·ai编程