Commit ede5bef5 authored by zhoushiguang's avatar zhoushiguang

Merge remote-tracking branch 'origin/master'

parents 6b2fdf0c 9b76d884
...@@ -6,14 +6,11 @@ import net.wanji.databus.dao.entity.GreenwaveInfoPO; ...@@ -6,14 +6,11 @@ import net.wanji.databus.dao.entity.GreenwaveInfoPO;
import net.wanji.databus.dao.mapper.GreenwaveCrossMapper; import net.wanji.databus.dao.mapper.GreenwaveCrossMapper;
import net.wanji.databus.dao.mapper.GreenwaveInfoMapper; import net.wanji.databus.dao.mapper.GreenwaveInfoMapper;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.LocalTime; import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
...@@ -28,7 +25,7 @@ import java.util.stream.Collectors; ...@@ -28,7 +25,7 @@ import java.util.stream.Collectors;
@Slf4j @Slf4j
public class CrossGreenWaveInfoCache implements InitializingBean { public class CrossGreenWaveInfoCache implements InitializingBean {
;public static final Map<Integer, List<GreenwaveCrossPO>> greenWaveInfoMap = new HashMap<>(); public static final Map<Integer, List<GreenwaveCrossPO>> greenWaveInfoMap = new HashMap<>();
@Resource @Resource
private GreenwaveInfoMapper greenwaveInfoMapper; private GreenwaveInfoMapper greenwaveInfoMapper;
......
...@@ -51,6 +51,8 @@ public class CrossSchemePhaseLightsCache implements CommandLineRunner { ...@@ -51,6 +51,8 @@ public class CrossSchemePhaseLightsCache implements CommandLineRunner {
Integer phaseId = crossPhasePO.getId(); Integer phaseId = crossPhasePO.getId();
String phaseNo = crossPhasePO.getPhaseNo(); String phaseNo = crossPhasePO.getPhaseNo();
Integer redTime = crossPhasePO.getRedTime(); Integer redTime = crossPhasePO.getRedTime();
Integer phaseTime = crossPhasePO.getPhaseTime();
Integer greenTime = crossPhasePO.getGreenTime();
List<CrossPhaseLightsPO> crossPhaseLightsPOList = baseCrossPhaseLightsMapper.selectByPhaseId(phaseId); List<CrossPhaseLightsPO> crossPhaseLightsPOList = baseCrossPhaseLightsMapper.selectByPhaseId(phaseId);
if (!CollectionUtils.isEmpty(crossPhaseLightsPOList)) { if (!CollectionUtils.isEmpty(crossPhaseLightsPOList)) {
for (CrossPhaseLightsPO crossPhaseLightsPO : crossPhaseLightsPOList) { for (CrossPhaseLightsPO crossPhaseLightsPO : crossPhaseLightsPOList) {
...@@ -66,6 +68,8 @@ public class CrossSchemePhaseLightsCache implements CommandLineRunner { ...@@ -66,6 +68,8 @@ public class CrossSchemePhaseLightsCache implements CommandLineRunner {
if (turn == 20) { if (turn == 20) {
continue; continue;
} }
crossSchemePhaseDirTurnDTO.setPhaseTime(phaseTime);
crossSchemePhaseDirTurnDTO.setGreenTime(greenTime);
crossSchemePhaseDirTurnDTO.setRedTime(redTime); crossSchemePhaseDirTurnDTO.setRedTime(redTime);
crossSchemePhaseDirTurnDTO.setLightsTurn(turn); crossSchemePhaseDirTurnDTO.setLightsTurn(turn);
crossSchemePhaseDirTurnDTOList.add(crossSchemePhaseDirTurnDTO); crossSchemePhaseDirTurnDTOList.add(crossSchemePhaseDirTurnDTO);
......
...@@ -13,5 +13,7 @@ public class CrossSchemePhaseDirTurnDTO { ...@@ -13,5 +13,7 @@ public class CrossSchemePhaseDirTurnDTO {
private String phaseNo; private String phaseNo;
private Integer lightsDir; private Integer lightsDir;
private Integer lightsTurn; private Integer lightsTurn;
private Integer phaseTime;
private Integer greenTime;
private Integer redTime; private Integer redTime;
} }
package net.wanji.datacenter.task;
import lombok.extern.slf4j.Slf4j;
import net.wanji.databus.dao.entity.BaseCrossSchemePO;
import net.wanji.databus.dao.entity.CrossSectionPO;
import net.wanji.databus.dao.entity.GreenwaveCrossPO;
import net.wanji.databus.dao.mapper.BaseCrossSchemeMapper;
import net.wanji.databus.dao.mapper.BaseCrossSectionMapper;
import net.wanji.datacenter.cache.CrossGreenWaveInfoCache;
import net.wanji.datacenter.cache.CrossSchemePhaseLightsCache;
import net.wanji.datacenter.cache.WeekDirFreeFlowSpeedCache;
import net.wanji.datacenter.pojo.dto.CrossSchemePhaseDirTurnDTO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* @author duanruiming
* @description 每天凌晨更新自由流速度
* @date 2023/10/14 9:22
*/
@Component
@Slf4j
public class DataCenterTask {
@Resource
private WeekDirFreeFlowSpeedCache weekDirFreeFlowSpeedCache;
@Resource
private BaseCrossSectionMapper baseCrossSectionMapper;
@Resource
private BaseCrossSchemeMapper baseCrossSchemeMapper;
@Scheduled(cron = "0 0 0 * * ?")
public void getWeekFreeFlowSpeed() throws Exception {
weekDirFreeFlowSpeedCache.run();
}
@Scheduled(initialDelay = 1000 * 60, fixedRate = 1000 * 60 * 60)
public void getGreenWaveWidth() throws Exception {
try {
Map<Integer, List<GreenwaveCrossPO>> greenWaveInfoMap = CrossGreenWaveInfoCache.greenWaveInfoMap;
int greenwaveWidth = 100;
for (Map.Entry<Integer, List<GreenwaveCrossPO>> entry : greenWaveInfoMap.entrySet()) {
Integer greenId = entry.getKey();
Double lastCrossDistance = 0.0; // 当前路口与上一路口距离
int crossTimeOffset = 0; // 上一路口到当前路口设计速度下时间差
int greenDelayTime = 0; // 每个路口绿波开始时间
List<GreenwaveCrossPO> greenwaveCrossPOList = entry.getValue();
if (!CollectionUtils.isEmpty(greenwaveCrossPOList)) {
for (GreenwaveCrossPO greenwaveCrossPO : greenwaveCrossPOList) {
String crossId = greenwaveCrossPO.getCrossId();
Integer sectionId = greenwaveCrossPO.getSectionId();
Integer inDir = greenwaveCrossPO.getInDir();
Integer offset = greenwaveCrossPO.getOffset();
crossTimeOffset += (int) (lastCrossDistance / (100 / 6)); // 自由流速度60
if (sectionId != null) {
CrossSectionPO crossSectionPO = baseCrossSectionMapper.selectById(sectionId);
if (Objects.nonNull(crossSectionPO)) {
Integer schemeId = crossSectionPO.getSchemeId();
BaseCrossSchemePO baseCrossSchemePO = baseCrossSchemeMapper.selectById(schemeId);
if (Objects.nonNull(baseCrossSchemePO)) {
String schemeNo = baseCrossSchemePO.getSchemeNo();
List<CrossSchemePhaseDirTurnDTO> crossSchemePhaseDirTurnDTOList = CrossSchemePhaseLightsCache.crossSchemePhaseDirTurnDTOList;
if (!CollectionUtils.isEmpty(crossSchemePhaseDirTurnDTOList)) {
// 过滤路口编号,方案号,直行或者圆饼灯,
List<CrossSchemePhaseDirTurnDTO> currenSchemeList = crossSchemePhaseDirTurnDTOList.stream().filter(po -> StringUtils.equals(crossId, po.getCrossId()) &&
StringUtils.equals(po.getSchemeNo(), schemeNo) &&
(Objects.equals(po.getLightsTurn(), 3) || Objects.equals(po.getLightsTurn(), 1))).collect(Collectors.toList());
Integer lastPhaseTime = 0; // 上一个相位的时间
for (CrossSchemePhaseDirTurnDTO dto : currenSchemeList) {
// 当前路口方案绿波方向的绿灯时间
lastPhaseTime += dto.getPhaseTime();
if (Objects.equals(inDir, dto.getLightsDir())) {
lastPhaseTime -= dto.getPhaseTime();
greenDelayTime = lastPhaseTime > greenDelayTime ? lastPhaseTime : greenDelayTime;
Integer greenWaveStartIndex = offset + greenDelayTime + crossTimeOffset;
Integer greenWaveEndIndex = offset + dto.getPhaseTime();
greenwaveWidth = Math.min(greenwaveWidth, greenWaveEndIndex - greenWaveStartIndex);
}
}
}
}
}
}
lastCrossDistance = greenwaveCrossPO.getNextCrossLen();
}
}
log.info("当前绿波编号:{}, 绿波带宽:{}", greenId, greenwaveWidth);
}
} catch (Exception e) {
log.error("获取绿波带宽异常", e);
throw new Exception("获取绿波带宽异常", e);
}
}
}
package net.wanji.datacenter.task;
import lombok.extern.slf4j.Slf4j;
import net.wanji.datacenter.cache.WeekDirFreeFlowSpeedCache;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @author duanruiming
* @description 每天凌晨更新自由流速度
* @date 2023/10/14 9:22
*/
@Component
@Slf4j
public class WeekFreeFlowSpeedTask {
@Resource
private WeekDirFreeFlowSpeedCache weekDirFreeFlowSpeedCache;
@Scheduled(cron = "0 0 0 * * ?")
public void getWeekFreeFlowSpeed() throws Exception {
weekDirFreeFlowSpeedCache.run();
}
}
...@@ -73,6 +73,16 @@ public class Constant { ...@@ -73,6 +73,16 @@ public class Constant {
*/ */
public static int CROSSING = 1; public static int CROSSING = 1;
/**
* 行人灯转向
*/
public static final String PEDESTRAIN_LIGHT_CODE = "20";
/**
* 右转灯转向
*/
public static final String RIGHT_LIGHT_CODE = "3";
/** /**
* 入侵结果 * 入侵结果
*/ */
......
package com.wanji.indicators.task.trajectory; package com.wanji.indicators.task.trajectory;
import java.util.UUID; import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/** /**
* @author : jenny * @author : jenny
...@@ -10,7 +12,11 @@ import java.util.UUID; ...@@ -10,7 +12,11 @@ import java.util.UUID;
*/ */
public class Test2 { public class Test2 {
public static void main(String[] args) { public static void main(String[] args) {
String eventSerialNumber = UUID.randomUUID().toString().replace("-",""); List<String> list = new ArrayList<>();
System.out.println(eventSerialNumber); List<String> filteredList = list.stream()
.filter(element -> element.length() > 4)
.collect(Collectors.toList());
System.out.println(filteredList.size());
} }
} }
...@@ -88,6 +88,6 @@ public class CarDataValidatorFlatMap implements FlatMapFunction<FrameModel, CarT ...@@ -88,6 +88,6 @@ public class CarDataValidatorFlatMap implements FlatMapFunction<FrameModel, CarT
} }
public static boolean isQualifiedPlate(String plate){ public static boolean isQualifiedPlate(String plate){
return StringUtils.isNotEmpty(plate) && !Objects.equals("null", plate) && !Objects.equals("默A00000", plate); return StringUtils.isNotEmpty(plate) && !Objects.equals("null", plate) && !plate.contains("00000");
} }
} }
package com.wanji.indicators.task.trajectory.func;
import com.wanji.indicators.task.trajectory.CarTrajectoryIndexMain;
import com.wanji.indicators.task.trajectory.pojo.CongestionResult;
import com.wanji.indicators.task.trajectory.pojo.StartDuration;
import org.apache.flink.api.common.state.MapState;
import org.apache.flink.api.common.state.MapStateDescriptor;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.functions.KeyedProcessFunction;
import org.apache.flink.util.Collector;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Iterator;
/**
* 协调方向拥堵数据
*
* @author Kent HAN
* @date 2023/11/14 10:02
*/
public class CoordCongestionDataFunction extends KeyedProcessFunction<String, CongestionResult, CongestionResult> {
// Key:方向
private MapState<Integer, StartDuration> dirState;
@Override
public void open(Configuration parameters) throws Exception {
dirState = getRuntimeContext()
.getMapState(new MapStateDescriptor<>("dir_map",
Integer.class, StartDuration.class));
}
@Override
public void processElement(CongestionResult value,
KeyedProcessFunction<String, CongestionResult, CongestionResult>.Context ctx,
Collector<CongestionResult> out) throws Exception {
String rid = ctx.getCurrentKey();
Integer dir = CarTrajectoryIndexMain.ridEndIndirMap.get(rid);
value.setDir(dir);
Double index = value.getIndex();
boolean isCongestion = index > 1.5;
Integer stateKey = dir;
if (isCongestion) {
try {
if (!dirState.contains(stateKey)) {
StartDuration startDuration = new StartDuration();
// 获取当前的时间戳
Instant now = Instant.now();
// 获取1分钟前的时间戳
Instant oneMinuteBefore = now.minus(1, ChronoUnit.MINUTES);
// 转换成毫秒
long startTimeMilli = oneMinuteBefore.toEpochMilli();
value.setStartTime(startTimeMilli);
startDuration.setStartTime(startTimeMilli);
long nowMilli = now.toEpochMilli();
long durationMilli = nowMilli - startTimeMilli;
int durationInt = (int) durationMilli / (1000 * 60);
value.setDuration(durationInt);
startDuration.setDuration(durationInt);
dirState.put(stateKey, startDuration);
} else {
StartDuration startDuration = dirState.get(stateKey);
Long startTimeMilli = startDuration.getStartTime();
value.setStartTime(startTimeMilli);
Instant now = Instant.now();
long nowMilli = now.toEpochMilli();
long durationMilli = nowMilli - startTimeMilli;
int durationInt = (int) durationMilli / (1000 * 60);
startDuration.setDuration(durationInt);
value.setDuration(durationInt);
dirState.put(stateKey, startDuration);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
} else {
// 删除状态
try {
Iterator<Integer> mapStateIterator = dirState.keys().iterator();
while (mapStateIterator.hasNext()){
Integer key = mapStateIterator.next();
if(key.equals(stateKey)){
mapStateIterator.remove();
}
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
out.collect(value);
}
}
package com.wanji.indicators.task.trajectory.func;
import com.wanji.indicators.constant.CongestEnum;
import com.wanji.indicators.task.trajectory.CarTrajectoryIndexMain;
import com.wanji.indicators.task.trajectory.pojo.CongestionResult;
import com.wanji.indicators.task.trajectory.pojo.StartDuration;
import org.apache.flink.api.common.state.MapState;
import org.apache.flink.api.common.state.MapStateDescriptor;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.functions.ProcessFunction;
import org.apache.flink.util.Collector;
import java.time.Instant;
import java.util.*;
public class MergeCongestionFunction extends ProcessFunction<CongestionResult, CongestionResult> {
// 保存 dirCongestion 的状态,Key:路口Id-方向,Value:指数
private MapState<String, Double> dirState;
// 保存开始时间和持续时长。Key:路口ID
private MapState<String, StartDuration> crossState;
@Override
public void open(Configuration parameters) throws Exception {
MapStateDescriptor<String, Double> dirStateDescriptor = new MapStateDescriptor<>(
"dirState", String.class, Double.class);
MapStateDescriptor<String, StartDuration> crossStateDescriptor = new MapStateDescriptor<>(
"crossState", String.class, StartDuration.class);
dirState = getRuntimeContext().getMapState(dirStateDescriptor);
crossState = getRuntimeContext().getMapState(crossStateDescriptor);
}
@Override
public void processElement(CongestionResult value,
ProcessFunction<CongestionResult, CongestionResult>.Context ctx,
Collector<CongestionResult> out) throws Exception {
String crossId = value.getCrossId();
Integer dir = value.getDir();
String stateKey = crossId + "-" + dir;
Double index = value.getIndex();
dirState.put(stateKey, index);
Iterable<String> dirKeys = dirState.keys();
List<String> crossDirs = CarTrajectoryIndexMain.crossDirs.get(crossId);
if (dirKeys != null) {
// 路口各方向数据是否齐全
Set<String> allKeys = new HashSet<>();
dirKeys.forEach(allKeys::add);
boolean containsAll = allKeys.containsAll(crossDirs);
if (containsAll) {
Map<String, Double> dirIndexMap = new HashMap<>();
for (String crossDir : crossDirs) {
Double v = dirState.get(crossDir);
dirIndexMap.put(crossDir, v);
}
// 加总 延时指数*车道数量
double numeratorSum = 0.0;
int laneCountsSum = 0;
boolean isAllDirsCongestion = true; // 所有路口是否拥堵
for (Map.Entry<String, Double> entry : dirIndexMap.entrySet()) {
Double dirIndex = entry.getValue();
// 车道数量
String key = entry.getKey();
Integer laneCounts = CarTrajectoryIndexMain.dirLaneCounts.get(key);
double numerator = dirIndex * laneCounts;
numeratorSum += numerator;
laneCountsSum += laneCounts;
if (dirIndex <= 0.6) {
isAllDirsCongestion = false;
}
}
double crossIndex = numeratorSum / laneCountsSum;
CongestionResult congestionResult = new CongestionResult();
congestionResult.setCrossId(crossId);
congestionResult.setIndex(crossIndex);
boolean isCrossCongestion = false;
if (crossIndex >= 2 && isAllDirsCongestion) {
isCrossCongestion = true;
}
String crossStateKey = crossId;
if (isCrossCongestion) {
String indexName;
String congestionType;
if (crossIndex <= 2.0) {
indexName = "轻度拥堵";
congestionType = CongestEnum.LIGHT_CONGEST.getType();
} else if (crossIndex <= 3.0) {
indexName = "中度拥堵";
congestionType = CongestEnum.MODERATE_CONGEST.getType();
} else {
indexName = "重度拥堵";
congestionType = CongestEnum.HEAVY_CONGEST.getType();
}
congestionResult.setIndexName(indexName);
congestionResult.setCongestionType(congestionType);
// 保存状态
try {
if (!crossState.contains(crossStateKey)) {
StartDuration startDuration = new StartDuration();
// 获取当前的时间戳
Instant now = Instant.now();
long nowTimeMilli = now.toEpochMilli();
congestionResult.setStartTime(nowTimeMilli);
startDuration.setStartTime(nowTimeMilli);
congestionResult.setDuration(0);
startDuration.setDuration(0);
crossState.put(crossStateKey, startDuration);
} else {
StartDuration startDuration = crossState.get(crossStateKey);
Long startTimeMilli = startDuration.getStartTime();
congestionResult.setStartTime(startTimeMilli);
Instant now = Instant.now();
long nowMilli = now.toEpochMilli();
long durationMilli = nowMilli - startTimeMilli;
int durationInt = (int) durationMilli / (1000 * 60);
startDuration.setDuration(durationInt);
congestionResult.setDuration(durationInt);
crossState.put(crossStateKey, startDuration);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
} else {
// 删除状态
try {
Iterator<String> mapStateIterator = crossState.keys().iterator();
while (mapStateIterator.hasNext()){
String key = mapStateIterator.next();
if(key.equals(crossStateKey)){
mapStateIterator.remove();
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
out.collect(congestionResult);
}
}
}
}
\ No newline at end of file
package com.wanji.indicators.task.trajectory.func; package com.wanji.indicators.task.trajectory.func;
import com.wanji.indicators.model.CarTrackModel; import com.wanji.indicators.model.CarTrackModel;
import com.wanji.indicators.task.trajectory.pojo.OverFlowIndexResult; import com.wanji.indicators.task.trajectory.pojo.OverFlowAndDeadlockEvent;
import org.apache.flink.streaming.api.functions.windowing.ProcessWindowFunction; import org.apache.flink.streaming.api.functions.windowing.ProcessWindowFunction;
import org.apache.flink.streaming.api.windowing.windows.TimeWindow; import org.apache.flink.streaming.api.windowing.windows.TimeWindow;
import org.apache.flink.util.Collector; import org.apache.flink.util.Collector;
...@@ -9,9 +9,7 @@ import org.apache.flink.util.Collector; ...@@ -9,9 +9,7 @@ import org.apache.flink.util.Collector;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport; import java.util.stream.StreamSupport;
/** /**
...@@ -20,7 +18,7 @@ import java.util.stream.StreamSupport; ...@@ -20,7 +18,7 @@ import java.util.stream.StreamSupport;
* @createTime : 2023/10/27 10:39 * @createTime : 2023/10/27 10:39
* @Description : * @Description :
*/ */
public class ProcessOverFlowFunction extends ProcessWindowFunction<CarTrackModel, OverFlowIndexResult, String, TimeWindow> { public class ProcessOverFlowFunction extends ProcessWindowFunction<CarTrackModel, OverFlowAndDeadlockEvent, String, TimeWindow> {
private Integer agvSpeed = 5; private Integer agvSpeed = 5;
private Integer duration = 3; private Integer duration = 3;
...@@ -42,7 +40,7 @@ public class ProcessOverFlowFunction extends ProcessWindowFunction<CarTrackModel ...@@ -42,7 +40,7 @@ public class ProcessOverFlowFunction extends ProcessWindowFunction<CarTrackModel
} }
@Override @Override
public void process(String s, ProcessWindowFunction<CarTrackModel, OverFlowIndexResult, String, TimeWindow>.Context context, Iterable<CarTrackModel> iterable, Collector<OverFlowIndexResult> collector) throws Exception { public void process(String s, ProcessWindowFunction<CarTrackModel, OverFlowAndDeadlockEvent, String, TimeWindow>.Context context, Iterable<CarTrackModel> iterable, Collector<OverFlowAndDeadlockEvent> collector) throws Exception {
List<CarTrackModel> carInCrossRoadList = StreamSupport.stream(iterable.spliterator(), false).collect(Collectors.toList()); List<CarTrackModel> carInCrossRoadList = StreamSupport.stream(iterable.spliterator(), false).collect(Collectors.toList());
} }
} }
package com.wanji.indicators.task.trajectory.func;
import com.wanji.indicators.constant.CongestEnum;
import com.wanji.indicators.task.trajectory.pojo.CongestionResult;
import com.wanji.indicators.task.trajectory.pojo.StartDuration;
import com.wanji.indicators.task.trajectory.pojo.UnbalanceResult;
import com.wanji.indicators.util.DateUtil;
import org.apache.flink.api.common.state.MapState;
import org.apache.flink.api.common.state.MapStateDescriptor;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.functions.windowing.ProcessWindowFunction;
import org.apache.flink.streaming.api.windowing.windows.TimeWindow;
import org.apache.flink.util.Collector;
import org.springframework.util.CollectionUtils;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
/**
* @author Kent HAN
* @date 2023/11/16 17:45
*/
public class UnbalanceFunction extends ProcessWindowFunction<CongestionResult, UnbalanceResult, String, TimeWindow> {
// 开始时间和持续时长状态。Key:路口ID
private MapState<String, StartDuration> crossState;
@Override
public void open(Configuration parameters) {
crossState = getRuntimeContext()
.getMapState(new MapStateDescriptor<>(
"crossState", String.class, StartDuration.class));
}
@Override
public void process(String crossId, ProcessWindowFunction<CongestionResult, UnbalanceResult, String, TimeWindow>.Context context, Iterable<CongestionResult> iterable, Collector<UnbalanceResult> collector) throws Exception {
List<CongestionResult> collect = StreamSupport.stream(iterable.spliterator(), false)
.collect(Collectors.toList());
if (!CollectionUtils.isEmpty(collect) && collect.size() > 1) {
// 获取拥堵指数最大和最小的元素
Optional<CongestionResult> maxElement = collect.stream()
.max(Comparator.comparingDouble(CongestionResult::getIndex));
CongestionResult maxCongestionResult = maxElement.get();
Optional<CongestionResult> minElement = collect.stream()
.min(Comparator.comparingDouble(CongestionResult::getIndex));
CongestionResult minCongestionResult = minElement.get();
Double maxIndex = maxCongestionResult.getIndex();
Double minIndex = minCongestionResult.getIndex();
String maxName = maxCongestionResult.getIndexName();
String minName = minCongestionResult.getIndexName();
double index = maxIndex / minIndex;
String name = CongestEnum.NO_CONGEST.getName();
if (index >= 1.5 && !name.equals(maxName) && !name.equals(minName)) {
// 出现失衡
UnbalanceResult result = new UnbalanceResult();
result.setCrossId(crossId);
result.setIndex(index);
result.setGlobalTimeStamp(new Date().getTime());
result.setTimestamp(DateUtil.toDateTime(result.getGlobalTimeStamp(), DateUtil.YYYY_MM_DD_HH_MM_SS));
try {
if (!crossState.contains(crossId)) {
StartDuration startDuration = new StartDuration();
// 获取当前的时间戳
Instant now = Instant.now();
// 获取1分钟前的时间戳
Instant before = now.minus(1, ChronoUnit.MINUTES);
// 转换成毫秒
long beforeMilli = before.toEpochMilli();
result.setStartTime(beforeMilli);
startDuration.setStartTime(beforeMilli);
long nowMilli = now.toEpochMilli();
long durationMilli = nowMilli - beforeMilli;
int durationInt = (int) durationMilli / (1000 * 60);
result.setDuration(durationInt);
startDuration.setDuration(durationInt);
crossState.put(crossId, startDuration);
} else {
StartDuration startDuration = crossState.get(crossId);
Long startTimeMilli = startDuration.getStartTime();
result.setStartTime(startTimeMilli);
Instant now = Instant.now();
long nowMilli = now.toEpochMilli();
long durationMilli = nowMilli - startTimeMilli;
int durationInt = (int) durationMilli / (1000 * 60);
startDuration.setDuration(durationInt);
result.setDuration(durationInt);
crossState.put(crossId, startDuration);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
collector.collect(result);
} else {
// 删除状态
try {
Iterator<String> iter = crossState.keys().iterator();
while (iter.hasNext()){
String key = iter.next();
if(key.equals(crossId)){
iter.remove();
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
}
...@@ -14,7 +14,6 @@ import org.springframework.util.CollectionUtils; ...@@ -14,7 +14,6 @@ import org.springframework.util.CollectionUtils;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
...@@ -36,7 +35,8 @@ public class CarTrackInCrossRoadFlatMap implements FlatMapFunction<FrameModel, C ...@@ -36,7 +35,8 @@ public class CarTrackInCrossRoadFlatMap implements FlatMapFunction<FrameModel, C
//判断车辆轨迹数据在指定区域内 //判断车辆轨迹数据在指定区域内
Map<String, List<CrossExitInfo>> crossExitMap = CarTrajectoryIndexMain.crossExitMap; Map<String, List<CrossExitInfo>> crossExitMap = CarTrajectoryIndexMain.crossExitMap;
for(Map.Entry<String, List<CrossExitInfo>> entry: crossExitMap.entrySet()){ for(Map.Entry<String, List<CrossExitInfo>> entry: crossExitMap.entrySet()){
Map<String, String> ridAndAreaCoordinates = entry.getValue().stream().collect(Collectors.toMap(CrossExitInfo::getRid, CrossExitInfo::getCoordinates)); Map<String, String> ridAndAreaCoordinates = entry.getValue().stream()
.collect(Collectors.toMap(CrossExitInfo::getRid, CrossExitInfo::getCoordinates));
if(ridAndAreaCoordinates.containsKey(car.getRoadnet().getRid())){ if(ridAndAreaCoordinates.containsKey(car.getRoadnet().getRid())){
String coordinates = ridAndAreaCoordinates.get(car.getRoadnet().getRid()); String coordinates = ridAndAreaCoordinates.get(car.getRoadnet().getRid());
boolean inPolygon = GeomsConvertUtil.isInPolygon(car.getLongitude(), car.getLatitude(), coordinates); boolean inPolygon = GeomsConvertUtil.isInPolygon(car.getLongitude(), car.getLatitude(), coordinates);
......
...@@ -9,7 +9,10 @@ import lombok.Data; ...@@ -9,7 +9,10 @@ import lombok.Data;
* @Description : * @Description :
*/ */
@Data @Data
public class RidIndexResultOfEastAndWest { public class CongestionResult {
private Integer dir;
private String rid; private String rid;
//该路段的结束路口 //该路段的结束路口
private String crossId; private String crossId;
...@@ -27,4 +30,7 @@ public class RidIndexResultOfEastAndWest { ...@@ -27,4 +30,7 @@ public class RidIndexResultOfEastAndWest {
private Long startTime; private Long startTime;
private Long endTime; private Long endTime;
private Integer duration;
} }
package com.wanji.indicators.task.trajectory.pojo;
import lombok.Data;
import java.util.List;
/**
* @author : jenny
* @version : 1.0
* @createTime : 2023/10/27 10:03
* @Description :
*/
@Data
public class OverFlowAndDeadlockEvent {
private String crossId;
private List<OverFlowDetail> details;
private boolean deadlock;
private Long overflowStartTime;
private Integer overflowDuration;
private Double overflowIndex;
private Long deadlockStartTime;
private Integer deadlockDuration;
private Long globalTimeStamp;
private String dateTime;
private Long endTime;
}
...@@ -12,6 +12,13 @@ import lombok.Data; ...@@ -12,6 +12,13 @@ import lombok.Data;
public class OverFlowDetail { public class OverFlowDetail {
//出现溢出的路口出口所在路段名称 //出现溢出的路口出口所在路段名称
private String rid; private String rid;
private String crossId;
private Long startTime;
private Integer duration;
//溢出指数 //溢出指数
private Double index; private Double index;
//溢出发生时间戳 //溢出发生时间戳
......
package com.wanji.indicators.task.trajectory.pojo;
import java.util.List;
/**
* @author : jenny
* @version : 1.0
* @createTime : 2023/10/27 10:03
* @Description :
*/
public class OverFlowIndexResult {
//发生溢出的路口id
private String crossId;
private List<OverFlowDetail> details;
private boolean isDeadLock;
private Long globalTimeStamp;
private String dateTime;
private Long startTime;
private Long endTime;
public String getCrossId() {
return crossId;
}
public void setCrossId(String crossId) {
this.crossId = crossId;
}
public List<OverFlowDetail> getDetails() {
return details;
}
public void setDetails(List<OverFlowDetail> details) {
this.details = details;
}
public boolean isDeadLock() {
return isDeadLock;
}
public void setDeadLock(boolean deadLock) {
isDeadLock = deadLock;
}
public Long getGlobalTimeStamp() {
return globalTimeStamp;
}
public void setGlobalTimeStamp(Long globalTimeStamp) {
this.globalTimeStamp = globalTimeStamp;
}
public String getDateTime() {
return dateTime;
}
public void setDateTime(String dateTime) {
this.dateTime = dateTime;
}
public Long getStartTime() {
return startTime;
}
public void setStartTime(Long startTime) {
this.startTime = startTime;
}
public Long getEndTime() {
return endTime;
}
public void setEndTime(Long endTime) {
this.endTime = endTime;
}
}
...@@ -19,7 +19,7 @@ public class PhaseEmptyResult { ...@@ -19,7 +19,7 @@ public class PhaseEmptyResult {
private String turn; private String turn;
//转向空放时间/绿灯总时长 //转向空放时间/绿灯总时长
private double index; private Double index;
private Long globalTimeStamp; private Long globalTimeStamp;
...@@ -27,5 +27,5 @@ public class PhaseEmptyResult { ...@@ -27,5 +27,5 @@ public class PhaseEmptyResult {
private Long endTime; private Long endTime;
private int duration; private Integer duration;
} }
package com.wanji.indicators.task.trajectory.pojo;
import lombok.Data;
@Data
public class StartDuration {
// 开始时间(毫秒时间戳)
private Long startTime;
// 持续时长(分钟)
private Integer duration;
}
...@@ -16,6 +16,8 @@ public class UnbalanceResult { ...@@ -16,6 +16,8 @@ public class UnbalanceResult {
//失衡发生时间 //失衡发生时间
private String timestamp; private String timestamp;
private Integer duration;
private Long globalTimeStamp; private Long globalTimeStamp;
private Long startTime; private Long startTime;
......
...@@ -44,19 +44,24 @@ cross.event.data.topic=analysis.cross.event ...@@ -44,19 +44,24 @@ cross.event.data.topic=analysis.cross.event
plate.prefix= plate.prefix=
#路段默认自由流速度配置值 km/h #路段默认自由流速度配置值 km/h
rid.default.free.speed=80 rid.default.free.speed=80
#东西方向路段拥堵指数统计 # 方向级别拥堵数据
rid.traffic.index.analysis.topic=rid.traffic.index.analysis dir.congestion.index.topic=dir.congestion.index
#南北方向饱和度计算 # 路口级别拥堵数据
cross.congestion.index.topic=cross.congestion.index
#非协调方向饱和度计算
rid.traffic.index.north.south.topic=rid.traffic.index.north.south.analysis rid.traffic.index.north.south.topic=rid.traffic.index.north.south.analysis
#东西方向路段的rid和方向 # rid和终点路口进口方向
east.west.rid.direction.list=13NED0B5Q9013NF80B5QN00:6,13NGH0B5RC013NF80B5QN00:2,13NI00B5RM013NGH0B5RC00:3,13NF80B5QN013NGH0B5RC00:6,13NGH0B5RC013NI00B5RM00:7,13NID0B5RM013NI00B5RM00:3 rid.end.indir.list=13NED0B5Q9013NF80B5QN00:6,13NGH0B5RC013NF80B5QN00:2,13NI00B5RM013NGH0B5RC00:3,13NF80B5QN013NGH0B5RC00:6,13NGH0B5RC013NI00B5RM00:7,13NID0B5RM013NI00B5RM00:3,13NG40B5SK013NI00B5RM00:1,13NEH0B5RJ013NGH0B5RC00:1,13NEP0B5QJ013NGH0B5RC00:5,13NDG0B5RI013NF80B5QN00:1,13NDT0B5Q9013NF80B5QN00:4
#南北方向路段的rid和方向 # rid和起点路口出口方向
north.south.rid.direction.list=13NG40B5SK013NI00B5RM00:1,13NEH0B5RJ013NGH0B5RC00:1,13NEP0B5QJ013NGH0B5RC00:5,13NDG0B5RI013NF80B5QN00:1,13NDT0B5Q9013NF80B5QN00:4 rid.start.outdir.list=13NF80B5QN013NED0B5Q900:6,13NF80B5QN013NGH0B5RC00:2,13NGH0B5RC013NI00B5RM00:3,13NGH0B5RC013NF80B5QN00:6,13NI00B5RM013NGH0B5RC00:7,13NI00B5RM013NID0B5RM00:3,13NI00B5RM013NG40B5SK00:1,13NGH0B5RC013NEH0B5RJ00:1,13NGH0B5RC013NEP0B5QJ00:5,13NF80B5QN013NDG0B5RI00:1,13NF80B5QN013NDT0B5Q900:4
# 路口ID-方向-转向对应的行人灯通过时长
cross.dir.turn.ped.green=13NF80B5QN0-1-2:20,13NF80B5QN0-2-2:15,13NF80B5QN0-4-2:20,13NF80B5QN0-6-2:15,13NGH0B5RC0-1-2:30,13NGH0B5RC0-3-2:30,13NGH0B5RC0-5-2:30,13NGH0B5RC0-6-2:25,13NI00B5RM0-3-2:30,13NI00B5RM0-7-2:30,13NI00B5RM0-1-1:30
#路口溢出评价指标 #路口溢出评价指标
road.overflow.avg.speed=5.0 road.overflow.avg.speed=5.0
road.overflow.duration=3 road.overflow.duration=3000
road.overflow.deadlock.index.analysis.topic=crossroad.overflow.deadlock.index.analysis road.overflow.deadlock.index.analysis.topic=crossroad.overflow.deadlock.index.analysis
#路口失衡topic #路口失衡topic
...@@ -69,8 +74,10 @@ cross.road.deadlock.avg.speed=5.0 ...@@ -69,8 +74,10 @@ cross.road.deadlock.avg.speed=5.0
#相位灯的状态数据 #相位灯的状态数据
light.status.topic=cross_lights_status light.status.topic=cross_lights_status
#虚拟路口区域 # 虚拟路口区域
# 霞景路西,旅游路与回龙山路交叉口
virtual.crossroad.13NED0B5Q90=13NED0B5Q90:117.08503591467242,36.64125732273356;117.08495255127629,36.641426722875224;117.08499878952986,36.641454206982246;117.08508543702352,36.641286700399476 virtual.crossroad.13NED0B5Q90=13NED0B5Q90:117.08503591467242,36.64125732273356;117.08495255127629,36.641426722875224;117.08499878952986,36.641454206982246;117.08508543702352,36.641286700399476
# 福地街东,旅游路与隧道交叉口
virtual.crossroad.13NH20B5RH0=13NH20B5RH0:117.09669255282627,36.644871615002884;117.09669985552095,36.645055610398025;117.09675474612689,36.64505324101935;117.09674606214631,36.64486930675771 virtual.crossroad.13NH20B5RH0=13NH20B5RH0:117.09669255282627,36.644871615002884;117.09669985552095,36.645055610398025;117.09675474612689,36.64505324101935;117.09674606214631,36.64486930675771
#相位空放topic #相位空放topic
......
...@@ -5,9 +5,9 @@ ...@@ -5,9 +5,9 @@
## 2. 指标说明 ## 2. 指标说明
### 2.1 拥堵 ### 2.1 拥堵
拥堵指标计算分为东西方向和南北方向 拥堵指标计算分为协调方向方向和非协调方向
- 东西方向拥堵指数计算会针对每个路口的进口路段进行计算,统计每个路段的拥堵指数,并根据拥堵指数进行阈值判断后,获取该路段的交通状态 - 协调方向拥堵指数计算会针对每个路口的进口路段进行计算,统计每个路段的拥堵指数,并根据拥堵指数进行阈值判断后,获取该路段的交通状态
- 南北方向的拥堵指数计算是根据饱和度计算绿灯时间内,车辆空档时间。根据算法文档给出的计算公式进行相关计算后,判断其阈值范围,从而获取该路段的交通状态 - 非协调方向的拥堵指数计算:根据绿灯时间内车辆空档时间,计算饱和度。根据算法文档阈值判断拥堵等级。
### 2.2 失衡 ### 2.2 失衡
- 根据算法指标计算文档给出的计算公式,计算每个路口是否处于失衡状态 - 根据算法指标计算文档给出的计算公式,计算每个路口是否处于失衡状态
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment