diff --git a/CHANGELOG.md b/CHANGELOG.md index 27a8f56f9f5d8c929b3a05af23ccb83a03c99d5c..703d91769731e25f5b3229e7e2b32b02b341eeb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,16 @@ #### 功能构建 -- (无) +- 实现预设映射器。 + - com.dwarfeng.fdr.impl.handler.mapper.TrimMapperRegistry。 + - com.dwarfeng.fdr.impl.handler.mapper.ToBooleanMapperRegistry。 + - com.dwarfeng.fdr.impl.handler.mapper.EnableRatioMapperRegistry。 + - com.dwarfeng.fdr.impl.handler.mapper.HighPassMapperRegistry。 + - com.dwarfeng.fdr.impl.handler.mapper.HighPassCounterMapperRegistry。 + - com.dwarfeng.fdr.impl.handler.mapper.HighPassExistenceMapperRegistry。 + - com.dwarfeng.fdr.impl.handler.mapper.LowPassMapperRegistry。 + - com.dwarfeng.fdr.impl.handler.mapper.LowPassCounterMapperRegistry。 + - com.dwarfeng.fdr.impl.handler.mapper.LowPassExistenceMapperRegistry。 #### Bug修复 diff --git a/fdr-impl/src/main/java/com/dwarfeng/fdr/impl/handler/mapper/EnableRatioMapperRegistry.java b/fdr-impl/src/main/java/com/dwarfeng/fdr/impl/handler/mapper/EnableRatioMapperRegistry.java new file mode 100644 index 0000000000000000000000000000000000000000..a19dc6283d7d97cbdf9f2f3c66f10a8fdd253914 --- /dev/null +++ b/fdr-impl/src/main/java/com/dwarfeng/fdr/impl/handler/mapper/EnableRatioMapperRegistry.java @@ -0,0 +1,197 @@ +package com.dwarfeng.fdr.impl.handler.mapper; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.annotation.JSONField; +import com.dwarfeng.fdr.sdk.util.CompareUtil; +import com.dwarfeng.fdr.stack.exception.MapperException; +import com.dwarfeng.fdr.stack.exception.MapperMakeException; +import com.dwarfeng.fdr.stack.handler.Mapper; +import com.dwarfeng.subgrade.stack.bean.Bean; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.Date; +import java.util.List; + +/** + * 使能比例映射器注册。 + * + * @author mooyuan + * @since 2.0.0 + */ +@Component +public class EnableRatioMapperRegistry extends AbstractMapperRegistry { + + public static final String MAPPER_TYPE = "enable_ratio_mapper"; + + private final ApplicationContext ctx; + + public EnableRatioMapperRegistry(ApplicationContext ctx) { + super(MAPPER_TYPE); + this.ctx = ctx; + } + + @Override + public String provideLabel() { + return "使能比例映射器"; + } + + @Override + public String provideDescription() { + return "用于计算布尔类型数据的使能比例,即数据中真值的占用时间与序列的总时间的比值: \n" + + "invert 用于控制计算的是真值的比例还是假值的比例: \n" + + " false:计算的是真值的比例 \n" + + " true:计算的是假值的比例 \n"; + } + + @Override + public String provideExampleParam() { + return JSON.toJSONString(new Config(false)); + } + + @Override + public Mapper makeMapper() throws MapperException { + try { + return ctx.getBean(EnableRatioMapper.class); + } catch (Exception e) { + throw new MapperMakeException(e); + } + } + + @Override + public String toString() { + return "EnableRatioMapper{" + + "mapperType='" + mapperType + '\'' + + '}'; + } + + @Component + @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) + public static class EnableRatioMapper extends AggregateMapper { + + @Override + protected Object doAggregate(MapParam mapParam, List items, Date startDate, Date endDate) { + + // 获得配置。 + Config config = JSON.parseObject(mapParam.getParam(), Config.class); + + boolean invert = config.getInvert(); + + // 对数据点进行时间排序(正序) + items.sort(CompareUtil.DATA_HAPPENED_DATE_ASC_COMPARATOR); + + //更新开始时间,去掉真空期 + startDate = items.get(0).getHappenedDate(); + + // 判断中间存在不为boolean类型的数据抛出异常 + for (Item item : items) { + if (!(item.getValue() instanceof Boolean)) { + throw new IllegalStateException("存在数据点值不为boolean类型"); + } + } + + // 计算占比 + return calRatioByItems(items, startDate, endDate, invert); + } + + /** + * 计算占比 + * + * @param items 排完序的数据点数组 + * @param startDate 序列开始时间 + * @param endDate 序列结束时间 + * @param invert true 计算false的占比、false 计算true的占比 + * @return 获取占比 + */ + private double calRatioByItems(List items, Date startDate, Date endDate, boolean invert) { + // 符合时间 + BigDecimal calTime = BigDecimal.ZERO; + boolean calFlag = false; + + BigDecimal startDateTime = BigDecimal.valueOf(startDate.getTime()); + BigDecimal endDateTime = BigDecimal.valueOf(endDate.getTime()); + // 总时间 + BigDecimal allTime = endDateTime.subtract(startDateTime); + + // 上一次符合的时间 + BigDecimal preTime = BigDecimal.ZERO; + + for (Item item : items) { + if (item.getValue() instanceof Boolean && !invert == (Boolean) item.getValue()) { + + if (calFlag) { + continue; + } + + preTime = BigDecimal.valueOf(item.getHappenedDate().getTime()); + calFlag = true; + } else { + if (!calFlag) { + continue; + } + + calTime = calTime.add(BigDecimal.valueOf(item.getHappenedDate().getTime()).subtract(preTime)); + calFlag = false; + } + } + + // 处理结束的时间,当最后时间的calFlag还是true时处理 + if (calFlag) { + calTime = calTime.add(endDateTime.subtract(preTime)); + } + + return calTime.divide(allTime, 4, RoundingMode.HALF_UP).doubleValue(); + } + + @Override + public String toString() { + return "EnableRatioMapper{}"; + } + } + + public static class Config implements Bean { + + private static final long serialVersionUID = 6070172089803753764L; + + @JSONField(name = "invert", ordinal = 1) + private boolean invert; + + @JSONField(name = "#invert", ordinal = 2, deserialize = false) + private String invertRem = "true:计算的是假值的比例;false:计算的是真值的比例"; + + public Config() { + } + + public Config(boolean invert) { + this.invert = invert; + } + + public boolean getInvert() { + return invert; + } + + public void setInvert(boolean invert) { + this.invert = invert; + } + + public String getInvertRem() { + return invertRem; + } + + public void setInvertRem(String invertRem) { + this.invertRem = invertRem; + } + + @Override + public String toString() { + return "Config{" + + "invert=" + invert + + ", invertRem='" + invertRem + '\'' + + '}'; + } + } +} diff --git a/fdr-impl/src/main/java/com/dwarfeng/fdr/impl/handler/mapper/HighPassCounterMapperRegistry.java b/fdr-impl/src/main/java/com/dwarfeng/fdr/impl/handler/mapper/HighPassCounterMapperRegistry.java new file mode 100644 index 0000000000000000000000000000000000000000..dd8c2876b921fb7149afe6465f2228adc371f692 --- /dev/null +++ b/fdr-impl/src/main/java/com/dwarfeng/fdr/impl/handler/mapper/HighPassCounterMapperRegistry.java @@ -0,0 +1,181 @@ +package com.dwarfeng.fdr.impl.handler.mapper; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.annotation.JSONField; +import com.dwarfeng.fdr.stack.exception.MapperException; +import com.dwarfeng.fdr.stack.exception.MapperMakeException; +import com.dwarfeng.fdr.stack.handler.Mapper; +import com.dwarfeng.subgrade.stack.bean.Bean; +import com.dwarfeng.subgrade.stack.bean.key.LongIdKey; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.util.Date; +import java.util.List; + +/** + * 高通计数映射器 + * + *

