可疑对象分析
可疑对象的处理,可以从他行迹的几个坐标距离,与事件差进行对比。如果符合逻辑,可以认为是当前对象是无可疑的。如果是可疑的,即将结果先保存起来,进入可疑对象库。
- 通过获取时间段的数据;
- 根据被监测对象的 RSFZ 聚合数据;(RSFZ: SBBH_TGSJ_JWZB)
- 根据判定规则:处理每个监测对象的 RSFZ 的聚合数据,将符合负责的数据唯一标识放到累加器中;
- 获取家属器的唯一标识,从表中查询相关记录,存入 mysql 中。
代码
public class VerifyCompute {
String sql = "select * from t_alldata t where t.tgsj";
Dataset<Row> allFromTime = spark.sql(sql);
JavaRDD<Row> resultRDD = allFromTime.javaRDD();
/**
* 从数据中获取必要的列名来转换成 PairRDD
*/
JavaPairRDD<String, String> pairRDD = resultRDD.mapToPair(new PairFunction<Row, String, String>() {
@Override
public Tuple2<String, String> call(Row row) throws Exception {
String rsfz = row.getAs("RSFZ");
String id = row.getAs("ID");
String tgsj = row.getAs("TGSJ");
String sbbh =row.getAs("SBBH");
String jwzb = row.getAs("JWZB");
String tuple01 = rsfz;
String tuple02 = id + "_" + jwzb + "_" + tgsj+"_"+sbbh;
return new Tuple2<String, String>(tuple01, tuple02);
}
});
/**
* 对相同身份证的数据对 id + "_" + jwzb + "_" + tgsj 进行叠加,这样就可以
* 获取 通过时间 和 经纬坐标。
*/
JavaPairRDD<String, String> reduceRDD = pairRDD.reduceByKey(new Function2<String, String, String>() {
private static final long serialVersionUID = 1L;
@Override
public String call(String v1, String v2) throws Exception {
return v1 + "&" + v2;
}
});
//创建累加器,用于添加计算后的数据。
CollectionAccumulator<String> acc = jsc.sc().collectionAccumulator();
/**
* 由于不能在 map foreach 中调用RDD,所以可以用累加器将 id 封装起来。
*/
reduceRDD.foreach(new VoidFunction<Tuple2<String, String>>() {
private static final long serialVersionUID = 1L;
@Override
public void call(Tuple2<String, String> s2) throws Exception {
String IDCard = s2._1;
String[] values = s2._2.split("&");
for (int i = 0; i < values.length; i++) {
for (int k = i + 1; k < values.length; k++) {
String value1 = values[i];
String value2 = values[k];
String[] item1 = value1.split("_");
String[] item2 = value2.split("_");
String id1 = item1[0];
String lon1 = item1[1];
String lat1 =item1[2];
String tgsj1 = item1[3];
String id2 = item2[0];
String lon2 = item2[1];
String lat2 =item2[2];
String tgsj2 = item2[3];
double subHour = TimeUtils.getSubHour(tgsj1, tgsj2);
double distance = MapUtils.getLongDistance(Double.valueOf(lon1), Double.valueOf(lat1),Double.valueOf(lon2),Double.valueOf(lat2));
Integer speed = SpeedUtils.getSpeed(distance, subHour);
//核心操作
if (speed > 5) {
acc.add(id1 + "_" + id2);
/**
* 如果这里就进行 RDD,就会发生 空指针异常。所以,要在map、foreach算子中调用 dataFrame 或 RDD 方法
*/
}
}
}
}
});
List<String> accValue = acc.value();
for(String id: accValue) {
Dataset<Row> resultDF3 = spark.sql("select RSFZ,GRXB,PSQK, TGSJ," +
"SBBH,JWZB from t_alldata where id in (" + id.split("_")[0] + "," + id.split("_")[1] + ")");
resultDF3.show(20);
Dataset<Row> resultDF4 = resultDF3.withColumn("CreateTime", functions.lit(new Date().getTime()));
resultDF4.write()
.format("jdbc")
.option("url", "jdbc:mysql://bigdata03:3306/test?characterEncoding=UTF-8")
.option("dbtable", "t_verify_result")
.option("user", "root")
.option("password", "123456")
.mode(SaveMode.Append)
.save();
}
}
}
实操实现
- 在 mysql 数据库中创建表
CREATE TABLE t_verify_result(
RSFZ text,
GRXB text,
PSQK text,
TGSJ text,
SBBH text,
JWZB text,
CJSJ text
)charset utf8 collate utf8_general_ci;
- 复用 hive 中 t_people_together 表的数据。
- 使用 submit 执行
./spark-submit
--master spark://bigdata01:7077
--class com.monitor.compare.VerifyCompute
--deploy-mode client
/root/monitoranalysis-1.0-SNAPSHOT.jar
这样就可以把数据以 RSFZ | GRXB | PSQK | TGSJ SBBH | JWZB | CJSJ 方式在数据库中。
第二种方式
这种方式采用纯 SQL 来进行处理
首先自定义一个 UDF
public class ComputeUDF implements UDF1<String, String> {
@Override
public String call(String s) throws Exception {
StringBuilder sbResult = new StringBuilder();
String value = s;
String[] values = s.split("&");
// 对数据进行遍历,将数据中的 时间与经纬度取出来计算出不同的 speed。
for (int i = 0; i < values.length; i++) {
for (int k = i+1; k < values.length; k++) {
String value1 = values[i];
String value2 = values[k];
String[] item1 = value1.split("_");
String[] item2 = value2.split("_");
String id1 = item1[0];
String lon1 = item1[1];
String lat1 = item1[2];
String tgsj1 = item1[3];
String id2 = item2[0];
String lon2 = item2[1];
String lat2 = item2[2];
String tgsj2 = item2[3];
//System.out.println("id= "+id1+" ,lon= "+lon1+" ,lat= "+lat1+" ,tgsj= "+tgsj1);
double subHour = TimeUtils.getSubHour(tgsj1, tgsj2);
// System.out.println("subHour= "+subHour);
double distanct = MapUtils.getLongDistance(Double.valueOf(lon1), Double.valueOf(lat1), Double.valueOf(lon2), Double.valueOf(lat2));
//System.out.println("distanct= "+distanct);
Integer speed = SpeedUtils.getSpeed(distanct, subHour);
//System.out.println("speed= "+speed);
if (speed > 5 && speed != null) {
if (sbResult.length() > 0) {
sbResult.append("&").append(id1 + "_" + id2);
} else {
//首次 append 到StringBuilder。
sbResult.append(id1 + "_" + id2);
}
}
}
}
return sbResult.toString().length() > 0 ? sbResult.toString() : null;
}
}
其次,在 Spark程序中使用该方法
Dataset<Row> sqlDF = spark.sql("select rsfz,verifyValue from(" +
"select rsfz,getVerify(concat_ws('&',collect_set(concat_ws('_',id,jwzb,tgsj)))) " +
"as verifyValue from t_people_together group by rsfz) where verifyValue is not null");
如果看不懂上述 sql 语句,可以拆分为三个 sql
spark.sql("select RSFZ,concat_ws('_',ID,JWZB,TGSJ) as concatValue from t_alldata").show(false);
spark.sql("select RSFZ,concat_ws('&',collect_set(concat_ws('_',ID,JWZB,TGSJ))) " +
"as concatValue from t_alldata group by RSFZ").show(false);
getVerify 返回 id1_id2,所以显示的结果是 <RSFZ id1_id2>
spark.sql("select RSFZ,getVerify(concat_ws('&',collect_set(concat_ws('_',ID,JWZB,TGSJ)))) " +
"as verifyValue from t_alldata group by RSFZ").show(false);
实际操作
- 创建 mysql 数据库表
CREATE TABLE t_verify_result2(
RSFZ text,
GRXB text,
PSQK text,
TGSJ text,
SBBH text,
JWZB text,
CJSJ text
)charset utf8 collate utf8_general_ci;
- 执行 spark
./spark-submit
--master spark://bigdata01:7077
--class com.monitor.compare.VerifyCompute2
--deploy-mode client
/root/monitoranalysis-1.0-SNAPSHOT.jar
实例代码
https://github.com/yy1028500451/MonitorAnalysis/tree/master/src/main/java/com/monitor/compare