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 #开源 #流式处理 #规则引擎 #实时监控

相关推荐
华仔啊2 小时前
面试官问:流量突然暴增100倍,系统怎么扛?我的方案是...
java
一只乔哇噻3 小时前
java后端工程师进修ing(研一版‖day50)
java·开发语言
快码加编~3 小时前
无法解析插件 org.apache.maven.plugins:maven-site-plugin:3.12.1
java·学习·maven·intellij-idea
托比-马奎尔3 小时前
Maven学习
java·学习·maven
znhy@1233 小时前
十一、Maven web项目的构建
java·maven
paopao_wu3 小时前
Spring AI 从入门到实战-目录
java·人工智能·spring
Hello.Reader3 小时前
用 Maven 配置 Flink 从初始化到可部署的完整实践
java·flink·maven
java_logo4 小时前
使用 Docker 部署 Nginx 教程
java·spring cloud·eureka
小蒜学长4 小时前
springboot基于BS的小区家政服务预约平台(代码+数据库+LW)
java·数据库·spring boot·后端