+ * 计算高于阈值的数据的个数。 + * + * @author mooyuan + * @since 2.0.0 + */ +public class HighPassCounterMapperRegistry extends AbstractMapperRegistry { + + public static final String MAPPER_TYPE = "high_pass_counter_mapper"; + + private final ApplicationContext ctx; + + public HighPassCounterMapperRegistry(ApplicationContext ctx) { + super(MAPPER_TYPE); + this.ctx = ctx; + } + + @Override + public String provideLabel() { + return "高通计数映射器"; + } + + @Override + public String provideDescription() { + return "用于计算高于阈值的数据的个数: \n" + + "invert 用于控制计算的是低于阈值的数据还是高于阈值的数据: \n" + + " false:过滤的是高于阈值的数据 \n" + + " true:过滤的是低于阈值的数据 \n" + + "threshold用于过滤的阈值 \n" + + "can_equal是否包含等于阈值的数据"; + } + + @Override + public String provideExampleParam() { + return JSON.toJSONString(new Config(0.00, true, false)); + } + + @Override + public Mapper makeMapper() throws MapperException { + try { + return ctx.getBean(HighPassCounterMapper.class); + } catch (Exception e) { + throw new MapperMakeException(e); + } + } + + @Override + public String toString() { + return "HighPassCounterMapper{" + + "mapperType='" + mapperType + '\'' + + '}'; + } + + @Component + @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) + public static class HighPassCounterMapper extends AggregateMapper { + + @Override + protected Object doAggregate(MapParam mapParam, List items, Date startDate, Date endDate) { + Sequence s = HighPassMapperRegistry.HighPassMapper.highPass(mapParam, new Sequence(new LongIdKey(0L), items, startDate, endDate)); + return s.getItems().size(); + } + + @Override + public String toString() { + return "HighPassCounterMapper{}"; + } + } + + public static class Config implements Bean { + + private static final long serialVersionUID = 4334109826634237727L; + + @JSONField(name = "threshold", ordinal = 1) + private double threshold; + + @JSONField(name = "#threshold", ordinal = 2, deserialize = false) + private String thresholdRem = "阈值,对数据进行筛选的标准"; + + @JSONField(name = "can_equal", ordinal = 3) + private boolean canEqual; + + @JSONField(name = "#can_equal", ordinal = 4, deserialize = false) + private String canEqualRem = "true:包含阈值,false:不包含阈值"; + + @JSONField(name = "invert", ordinal = 5) + private boolean invert; + + @JSONField(name = "#invert", ordinal = 6, deserialize = false) + private String invertRem = "true:过滤掉高于阈值的数据,false:过滤掉低于阈值的数据"; + + public Config() { + } + + public Config(double threshold, boolean canEqual, boolean invert) { + this.threshold = threshold; + this.canEqual = canEqual; + this.invert = invert; + } + + public double getThreshold() { + return threshold; + } + + public void setThreshold(double threshold) { + this.threshold = threshold; + } + + public String getThresholdRem() { + return thresholdRem; + } + + public void setThresholdRem(String thresholdRem) { + this.thresholdRem = thresholdRem; + } + + public boolean getCanEqual() { + return canEqual; + } + + public void setCanEqual(boolean canEqual) { + this.canEqual = canEqual; + } + + public String getCanEqualRem() { + return canEqualRem; + } + + public void setCanEqualRem(String canEqualRem) { + this.canEqualRem = canEqualRem; + } + + public boolean getInvert() { + return invert; + } + + public void setInvert(boolean invert) { + this.invert = invert; + } + + public String getInvertRem() { + return invertRem; + } + + public void setInvertRem(String invertRem) { + this.invertRem = invertRem; + } + + @Override + public String toString() { + return "Config{" + + "threshold=" + threshold + + ", thresholdRem='" + thresholdRem + '\'' + + ", canEqual=" + canEqual + + ", canEqualRem='" + canEqualRem + '\'' + + ", invert=" + invert + + ", invertRem='" + invertRem + '\'' + + '}'; + } + } +} diff --git a/fdr-impl/src/main/java/com/dwarfeng/fdr/impl/handler/mapper/HighPassExistenceMapperRegistry.java b/fdr-impl/src/main/java/com/dwarfeng/fdr/impl/handler/mapper/HighPassExistenceMapperRegistry.java new file mode 100644 index 0000000000000000000000000000000000000000..2421b833adb2f545127ca05e09a073c39df043f6 --- /dev/null +++ b/fdr-impl/src/main/java/com/dwarfeng/fdr/impl/handler/mapper/HighPassExistenceMapperRegistry.java @@ -0,0 +1,218 @@ +package com.dwarfeng.fdr.impl.handler.mapper; + + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.annotation.JSONField; +import com.dwarfeng.fdr.stack.exception.MapperException; +import com.dwarfeng.fdr.stack.exception.MapperMakeException; +import com.dwarfeng.fdr.stack.handler.Mapper; +import com.dwarfeng.subgrade.stack.bean.Bean; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.util.Date; +import java.util.List; +import java.util.Objects; + +/** + * 高通存在映射器注册。 + * + *

+ * 高通存在映射器,用于判断是否存在高于阈值的数据。 + * + * @author mooyuan + * @since 2.0.0 + */ +public class HighPassExistenceMapperRegistry extends AbstractMapperRegistry { + + public static final String MAPPER_TYPE = "high_pass_existence_mapper"; + + private final ApplicationContext ctx; + + public HighPassExistenceMapperRegistry(ApplicationContext ctx) { + super(MAPPER_TYPE); + this.ctx = ctx; + } + + @Override + public String provideLabel() { + return "高通存在映射器"; + } + + @Override + public String provideDescription() { + return "用于判断是否存在高于阈值的数据: \n" + + "invert 用于控制计算的是低于阈值的数据还是高于阈值的数据: \n" + + " false:过滤的是高于阈值的数据 \n" + + " true:过滤的是低于阈值的数据 \n" + + "threshold用于过滤的阈值 \n" + + "can_equal是否包含等于阈值的数据"; + } + + @Override + public String provideExampleParam() { + return JSON.toJSONString(new Config(0.00, true, false)); + } + + @Override + public Mapper makeMapper() throws MapperException { + try { + return ctx.getBean(HighPassExistenceMapper.class); + } catch (Exception e) { + throw new MapperMakeException(e); + } + } + + @Override + public String toString() { + return "HighPassExistenceMapper{" + + "mapperType='" + mapperType + '\'' + + '}'; + } + + @Component + @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) + public static class HighPassExistenceMapper extends AggregateMapper { + + @Override + protected Object doAggregate(MapParam mapParam, List items, Date startDate, Date endDate) { + // 获得配置。 + Config config = JSON.parseObject(mapParam.getParam(), Config.class); + + double threshold = config.getThreshold(); + + boolean canEqual = config.getCanEqual(); + + boolean invert = config.getInvert(); + + return doDetermine(items, threshold, invert, canEqual); + } + + // 为了保证代码的可读性,此处代码不做简化。 + @SuppressWarnings("ConstantConditions") + private boolean doDetermine(List items, double threshold, boolean invert, boolean canEqual) { + for (Item item : items) { + if (invert && canEqual) { + if ((Objects.isNull(item.getValue()) ? 0.00 : (double) item.getValue()) <= threshold) { + return true; + } + } else if (invert && !canEqual) { + if ((Objects.isNull(item.getValue()) ? 0.00 : (double) item.getValue()) < threshold) { + return true; + } + } else if (!invert && canEqual) { + if ((Objects.isNull(item.getValue()) ? 0.00 : (double) item.getValue()) >= threshold) { + return true; + } + } else { + if ((Objects.isNull(item.getValue()) ? 0.00 : (double) item.getValue()) > threshold) { + return true; + } + } + } + + return false; + } + + @Override + public String toString() { + return "HighPassExistenceMapper{}"; + } + } + + + public static class Config implements Bean { + + private static final long serialVersionUID = 2358214849837705523L; + + @JSONField(name = "threshold", ordinal = 1) + private double threshold; + + @JSONField(name = "#threshold", ordinal = 2, deserialize = false) + private String thresholdRem = "阈值,对数据进行筛选的标准"; + + @JSONField(name = "can_equal", ordinal = 3) + private boolean canEqual; + + @JSONField(name = "#can_equal", ordinal = 4, deserialize = false) + private String canEqualRem = "true:包含阈值,false:不包含阈值"; + + @JSONField(name = "invert", ordinal = 5) + private boolean invert; + + @JSONField(name = "#invert", ordinal = 6, deserialize = false) + private String invertRem = "true:过滤掉高于阈值的数据,false:过滤掉低于阈值的数据"; + + public Config() { + } + + public Config(double threshold, boolean canEqual, boolean invert) { + this.threshold = threshold; + this.canEqual = canEqual; + this.invert = invert; + } + + public double getThreshold() { + return threshold; + } + + public void setThreshold(double threshold) { + this.threshold = threshold; + } + + public String getThresholdRem() { + return thresholdRem; + } + + public void setThresholdRem(String thresholdRem) { + this.thresholdRem = thresholdRem; + } + + public boolean getCanEqual() { + return canEqual; + } + + public void setCanEqual(boolean canEqual) { + this.canEqual = canEqual; + } + + public String getCanEqualRem() { + return canEqualRem; + } + + public void setCanEqualRem(String canEqualRem) { + this.canEqualRem = canEqualRem; + } + + public boolean getInvert() { + return invert; + } + + public void setInvert(boolean invert) { + this.invert = invert; + } + + public String getInvertRem() { + return invertRem; + } + + public void setInvertRem(String invertRem) { + this.invertRem = invertRem; + } + + @Override + public String toString() { + return "Config{" + + "threshold=" + threshold + + ", thresholdRem='" + thresholdRem + '\'' + + ", canEqual=" + canEqual + + ", canEqualRem='" + canEqualRem + '\'' + + ", invert=" + invert + + ", invertRem='" + invertRem + '\'' + + '}'; + } + } + +} diff --git a/fdr-impl/src/main/java/com/dwarfeng/fdr/impl/handler/mapper/HighPassMapperRegistry.java b/fdr-impl/src/main/java/com/dwarfeng/fdr/impl/handler/mapper/HighPassMapperRegistry.java new file mode 100644 index 0000000000000000000000000000000000000000..decae2081c948ee38bdb87e14e8abb932ac6d32d --- /dev/null +++ b/fdr-impl/src/main/java/com/dwarfeng/fdr/impl/handler/mapper/HighPassMapperRegistry.java @@ -0,0 +1,224 @@ +package com.dwarfeng.fdr.impl.handler.mapper; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.annotation.JSONField; +import com.dwarfeng.fdr.stack.exception.MapperException; +import com.dwarfeng.fdr.stack.exception.MapperMakeException; +import com.dwarfeng.fdr.stack.handler.Mapper; +import com.dwarfeng.subgrade.stack.bean.Bean; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * 高通映射器注册。 + * + *

+ * 保留高于阈值的数据。 + * + * @author mooyuan + * @since 2.0.0 + */ +public class HighPassMapperRegistry extends AbstractMapperRegistry { + public static final String MAPPER_TYPE = "high_pass_mapper"; + + private final ApplicationContext ctx; + + public HighPassMapperRegistry(ApplicationContext ctx) { + super(MAPPER_TYPE); + this.ctx = ctx; + } + + @Override + public String provideLabel() { + return "高通映射器"; + } + + @Override + public String provideDescription() { + return "用于保留高于阈值的数据: \n" + + "invert 用于控制计算的是低于阈值的数据还是高于阈值的数据: \n" + + " false:过滤的是高于阈值的数据 \n" + + " true:过滤的是低于阈值的数据 \n" + + "threshold用于过滤的阈值 \n" + + "can_equal是否包含等于阈值的数据"; + } + + @Override + public String provideExampleParam() { + return JSON.toJSONString(new Config(0.00, true, false)); + } + + @Override + public Mapper makeMapper() throws MapperException { + try { + return ctx.getBean(HighPassMapper.class); + } catch (Exception e) { + throw new MapperMakeException(e); + } + } + + @Override + public String toString() { + return "HighPassMapper{" + + "mapperType='" + mapperType + '\'' + + '}'; + } + + @Component + @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) + public static class HighPassMapper extends OneToOneMapper { + + @Override + protected Sequence doOneToOneMap(MapParam mapParam, Sequence sequence) { + + + return highPass(mapParam, sequence); + } + + @SuppressWarnings("DuplicatedCode") + public static Sequence highPass(MapParam mapParam, Sequence sequence) { + // 获得配置。 + Config config = JSON.parseObject(mapParam.getParam(), Config.class); + + double threshold = config.getThreshold(); + + boolean canEqual = config.getCanEqual(); + + boolean invert = config.getInvert(); + + // 定义数据条目列表。 + List items; + + items = doFilter(sequence, threshold, canEqual, invert); + + return new Sequence(sequence.getPointKey(), items, sequence.getStartDate(), sequence.getEndDate()); + } + + // 为了保证代码的可读性,此处代码不做简化。 + @SuppressWarnings("ConstantConditions") + private static List doFilter(Sequence sequence, double threshold, boolean canEqual, boolean invert) { + List items; + if (invert && canEqual) { + items = sequence.getItems().stream().filter( + item -> (Objects.isNull(item.getValue()) ? 0.00 : (double) item.getValue()) <= threshold + ).collect(Collectors.toList()); + } else if (invert && !canEqual) { + items = sequence.getItems().stream().filter( + item -> (Objects.isNull(item.getValue()) ? 0.00 : (double) item.getValue()) < threshold + ).collect(Collectors.toList()); + } else if (!invert && canEqual) { + items = sequence.getItems().stream().filter( + item -> (Objects.isNull(item.getValue()) ? 0.00 : (double) item.getValue()) >= threshold + ).collect(Collectors.toList()); + } else { + items = sequence.getItems().stream().filter( + item -> (Objects.isNull(item.getValue()) ? 0.00 : (double) item.getValue()) > threshold + ).collect(Collectors.toList()); + } + return items; + } + + @Override + public String toString() { + return "HighPassMapper{}"; + } + } + + public static class Config implements Bean { + + private static final long serialVersionUID = -3275585723620360134L; + + @JSONField(name = "threshold", ordinal = 1) + private double threshold; + + @JSONField(name = "#threshold", ordinal = 2, deserialize = false) + private String thresholdRem = "阈值,对数据进行筛选的标准"; + + @JSONField(name = "can_equal", ordinal = 3) + private boolean canEqual; + + @JSONField(name = "#can_equal", ordinal = 4, deserialize = false) + private String canEqualRem = "true:包含阈值,false:不包含阈值"; + + @JSONField(name = "invert", ordinal = 5) + private boolean invert; + + @JSONField(name = "#invert", ordinal = 6, deserialize = false) + private String invertRem = "true:过滤掉高于阈值的数据,false:过滤掉低于阈值的数据"; + + public Config() { + } + + public Config(double threshold, boolean canEqual, boolean invert) { + this.threshold = threshold; + this.canEqual = canEqual; + this.invert = invert; + } + + public double getThreshold() { + return threshold; + } + + public void setThreshold(double threshold) { + this.threshold = threshold; + } + + public String getThresholdRem() { + return thresholdRem; + } + + public void setThresholdRem(String thresholdRem) { + this.thresholdRem = thresholdRem; + } + + public boolean getCanEqual() { + return canEqual; + } + + public void setCanEqual(boolean canEqual) { + this.canEqual = canEqual; + } + + public String getCanEqualRem() { + return canEqualRem; + } + + public void setCanEqualRem(String canEqualRem) { + this.canEqualRem = canEqualRem; + } + + public boolean getInvert() { + return invert; + } + + public void setInvert(boolean invert) { + this.invert = invert; + } + + public String getInvertRem() { + return invertRem; + } + + public void setInvertRem(String invertRem) { + this.invertRem = invertRem; + } + + @Override + public String toString() { + return "Config{" + + "threshold=" + threshold + + ", thresholdRem='" + thresholdRem + '\'' + + ", canEqual=" + canEqual + + ", canEqualRem='" + canEqualRem + '\'' + + ", invert=" + invert + + ", invertRem='" + invertRem + '\'' + + '}'; + } + } +} diff --git a/fdr-impl/src/main/java/com/dwarfeng/fdr/impl/handler/mapper/LowPassCounterMapperRegistry.java b/fdr-impl/src/main/java/com/dwarfeng/fdr/impl/handler/mapper/LowPassCounterMapperRegistry.java new file mode 100644 index 0000000000000000000000000000000000000000..c16ee376474c62e5c89db4147d9a1c847e5fb927 --- /dev/null +++ b/fdr-impl/src/main/java/com/dwarfeng/fdr/impl/handler/mapper/LowPassCounterMapperRegistry.java @@ -0,0 +1,181 @@ +package com.dwarfeng.fdr.impl.handler.mapper; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.annotation.JSONField; +import com.dwarfeng.fdr.stack.exception.MapperException; +import com.dwarfeng.fdr.stack.exception.MapperMakeException; +import com.dwarfeng.fdr.stack.handler.Mapper; +import com.dwarfeng.subgrade.stack.bean.Bean; +import com.dwarfeng.subgrade.stack.bean.key.LongIdKey; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.util.Date; +import java.util.List; + +/** + * 低通计数映射器 + * + *

+ * 计算低于阈值的数据的个数。 + * + * @author mooyuan + * @since 2.0.0 + */ +public class LowPassCounterMapperRegistry extends AbstractMapperRegistry { + + public static final String MAPPER_TYPE = "low_pass_counter_mapper"; + + private final ApplicationContext ctx; + + public LowPassCounterMapperRegistry(ApplicationContext ctx) { + super(MAPPER_TYPE); + this.ctx = ctx; + } + + @Override + public String provideLabel() { + return "低通计数映射器"; + } + + @Override + public String provideDescription() { + return "用于计算低于阈值的数据的个数: \n" + + "invert 用于控制计算的是低于阈值的数据还是高于阈值的数据: \n" + + " false:过滤的是高于阈值的数据 \n" + + " true:过滤的是低于阈值的数据 \n" + + "threshold用于过滤的阈值 \n" + + "can_equal是否包含等于阈值的数据"; + } + + @Override + public String provideExampleParam() { + return JSON.toJSONString(new Config(0.00, true, false)); + } + + @Override + public Mapper makeMapper() throws MapperException { + try { + return ctx.getBean(LowPassCounterMapper.class); + } catch (Exception e) { + throw new MapperMakeException(e); + } + } + + @Override + public String toString() { + return "LowPassCounterMapper{" + + "mapperType='" + mapperType + '\'' + + '}'; + } + + @Component + @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) + public static class LowPassCounterMapper extends AggregateMapper { + + @Override + protected Object doAggregate(MapParam mapParam, List items, Date startDate, Date endDate) { + Sequence s = LowPassMapperRegistry.LowPassMapper.lowPass(mapParam, new Sequence(new LongIdKey(0L), items, startDate, endDate)); + return s.getItems().size(); + } + + @Override + public String toString() { + return "LowPassCounterMapper{}"; + } + } + + public static class Config implements Bean { + + private static final long serialVersionUID = 1816088081525711050L; + + @JSONField(name = "threshold", ordinal = 1) + private double threshold; + + @JSONField(name = "#threshold", ordinal = 2, deserialize = false) + private String thresholdRem = "阈值,对数据进行筛选的标准"; + + @JSONField(name = "can_equal", ordinal = 3) + private boolean canEqual; + + @JSONField(name = "#can_equal", ordinal = 4, deserialize = false) + private String canEqualRem = "true:包含阈值,false:不包含阈值"; + + @JSONField(name = "invert", ordinal = 5) + private boolean invert; + + @JSONField(name = "#invert", ordinal = 6, deserialize = false) + private String invertRem = "true:过滤掉低于阈值的数据,false:过滤掉高于阈值的数据"; + + public Config() { + } + + public Config(double threshold, boolean canEqual, boolean invert) { + this.threshold = threshold; + this.canEqual = canEqual; + this.invert = invert; + } + + public double getThreshold() { + return threshold; + } + + public void setThreshold(double threshold) { + this.threshold = threshold; + } + + public String getThresholdRem() { + return thresholdRem; + } + + public void setThresholdRem(String thresholdRem) { + this.thresholdRem = thresholdRem; + } + + public boolean getCanEqual() { + return canEqual; + } + + public void setCanEqual(boolean canEqual) { + this.canEqual = canEqual; + } + + public String getCanEqualRem() { + return canEqualRem; + } + + public void setCanEqualRem(String canEqualRem) { + this.canEqualRem = canEqualRem; + } + + public boolean getInvert() { + return invert; + } + + public void setInvert(boolean invert) { + this.invert = invert; + } + + public String getInvertRem() { + return invertRem; + } + + public void setInvertRem(String invertRem) { + this.invertRem = invertRem; + } + + @Override + public String toString() { + return "Config{" + + "threshold=" + threshold + + ", thresholdRem='" + thresholdRem + '\'' + + ", canEqual=" + canEqual + + ", canEqualRem='" + canEqualRem + '\'' + + ", invert=" + invert + + ", invertRem='" + invertRem + '\'' + + '}'; + } + } +} diff --git a/fdr-impl/src/main/java/com/dwarfeng/fdr/impl/handler/mapper/LowPassExistenceMapperRegistry.java b/fdr-impl/src/main/java/com/dwarfeng/fdr/impl/handler/mapper/LowPassExistenceMapperRegistry.java new file mode 100644 index 0000000000000000000000000000000000000000..2a5c63de8d9b04ef32833d51219971a3f3b2c906 --- /dev/null +++ b/fdr-impl/src/main/java/com/dwarfeng/fdr/impl/handler/mapper/LowPassExistenceMapperRegistry.java @@ -0,0 +1,218 @@ +package com.dwarfeng.fdr.impl.handler.mapper; + + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.annotation.JSONField; +import com.dwarfeng.fdr.stack.exception.MapperException; +import com.dwarfeng.fdr.stack.exception.MapperMakeException; +import com.dwarfeng.fdr.stack.handler.Mapper; +import com.dwarfeng.subgrade.stack.bean.Bean; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.util.Date; +import java.util.List; +import java.util.Objects; + +/** + * 低通存在映射器注册 + * + *

+ * 低通存在映射器,用于判断是否存在低于阈值的数据。 + * + * @author mooyuan + * @since 2.0.0 + */ +public class LowPassExistenceMapperRegistry extends AbstractMapperRegistry { + + public static final String MAPPER_TYPE = "low_pass_existence_mapper"; + + private final ApplicationContext ctx; + + public LowPassExistenceMapperRegistry(ApplicationContext ctx) { + super(MAPPER_TYPE); + this.ctx = ctx; + } + + @Override + public String provideLabel() { + return "低通存在映射器"; + } + + @Override + public String provideDescription() { + return "用于判断是否存在低于阈值的数据: \n" + + "invert 用于控制计算的是低于阈值的数据还是高于阈值的数据: \n" + + " false:过滤的是低于阈值的数据 \n" + + " true:过滤的是高于阈值的数据 \n" + + "threshold用于过滤的阈值 \n" + + "can_equal是否包含等于阈值的数据"; + } + + @Override + public String provideExampleParam() { + return JSON.toJSONString(new Config(0.00, true, false)); + } + + @Override + public Mapper makeMapper() throws MapperException { + try { + return ctx.getBean(LowPassExistenceMapper.class); + } catch (Exception e) { + throw new MapperMakeException(e); + } + } + + @Override + public String toString() { + return "LowPassExistenceMapper{" + + "mapperType='" + mapperType + '\'' + + '}'; + } + + @Component + @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) + public static class LowPassExistenceMapper extends AggregateMapper { + + @Override + protected Object doAggregate(MapParam mapParam, List items, Date startDate, Date endDate) { + // 获得配置。 + Config config = JSON.parseObject(mapParam.getParam(), Config.class); + + double threshold = config.getThreshold(); + + boolean canEqual = config.getCanEqual(); + + boolean invert = config.getInvert(); + + return doDetermine(items, threshold, invert, canEqual); + } + + // 为了保证代码的可读性,此处代码不做简化。 + @SuppressWarnings("ConstantConditions") + private boolean doDetermine(List items, double threshold, boolean invert, boolean canEqual) { + for (Item item : items) { + if (invert && canEqual) { + if ((Objects.isNull(item.getValue()) ? 0.00 : (double) item.getValue()) >= threshold) { + return true; + } + } else if (invert && !canEqual) { + if ((Objects.isNull(item.getValue()) ? 0.00 : (double) item.getValue()) > threshold) { + return true; + } + } else if (!invert && canEqual) { + if ((Objects.isNull(item.getValue()) ? 0.00 : (double) item.getValue()) <= threshold) { + return true; + } + } else { + if ((Objects.isNull(item.getValue()) ? 0.00 : (double) item.getValue()) < threshold) { + return true; + } + } + } + + return false; + } + + @Override + public String toString() { + return "LowPassExistenceMapper{}"; + } + } + + + public static class Config implements Bean { + + private static final long serialVersionUID = -5684552000019608904L; + + @JSONField(name = "threshold", ordinal = 1) + private double threshold; + + @JSONField(name = "#threshold", ordinal = 2, deserialize = false) + private String thresholdRem = "阈值,对数据进行筛选的标准"; + + @JSONField(name = "can_equal", ordinal = 3) + private boolean canEqual; + + @JSONField(name = "#can_equal", ordinal = 4, deserialize = false) + private String canEqualRem = "true:包含阈值,false:不包含阈值"; + + @JSONField(name = "invert", ordinal = 5) + private boolean invert; + + @JSONField(name = "#invert", ordinal = 6, deserialize = false) + private String invertRem = "true:过滤掉低于阈值的数据,false:过滤掉高于阈值的数据"; + + public Config() { + } + + public Config(double threshold, boolean canEqual, boolean invert) { + this.threshold = threshold; + this.canEqual = canEqual; + this.invert = invert; + } + + public double getThreshold() { + return threshold; + } + + public void setThreshold(double threshold) { + this.threshold = threshold; + } + + public String getThresholdRem() { + return thresholdRem; + } + + public void setThresholdRem(String thresholdRem) { + this.thresholdRem = thresholdRem; + } + + public boolean getCanEqual() { + return canEqual; + } + + public void setCanEqual(boolean canEqual) { + this.canEqual = canEqual; + } + + public String getCanEqualRem() { + return canEqualRem; + } + + public void setCanEqualRem(String canEqualRem) { + this.canEqualRem = canEqualRem; + } + + public boolean getInvert() { + return invert; + } + + public void setInvert(boolean invert) { + this.invert = invert; + } + + public String getInvertRem() { + return invertRem; + } + + public void setInvertRem(String invertRem) { + this.invertRem = invertRem; + } + + @Override + public String toString() { + return "Config{" + + "threshold=" + threshold + + ", thresholdRem='" + thresholdRem + '\'' + + ", canEqual=" + canEqual + + ", canEqualRem='" + canEqualRem + '\'' + + ", invert=" + invert + + ", invertRem='" + invertRem + '\'' + + '}'; + } + } + +} diff --git a/fdr-impl/src/main/java/com/dwarfeng/fdr/impl/handler/mapper/LowPassMapperRegistry.java b/fdr-impl/src/main/java/com/dwarfeng/fdr/impl/handler/mapper/LowPassMapperRegistry.java new file mode 100644 index 0000000000000000000000000000000000000000..46e1e0a290d6df3831dc4b0d74985087424254ec --- /dev/null +++ b/fdr-impl/src/main/java/com/dwarfeng/fdr/impl/handler/mapper/LowPassMapperRegistry.java @@ -0,0 +1,223 @@ +package com.dwarfeng.fdr.impl.handler.mapper; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.annotation.JSONField; +import com.dwarfeng.fdr.stack.exception.MapperException; +import com.dwarfeng.fdr.stack.exception.MapperMakeException; +import com.dwarfeng.fdr.stack.handler.Mapper; +import com.dwarfeng.subgrade.stack.bean.Bean; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * 低通映射器注册 + * + *

+ * 保留低于阈值的数据。 + * + * @author mooyuan + * @since 2.0.0 + */ +public class LowPassMapperRegistry extends AbstractMapperRegistry { + public static final String MAPPER_TYPE = "low_pass_mapper"; + + private final ApplicationContext ctx; + + public LowPassMapperRegistry(ApplicationContext ctx) { + super(MAPPER_TYPE); + this.ctx = ctx; + } + + @Override + public String provideLabel() { + return "低通映射器"; + } + + @Override + public String provideDescription() { + return "用于保留高于阈值的数据: \n" + + "invert 用于控制计算的是低于阈值的数据还是高于阈值的数据: \n" + + " false:过滤的是高于阈值的数据 \n" + + " true:过滤的是低于阈值的数据 \n" + + "threshold用于过滤的阈值 \n" + + "can_equal是否包含等于阈值的数据"; + } + + @Override + public String provideExampleParam() { + return JSON.toJSONString(new Config(0.00, true, false)); + } + + @Override + public Mapper makeMapper() throws MapperException { + try { + return ctx.getBean(LowPassMapper.class); + } catch (Exception e) { + throw new MapperMakeException(e); + } + } + + @Override + public String toString() { + return "LowPassMapper{" + + "mapperType='" + mapperType + '\'' + + '}'; + } + + @Component + @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) + public static class LowPassMapper extends OneToOneMapper { + + @Override + protected Sequence doOneToOneMap(MapParam mapParam, Sequence sequence) { + + return lowPass(mapParam, sequence); + } + + @SuppressWarnings("DuplicatedCode") + public static Sequence lowPass(MapParam mapParam, Sequence sequence) { + // 获得配置。 + Config config = JSON.parseObject(mapParam.getParam(), Config.class); + + double threshold = config.getThreshold(); + + boolean canEqual = config.getCanEqual(); + + boolean invert = config.getInvert(); + + // 定义数据条目列表。 + List items; + + items = doFilter(sequence, threshold, canEqual, invert); + + return new Sequence(sequence.getPointKey(), items, sequence.getStartDate(), sequence.getEndDate()); + } + + // 为了保证代码的可读性,此处代码不做简化。 + @SuppressWarnings("ConstantConditions") + private static List doFilter(Sequence sequence, double threshold, boolean canEqual, boolean invert) { + List items; + if (invert && canEqual) { + items = sequence.getItems().stream().filter( + item -> (Objects.isNull(item.getValue()) ? 0.00 : (double) item.getValue()) >= threshold + ).collect(Collectors.toList()); + } else if (invert && !canEqual) { + items = sequence.getItems().stream().filter( + item -> (Objects.isNull(item.getValue()) ? 0.00 : (double) item.getValue()) > threshold + ).collect(Collectors.toList()); + } else if (!invert && canEqual) { + items = sequence.getItems().stream().filter( + item -> (Objects.isNull(item.getValue()) ? 0.00 : (double) item.getValue()) <= threshold + ).collect(Collectors.toList()); + } else { + items = sequence.getItems().stream().filter( + item -> (Objects.isNull(item.getValue()) ? 0.00 : (double) item.getValue()) < threshold + ).collect(Collectors.toList()); + } + return items; + } + + @Override + public String toString() { + return "LowPassMapper{}"; + } + } + + public static class Config implements Bean { + + private static final long serialVersionUID = 6070172089803753766L; + + @JSONField(name = "threshold", ordinal = 1) + private double threshold; + + @JSONField(name = "#threshold", ordinal = 2, deserialize = false) + private String thresholdRem = "阈值,对数据进行筛选的标准"; + + @JSONField(name = "can_equal", ordinal = 3) + private boolean canEqual; + + @JSONField(name = "#can_equal", ordinal = 4, deserialize = false) + private String canEqualRem = "true:包含阈值,false:不包含阈值"; + + @JSONField(name = "invert", ordinal = 5) + private boolean invert; + + @JSONField(name = "#invert", ordinal = 6, deserialize = false) + private String invertRem = "true:过滤掉低于阈值的数据,false:过滤掉高于阈值的数据"; + + public Config() { + } + + public Config(double threshold, boolean canEqual, boolean invert) { + this.threshold = threshold; + this.canEqual = canEqual; + this.invert = invert; + } + + public double getThreshold() { + return threshold; + } + + public void setThreshold(double threshold) { + this.threshold = threshold; + } + + public String getThresholdRem() { + return thresholdRem; + } + + public void setThresholdRem(String thresholdRem) { + this.thresholdRem = thresholdRem; + } + + public boolean getCanEqual() { + return canEqual; + } + + public void setCanEqual(boolean canEqual) { + this.canEqual = canEqual; + } + + public String getCanEqualRem() { + return canEqualRem; + } + + public void setCanEqualRem(String canEqualRem) { + this.canEqualRem = canEqualRem; + } + + public boolean getInvert() { + return invert; + } + + public void setInvert(boolean invert) { + this.invert = invert; + } + + public String getInvertRem() { + return invertRem; + } + + public void setInvertRem(String invertRem) { + this.invertRem = invertRem; + } + + @Override + public String toString() { + return "Config{" + + "threshold=" + threshold + + ", thresholdRem='" + thresholdRem + '\'' + + ", canEqual=" + canEqual + + ", canEqualRem='" + canEqualRem + '\'' + + ", invert=" + invert + + ", invertRem='" + invertRem + '\'' + + '}'; + } + } +} diff --git a/fdr-impl/src/main/java/com/dwarfeng/fdr/impl/handler/mapper/ToBooleanMapperRegistry.java b/fdr-impl/src/main/java/com/dwarfeng/fdr/impl/handler/mapper/ToBooleanMapperRegistry.java new file mode 100644 index 0000000000000000000000000000000000000000..daddc6891661ef5e94507e54485f49a9b942dff3 --- /dev/null +++ b/fdr-impl/src/main/java/com/dwarfeng/fdr/impl/handler/mapper/ToBooleanMapperRegistry.java @@ -0,0 +1,239 @@ +package com.dwarfeng.fdr.impl.handler.mapper; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.annotation.JSONField; +import com.dwarfeng.fdr.stack.exception.MapperException; +import com.dwarfeng.fdr.stack.exception.MapperMakeException; +import com.dwarfeng.fdr.stack.handler.Mapper; +import com.dwarfeng.subgrade.stack.bean.Bean; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +/** + * 转换为布尔值的映射器注册。 + * + * @author mooyuan + * @since 2.0.0 + */ +@Component +public class ToBooleanMapperRegistry extends AbstractMapperRegistry { + + public static final String MAPPER_TYPE = "to_boolean_mapper"; + + private final ApplicationContext ctx; + + public ToBooleanMapperRegistry(ApplicationContext ctx) { + super(MAPPER_TYPE); + this.ctx = ctx; + } + + @Override + public String provideLabel() { + return "转换为布尔值的映射器"; + } + + @Override + public String provideDescription() { + return "保留数据表中所有序列的开始时间和结束时间。对每个序列的数据条目做映射处理: \n" + + "是否为严格模式: \n" + + " 是:只有严格匹配真值或者假值的数据才会被转换为布尔类型的数据,如果序列中存在其它值的则抛出 IllegalArgumentException 异常 \n" + + " 字符串真值:true \n" + + " 字符串假值:false \n" + + " 数字真值:1.0 \n" + + " 数字假值:0.0 \n" + + " 否:数据匹配真值时,会被转换为布尔类型的真值,其余任何值都会被转换为布尔类型的假值 \n"; + } + + @Override + public String provideExampleParam() { + return JSON.toJSONString(new Config(false, true)); + } + + @Override + public Mapper makeMapper() throws MapperException { + try { + return ctx.getBean(ToDoubleMapperRegistry.ToDoubleMapper.class); + } catch (Exception e) { + throw new MapperMakeException(e); + } + } + + @Override + public String toString() { + return "ToBooleanMapperRegistry{" + + "mapperType='" + mapperType + '\'' + + '}'; + } + + @Component + @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) + public static class ToBooleanMapper extends OneToOneMapper { + + @Override + protected Sequence doOneToOneMap(MapParam mapParam, Sequence sequence) { + + // 获得配置。 + Config config = JSON.parseObject(mapParam.getParam(), Config.class); + + // 遍历序列中的每个数据条目。 + List items = new ArrayList<>(sequence.getItems().size()); + for (Item item : sequence.getItems()) { + items.add(mapItem(config, item)); + } + + // 返回映射后的序列。 + return new Sequence(sequence.getPointKey(), items, sequence.getStartDate(), sequence.getEndDate()); + } + + // 处理具体的每条数据 + private Item mapItem(Config config, Item item) { + + // 是否忽略大小写 + boolean stringIgnoreCase = config.getStringIgnoreCase(); + boolean itemValue = false; + // 是否启用严格模式 + if (config.getStrict()) { + + if (!(item.getValue() instanceof String) && !(item.getValue() instanceof Number) && !(item.getValue() instanceof Boolean)) { + throw new IllegalStateException("严格模式:传入值格式不正确,请传入字符串、数值或者布尔"); + } + + if (item.getValue() instanceof String) { + + if ((stringIgnoreCase && "true".equalsIgnoreCase((String) item.getValue())) + || (!stringIgnoreCase && "true".equals(item.getValue()))) { + itemValue = true; + } else if ((stringIgnoreCase && !"false".equalsIgnoreCase((String) item.getValue())) + || (!stringIgnoreCase && !"false".equals(item.getValue()))) { + throw new IllegalStateException("严格模式:字符串格式不正确,请输入true或者false"); + } + } + + if (item.getValue() instanceof Number) { + if (BigDecimal.ONE.compareTo(BigDecimal.valueOf(((Number) item.getValue()).doubleValue())) == 0) { + itemValue = true; + } else if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(((Number) item.getValue()).doubleValue())) != 0) { + throw new IllegalStateException("严格模式:数值格式不正确,请输入1.0或者0.0"); + } + } + + } else { + + if (item.getValue() instanceof String) { + if ((stringIgnoreCase && "true".equalsIgnoreCase((String) item.getValue())) + || (!stringIgnoreCase && "true".equals(item.getValue()))) { + itemValue = true; + } + } + if (item.getValue() instanceof Number) { + if (BigDecimal.ONE.compareTo(BigDecimal.valueOf(((Number) item.getValue()).doubleValue())) == 0) { + itemValue = true; + } + } + } + if (item.getValue() instanceof Boolean) { + itemValue = (Boolean) item.getValue(); + } + + return new Item( + item.getPointKey(), + itemValue, + item.getHappenedDate() + ); + } + + @Override + public String toString() { + return "ToBooleanMapper{}"; + } + } + + public static class Config implements Bean { + + private static final long serialVersionUID = 6070172089803753762L; + + @JSONField(name = "strict", ordinal = 1) + private boolean strict; + + @JSONField(name = "#strict", ordinal = 2, deserialize = false) + private String onlyTrimStartRem = "true:启用严格模式,不符合直接抛出异常;false:不启用严格模式,不符合转为false"; + + @JSONField(name = "string_ignore_case", ordinal = 3) + private boolean stringIgnoreCase; + + @JSONField(name = "#string_ignore_case", ordinal = 4, deserialize = false) + private String stringIgnoreCaseRem = "true:忽略字符串大小写,false:不忽略大小写"; + + @JSONField(name = "#specification", ordinal = 5, deserialize = false) + private String specificationRem = + " 字符串真值:true \n" + + " 字符串假值:false \n" + + " 数字真值:1.0 \n" + + " 数字假值:0.0 \n"; + + public Config() { + } + + public Config(boolean strict, boolean stringIgnoreCase) { + this.strict = strict; + this.stringIgnoreCase = stringIgnoreCase; + } + + public boolean getStrict() { + return strict; + } + + public void setStrict(boolean strict) { + this.strict = strict; + } + + public String getOnlyTrimStartRem() { + return onlyTrimStartRem; + } + + public void setOnlyTrimStartRem(String onlyTrimStartRem) { + this.onlyTrimStartRem = onlyTrimStartRem; + } + + public boolean getStringIgnoreCase() { + return stringIgnoreCase; + } + + public void setStringIgnoreCase(boolean stringIgnoreCase) { + this.stringIgnoreCase = stringIgnoreCase; + } + + public String getStringIgnoreCaseRem() { + return stringIgnoreCaseRem; + } + + public void setStringIgnoreCaseRem(String stringIgnoreCaseRem) { + this.stringIgnoreCaseRem = stringIgnoreCaseRem; + } + + public String getSpecificationRem() { + return specificationRem; + } + + public void setSpecificationRem(String specificationRem) { + this.specificationRem = specificationRem; + } + + @Override + public String toString() { + return "Config{" + + "strict=" + strict + + ", onlyTrimStartRem='" + onlyTrimStartRem + '\'' + + ", stringIgnoreCase=" + stringIgnoreCase + + ", stringIgnoreCaseRem='" + stringIgnoreCaseRem + '\'' + + ", specificationRem='" + specificationRem + '\'' + + '}'; + } + } +} diff --git a/fdr-impl/src/main/java/com/dwarfeng/fdr/impl/handler/mapper/TrimMapperRegistry.java b/fdr-impl/src/main/java/com/dwarfeng/fdr/impl/handler/mapper/TrimMapperRegistry.java new file mode 100644 index 0000000000000000000000000000000000000000..98a834bf4d6feaf59c7eda2f66023948d29340a8 --- /dev/null +++ b/fdr-impl/src/main/java/com/dwarfeng/fdr/impl/handler/mapper/TrimMapperRegistry.java @@ -0,0 +1,144 @@ +package com.dwarfeng.fdr.impl.handler.mapper; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.annotation.JSONField; +import com.dwarfeng.fdr.sdk.util.CompareUtil; +import com.dwarfeng.fdr.stack.exception.MapperException; +import com.dwarfeng.fdr.stack.exception.MapperMakeException; +import com.dwarfeng.fdr.stack.handler.Mapper; +import com.dwarfeng.subgrade.stack.bean.Bean; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + + +/** + * 裁剪映射器注册。 + * + *

+ * 用于裁剪序列的起始时间和结束时间。映射器工作时会寻找序列中发生时间最早和最晚的数据, + * 然后将这两个数据的发生时间作为序列的起始时间和结束时间。 + * + * @author mooyuan + * @since 2.0.0 + */ +@Component +public class TrimMapperRegistry extends AbstractMapperRegistry { + + public static final String MAPPER_TYPE = "trim_mapper"; + + private final ApplicationContext ctx; + + public TrimMapperRegistry(ApplicationContext ctx) { + super(MAPPER_TYPE); + this.ctx = ctx; + } + + + @Override + public Mapper makeMapper() throws MapperException { + try { + return ctx.getBean(TrimMapper.class); + } catch (Exception e) { + throw new MapperMakeException(e); + } + } + + @Override + public String provideLabel() { + return "裁剪映射器"; + } + + @Override + public String provideDescription() { + return "映射器工作时会寻找序列中发生时间最早和最晚的数据,然后将这两个数据的发生时间作为序列的起始时间和结束时间,若使用 only_trim_start 配置项可以只裁剪序列的起始时间。"; + } + + @Override + public String provideExampleParam() { + return JSON.toJSONString(new Config(false)); + } + + @Component + @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) + public static class TrimMapper extends OneToOneMapper { + + @Override + protected Sequence doOneToOneMap(MapParam mapParam, Sequence sequence) { + + // 获得配置。 + Config config = JSON.parseObject(mapParam.getParam(), Config.class); + + return trimSequence(sequence, config.getOnlyTrimStart()); + } + + // 排序并截取序列 + private Sequence trimSequence(Sequence sequence, boolean only_trim_start) { + // 获取序列的起始时间与结束时间。 + List items = new ArrayList<>(sequence.getItems()); + items.sort(CompareUtil.DATA_HAPPENED_DATE_ASC_COMPARATOR); + + Date startDate = items.get(0).getHappenedDate(); + Date endDate = items.get(items.size() - 1).getHappenedDate(); + + // 如果起始时间等于结束时间只取一个值即可 + if (only_trim_start) { + + endDate = sequence.getEndDate(); + } + + // 返回新的序列 + return new Sequence(sequence.getPointKey(), items, startDate, endDate); + } + + @Override + public String toString() { + return "TrimMapper{}"; + } + + } + + public static class Config implements Bean { + + private static final long serialVersionUID = 3688860693739279015L; + + @JSONField(name = "only_trim_start", ordinal = 1) + private boolean onlyTrimStart = false; + + @JSONField(name = "#only_trim_start", ordinal = 2, deserialize = false) + private String onlyTrimStartRem = "当onlyTrimStart为true时只剪裁序列的起始时间,false裁剪序列的起始时间和结束时间"; + + public Config() { + } + + public Config(boolean onlyTrimStart) { + this.onlyTrimStart = onlyTrimStart; + } + + public boolean getOnlyTrimStart() { + return onlyTrimStart; + } + + public void setOnlyTrimStart(boolean onlyTrimStart) { + this.onlyTrimStart = onlyTrimStart; + } + + public String getOnlyTrimStartRem() { + return onlyTrimStartRem; + } + + public void setOnlyTrimStartRem(String onlyTrimStartRem) { + this.onlyTrimStartRem = onlyTrimStartRem; + } + + @Override + public String toString() { + return "Config{" + "onlyTrimStart=" + onlyTrimStart + ", onlyTrimStartRem='" + onlyTrimStartRem + '\'' + '}'; + } + } +} diff --git a/fdr-node/src/main/resources/opt/opt-mapper.xml b/fdr-node/src/main/resources/opt/opt-mapper.xml index f61a7bd344357a8b6e8c19ee64af782d35fdf074..dce83368763b0ab28833565e26af417446c51df3 100644 --- a/fdr-node/src/main/resources/opt/opt-mapper.xml +++ b/fdr-node/src/main/resources/opt/opt-mapper.xml @@ -95,5 +95,69 @@ type="assignable" expression="com.dwarfeng.fdr.impl.handler.mapper.MergeMapperRegistry" /> --> + + + + + + + + + + + + + + + + + + + + + + + + + + + +