Skip to content

Commit

Permalink
rule增加weighted_avg汇总模式
Browse files Browse the repository at this point in the history
  • Loading branch information
entropy-cloud committed Jan 21, 2025
1 parent e5e9c26 commit 80b7ba9
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 3 deletions.
2 changes: 1 addition & 1 deletion docs/dev-guide/graphql/graphql-type.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ GraphQL缺省只有Float、Int、String、Boolean、ID这几种基本类型。No


```java
static class ResultBean {
class ResultBean {
List<IOrmEntity> list;

@GraphQLReturn(bizObjName = "MyObject")
Expand Down
123 changes: 123 additions & 0 deletions docs/theory/thinking-in-functional-programming.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,126 @@

## 三. 从函数到函子

# 实用主义观点下的函数式编程思想

## 一. 引言
### 1.1 函数式编程的兴起
- 函数式编程的历史背景
- 为什么函数式编程在现代开发中越来越重要
- 实用主义视角下的函数式编程:从理论到实践

### 1.2 文章目标
- 探讨函数式编程的核心思想
- 从实用主义角度分析函数式编程的优势与挑战
- 提供实际案例,帮助读者理解如何将函数式编程应用于现实问题

---

## 二. 函数式编程的核心思想
### 2.1 纯函数与不可变性
- 纯函数的定义与特性
- 不可变数据结构的优势
- 纯函数在实践中的应用场景

### 2.2 高阶函数与函数组合
- 高阶函数的概念与作用
- 函数组合:将小函数组合成复杂逻辑
- 实际案例:使用高阶函数简化代码

### 2.3 声明式编程
- 声明式编程与命令式编程的对比
- 如何通过声明式编程提高代码可读性
- 实际案例:使用声明式风格处理数据

---

## 三. 函数式编程的核心工具
### 3.1 函子(Functor)
- 函子的定义与基本操作(`fmap`
- 函子的实际应用:处理容器中的值
- 实际案例:使用函子处理可选值(`Maybe`

### 3.2 单子(Monad)
- 单子的定义与核心操作(`return``bind`
- 单子的实际意义:处理副作用与计算顺序
- 实际案例:使用单子处理异步操作(`Promise`

### 3.3 应用函子(Applicative Functor)
- 应用函子的定义与操作
- 应用函子与函子、单子的关系
- 实际案例:使用应用函子处理多个上下文中的函数

---

## 四. 函数式编程的实用价值
### 4.1 代码的可维护性
- 纯函数与不可变性如何提高代码的可维护性
- 实际案例:重构命令式代码为函数式风格

### 4.2 并行与并发编程
- 函数式编程如何简化并行与并发编程
- 实际案例:使用函数式编程处理多线程任务

### 4.3 测试与调试
- 纯函数如何简化单元测试
- 实际案例:为函数式代码编写测试

### 4.4 函数式编程的局限性
- 函数式编程的学习曲线
- 性能问题与优化策略
- 何时选择函数式编程,何时选择其他范式

---

## 五. 函数式编程在现代开发中的应用
### 5.1 前端开发
- 函数式编程在前端框架中的应用(如React、Redux)
- 实际案例:使用函数式编程构建UI组件

### 5.2 后端开发
- 函数式编程在服务器端开发中的应用(如Node.js、Scala)
- 实际案例:使用函数式编程处理API请求

### 5.3 数据处理与机器学习
- 函数式编程在数据处理中的应用(如MapReduce)
- 实际案例:使用函数式编程处理大规模数据集

---

## 六. 函数式编程的未来
### 6.1 函数式编程与新兴技术
- 函数式编程在区块链、物联网等领域的应用
- 函数式编程与人工智能的结合

### 6.2 函数式编程的普及与教育
- 如何降低函数式编程的学习门槛
- 函数式编程在计算机教育中的角色

### 6.3 函数式编程的社区与生态
- 函数式编程语言的发展趋势(如Haskell、Elm、Clojure)
- 函数式编程工具与库的生态系统

---

## 七. 结论
### 7.1 函数式编程的核心价值
- 从实用主义角度总结函数式编程的优势
- 函数式编程如何改变开发者的思维方式

### 7.2 如何开始学习函数式编程
- 推荐学习资源与路径
- 实践建议:从小项目开始,逐步深入

### 7.3 函数式编程的未来展望
- 函数式编程在软件开发中的长期影响
- 开发者如何拥抱函数式编程的思想

---

## 参考文献
- 相关书籍、论文与在线资源
- 函数式编程语言与工具的官方文档

---

这个大纲从实用主义的角度出发,系统地探讨了函数式编程的核心思想、工具、应用场景以及未来发展方向。通过理论与实际案例的结合,旨在帮助读者深入理解函数式编程的价值,并将其应用于实际开发中。
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,6 @@ public interface RuleConstants {
String ENUM_RULE_TYPE_MATX = "MATX";

String FIELD_LOG_MESSAGES = "logMessages";

String WEIGHT_NAME_POSTFIX = "__weight";
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ public interface RuleErrors {

String ARG_DISPLAY_NAME = "displayName";

String ARG_RULE_NAME = "ruleName";
String ARG_OUTPUT_NAME = "outputName";

ErrorCode ERR_RULE_WORKBOOK_NO_RULE_SHEET =
define("nop.err.rule.workbook-no-rule-sheet",
"工作簿中没有名称为Rule的Sheet");
Expand Down Expand Up @@ -64,4 +67,7 @@ public interface RuleErrors {
ErrorCode ERR_RULE_INPUT_VAR_NOT_ALLOW_EMPTY =
define("nop.err.rule.input-var-not-allow-empty", "输入变量不允许为空:name={varName},displayName={displayName}",
ARG_VAR_NAME, ARG_DISPLAY_NAME);

ErrorCode ERR_RULE_AGGREGATE_WEIGHT_SIZE_NOT_MATCH =
define("nop.err.rule.aggregate-weight-size-not-match", "权重列表长度与输出列表长度不一致", ARG_RULE_NAME, ARG_OUTPUT_NAME);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,25 @@
*/
package io.nop.rule.core.execute;

import io.nop.api.core.convert.ConvertHelper;
import io.nop.api.core.exceptions.NopException;
import io.nop.commons.util.CollectionHelper;
import io.nop.commons.util.MathHelper;
import io.nop.core.lang.eval.IEvalAction;
import io.nop.core.lang.utils.Underscore;
import io.nop.rule.core.IExecutableRule;
import io.nop.rule.core.IRuleRuntime;
import io.nop.rule.core.model.RuleAggregateMethod;
import io.nop.rule.core.model.RuleOutputDefineModel;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static io.nop.rule.api.RuleApiErrors.ARG_RULE_NAME;
import static io.nop.rule.core.RuleErrors.ARG_OUTPUT_NAME;
import static io.nop.rule.core.RuleErrors.ERR_RULE_AGGREGATE_WEIGHT_SIZE_NOT_MATCH;

public class NormalizeOutputExecutableRule implements IExecutableRule {
private final IExecutableRule rule;
private final List<RuleOutputDefineModel> outputs;
Expand Down Expand Up @@ -52,6 +61,26 @@ private void aggOutput(RuleOutputDefineModel output, IRuleRuntime ruleRt) {
return;
}

boolean useWeight = output.isUseWeight();
List<Double> weights = null;
if (useWeight) {
weights = getWeights(ruleRt, output.getWeightName());
if (weights.isEmpty()) {
useWeight = false;
} else {
if (weights.size() != list.size()) {
throw new NopException(ERR_RULE_AGGREGATE_WEIGHT_SIZE_NOT_MATCH)
.param(ARG_RULE_NAME, ruleRt.getRuleName()).param(ARG_OUTPUT_NAME, name);
}

List<Object> withWeights = new ArrayList<>(list.size());
for (int i = 0; i < list.size(); i++) {
withWeights.add(MathHelper.multiply(list.get(i), weights.get(i)));
}
list = withWeights;
}
}

switch (aggMethod) {
case min: {
Object value = Underscore.min(list);
Expand All @@ -73,6 +102,16 @@ private void aggOutput(RuleOutputDefineModel output, IRuleRuntime ruleRt) {
ruleRt.setOutput(name, value);
break;
}
case weighted_avg: {
Object value = Underscore.sum(list);
Number sumWeight = list.size();
if (useWeight) {
sumWeight = Underscore.sum(weights);
}
value = MathHelper.divide(value, sumWeight);
ruleRt.setOutput(name, value);
break;
}
case list: {
ruleRt.setOutput(name, list);
break;
Expand All @@ -87,6 +126,19 @@ private void aggOutput(RuleOutputDefineModel output, IRuleRuntime ruleRt) {
}
}

private List<Double> getWeights(IRuleRuntime ruleRt, String name) {
List<Object> list = ruleRt.getOutputList(name);
if (list == null || list.isEmpty())
return Collections.emptyList();
List<Double> weights = new ArrayList<>(list.size());
for (Object obj : list) {
weights.add(ConvertHelper.toPrimitiveDouble(obj, 1.0,
err -> new NopException(err)
.param(ARG_RULE_NAME, ruleRt.getRuleName()).param(ARG_OUTPUT_NAME, name)));
}
return weights;
}

private Object getDefaultValue(RuleOutputDefineModel output, IRuleRuntime ruleRt) {
IEvalAction defaultExpr = output.getDefaultExpr();
if (defaultExpr == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ public enum RuleAggregateMethod {
@Label("取平均值")
avg,

@Label("按权重取平均值")
weighted_avg,

@Label("取第一个值")
first,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@
*/
package io.nop.rule.core.model;

import io.nop.rule.core.RuleConstants;
import io.nop.rule.core.model._gen._RuleOutputDefineModel;

public class RuleOutputDefineModel extends _RuleOutputDefineModel{
public RuleOutputDefineModel(){
public class RuleOutputDefineModel extends _RuleOutputDefineModel {
public RuleOutputDefineModel() {

}

public String getWeightName() {
return getName() + RuleConstants.WEIGHT_NAME_POSTFIX;
}
}

0 comments on commit 80b7ba9

Please sign in to comment.