{"id":28834708,"url":"https://github.com/jetlinks/reactor-ql","last_synced_at":"2025-10-24T02:42:04.430Z","repository":{"id":46138952,"uuid":"250231165","full_name":"jetlinks/reactor-ql","owner":"jetlinks","description":"用SQL来描述Reactor API.  可用SQL来实现数据处理逻辑,支持实时数据处理,支持聚合,分组,自定义函数等功能,让数据处理更简单.","archived":false,"fork":false,"pushed_at":"2025-05-29T02:44:55.000Z","size":550,"stargazers_count":206,"open_issues_count":0,"forks_count":114,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-05-29T03:41:40.154Z","etag":null,"topics":["reactor","rule-engine","sql","sql-to-flux","sql-to-reactor"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jetlinks.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-03-26T10:46:36.000Z","updated_at":"2025-05-29T02:44:52.000Z","dependencies_parsed_at":"2023-02-09T14:46:17.546Z","dependency_job_id":"de8fcefa-f66c-4ee3-9941-bb3420640c30","html_url":"https://github.com/jetlinks/reactor-ql","commit_stats":{"total_commits":198,"total_committers":5,"mean_commits":39.6,"dds":"0.46464646464646464","last_synced_commit":"a47352af86df855996c915d7e524237dead7243b"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/jetlinks/reactor-ql","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jetlinks%2Freactor-ql","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jetlinks%2Freactor-ql/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jetlinks%2Freactor-ql/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jetlinks%2Freactor-ql/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jetlinks","download_url":"https://codeload.github.com/jetlinks/reactor-ql/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jetlinks%2Freactor-ql/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260726741,"owners_count":23053229,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["reactor","rule-engine","sql","sql-to-flux","sql-to-reactor"],"created_at":"2025-06-19T09:41:50.172Z","updated_at":"2025-10-24T02:42:04.423Z","avatar_url":"https://github.com/jetlinks.png","language":"Java","readme":"# 用SQL来描述ReactorAPI进行数据处理\n\n![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/jetlinks/reactor-ql/maven-publish.yml?branch=master)\n[![Codacy Badge](https://api.codacy.com/project/badge/Grade/9e72a110fc6744bcb183a630a827dba8)](https://app.codacy.com/gh/jetlinks/reactor-ql?utm_source=github.com\u0026utm_medium=referral\u0026utm_content=jetlinks/reactor-ql\u0026utm_campaign=Badge_Grade_Settings)\n[![Maven Central](https://img.shields.io/maven-central/v/org.jetlinks/reactor-ql.svg)](http://search.maven.org/#search%7Cga%7C1%7Creactor-ql)\n[![Maven metadata URL](https://img.shields.io/maven-metadata/v.svg?metadataUrl=https%3A%2F%2Fcentral.sonatype.com%2Frepository%2Fmaven-snapshots%2Forg%2Fjetlinks%2Freactor-ql%2Fmaven-metadata.xml)](https://oss.sonatype.org/content/repositories/snapshots/org/jetlinks/reactor-ql/)\n[![codecov](https://codecov.io/gh/jetlinks/reactor-ql/branch/master/graph/badge.svg)](https://codecov.io/gh/jetlinks/reactor-ql)\n\n[Reactor](https://github.com/reactor) + [JSqlParser](https://github.com/JSQLParser/JSqlParser) = ReactorQL\n\n## 场景\n\n1. 规则引擎,在线编写SQL来定义数据处理规则.\n2. 实时统计每分钟平均温度.\n3. 统计每20条滚动数据平均值.\n4. ........\n\n## 特性\n\n1. 支持字段映射 `select name username from user`.\n2. 支持聚合函数 `count`,`sum`,`avg`,`max`,`min`.\n3. 支持运算 `select val/100 percent from cpu_usage`.\n4. 支持分组 `select sum(val) sum from topic group by interval('10s')`. 按时间分组.\n5. 支持多列分组 `select count(1) total,productId,deviceId from messages group by productId,deviceId`.\n6. 支持having `select avg(temp) avgTemp from temps group by interval('10s') having avgTemp\u003e10 `.\n7. 支持case when `select case type when 1 then '警告' when 2 then '故障' else '其他' end type from topic`.\n8. 支持Join `select t1.name,t2.detail from t1,t2 where t1.id = t2.id`.\n9. 响应式：数据源，函数执行都是异步非阻塞。\n\n## 例子\n\n引入依赖\n```xml\n\u003cdependency\u003e\n \u003cgroupId\u003eorg.jetlinks\u003c/groupId\u003e\n    \u003cartifactId\u003ereactor-ql\u003c/artifactId\u003e\n    \u003cversion\u003e{version}\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n用例:\n\n```java\n  ReactorQL.builder()\n        .sql(\"select avg(this) total from test group by interval('1s') having total \u003e 2\") //按每秒分组,并计算流中数据平均值,如果平均值大于2则下游收到数据.\n        .build()\n        .start(Flux.range(0, 10).delayElements(Duration.ofMillis(500)))\n        .doOnNext(System.out::println)\n        .as(StepVerifier::create)\n        .expectNextCount(4)\n        .verifyComplete();\n```\n\n更多用法请看 [单元测试](https://github.com/jetlinks/reactor-ql/blob/master/src/test/java/org/jetlinks/reactor/ql/ReactorQLTest.java)\n\n## 原理\n\n1. 解析SQL查询语句，生成SQL抽象语法树。\n2. 遍历SQL抽象语法树，使用策略模式，根据不同的语法类型，编译生成针对`Flux`的转换函数。\n    * 条件使用(`FilterFeature`)进行创建。\n    * 查询列(`columnMapper`)使用`ValueMapFeature`,`ValueFlatMapFeature`,`ValueAggMapFeature`进行创建。\n    * 分组(`groupBy`)使用`GroupFeature`进行创建。\n    * 数据源(`from`)使用`FromFeature`进行创建。\n        * 表 ，从上下文中基于表名获取`Flux`数据流。\n        * 子查询，基于子查询语句生成新的`ReactorQL`对象并执行获取数据源。\n        * 函数，使用策略模式获取对应`FromFeature`进行创建。\n    * 排序(`orderBy`)使用`ValueMapFeature`编译转换函数，基于转换函数执行结果进行排序。\n    * 关联查询(`join`)，支持多种join源。\n        * join 表，从上下文中基于表名获取`Flux`数据流进行数据关联。\n        * 子查询，基于子查询语句生成新的`ReactorQL`对象并执行获取数据源进行数据关联。\n\n3. 组合编译后各个片段对应的`Flux`转换函数。\n    * 组合顺序: `limit-\u003eoffset-\u003edistinct-\u003eorderBy-\u003ecolumnMapper-\u003egroupBy-\u003ewhere-\u003ejoin-\u003efrom`\n4. 传入上下文执行。\n    * 支持参数绑定。\n    * 指定数据源获取函数，使用表名获取数据源。\n\n## 拓展\n\n当内置的特性不满足需求时，可通过自定义的方式进行拓展。\n\n拓展了特性后，在启动时注册到元数据中。\n\n```java\n\nimport org.jetlinks.reactor.ql.ReactorQL;\n\n\npublic ReactorQL createQL(String sql) {\n    return ReactorQL\n            .builder()\n            .sql(sql)\n            //注册自定义的特性\n            .feature(customFeature1, customFeature2)\n            .build();\n}\n\n\n```\n\n### 拓展转换函数\n\n可通过拓展转换函数特性(`ValueMapFeature`)来自定义数据转换等操作，\n如实现 `select device.state(t.deviceId) from \"/device/**\" t`。\n\n```java\n\nimport org.jetlinks.reactor.ql.supports.map.FunctionMapFeature;\n\n// FunctionMapFeature针对ValueMapFeature实现了基础操作\npublic class DeviceStateFunction extends FunctionMapFeature {\n    public DeviceStateFunction() {\n        super(\"device.state\",\n              1,//最大参数数量\n              1,//最小参数数量\n              flux -\u003e flux \n                .collectList()//将响应式参数流中的数据收集为List\n                .flatMap(args -\u003e {\n                    if (args.size() != 1) {\n                        return Mono.empty();\n                    }\n                    String deviceId = String.valueOf(args.get(0));\n\n                    return getDeviceState(deviceId);\n                }));\n    }\n}\n\n\n```\n\n### 拓展数据源函数\n\n可通过拓展数据源函数特性来自定义数据源，\n如实现 `select * from mysql(....)`。\n\n例:\n\n```java\n\nimport net.sf.jsqlparser.statement.select.FromItem;\nimport org.jetlinks.reactor.ql.ReactorQLContext;\nimport org.jetlinks.reactor.ql.ReactorQLMetadata;\nimport org.jetlinks.reactor.ql.ReactorQLRecord;\nimport org.jetlinks.reactor.ql.feature.FeatureId;\nimport org.jetlinks.reactor.ql.feature.FromFeature;\nimport reactor.core.publisher.Flux;\n\nimport java.util.function.Function;\n\n// select * from mysql(....);\npublic class MysqlFromFeature implements FromFeature {\n   private static final String ID = FeatureId.From.of(\"mysql\").getId();\n\n   @Override\n   public Function\u003cReactorQLContext, Flux\u003cReactorQLRecord\u003e\u003e createFromMapper(\n           FromItem fromItem,\n           ReactorQLMetadata metadata) {\n      TableFunction from = ((TableFunction) fromItem);\n      net.sf.jsqlparser.expression.Function function = from.getFunction();\n      //函数参数列表\n      ExpressionList list = function.getParameters();\n      //别名\n      String alias = from.getAlias() != null ? from.getAlias().getName() : null;\n\n      Object params = prepareParameter(list);\n      return ctx -\u003e {\n         return this\n                 .execute0(params)\n                 .map(val -\u003e {\n                    return ReactorQLRecord.newRecord(alias, val, ctx);\n                 });\n      };\n   }\n\n   public Flux\u003cObject\u003e execute0(Object args) {\n      //执行真实逻辑，返回数据流。\n   }\n}\n\n```\n \n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjetlinks%2Freactor-ql","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjetlinks%2Freactor-ql","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjetlinks%2Freactor-ql/lists"}