登錄位移速度評估
此情況主要是對用戶的登錄地址在短時間出現在不同地方來進行評估是否存在風險!
評估這個我們需要知道客戶兩次不同登錄地址的距離,進行判斷在兩次登錄的間隔時間裏客戶有沒有可能利用現在的交通工具到達!
距離是通過經緯度來進行計算的,計算是保證準確的但存不存在誤差主要還是看給過來的數據是否存在誤差
下面問題來了,我們如何來計算兩個經緯度之間的距離那!
我們進行簡單推理下球⾯距離計算的公式
求AB的距離可以將它看作一個圓的弧長
得出最後的計算球面距離的公式爲
、
L=R·arc cos[cos(
wA
)cos(wB
)cos(jB
-jA
) + sin(wA
)sin(wB
)]
使用:
球面距離在開發中一般用在,地理位置的位移量計算中。
下面進入代碼實現登錄位移速度評估環節
package com.baizhi.evaluate.impl;
import com.baizhi.enties.*;
import com.baizhi.evaluate.Evaluate;
import com.baizhi.evaluate.EvaluateChain;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import static java.lang.Math.*;
public class SpeedEvaluate extends Evaluate {
private Double thresholdSpeed; //速度
private static final Double EARTH_RADIUS=6371.393;//千米 地球半徑
public SpeedEvaluate(Double thresholdSpeed) {
super(RiskFactor.SPEED);
this.thresholdSpeed=thresholdSpeed;
}
@Override
public void eval(EvaluateData evaluateData, HistoryData historyData, EvaluateReport evaluateReport,
EvaluateChain evaluateChain) {
evaluateReport.signReport(getRiskFactor(),
doSpeed(evaluateData.getGeoPoint(),evaluateData.getEvaluateTime(),historyData.getGeoPoints(),historyData.getHistoryLoginTime()));
//往下調
evaluateChain.daChain(evaluateData,historyData,evaluateReport);
}
/**
*通過球面距離公式計算出距離
* 然後通過相差時間評估出是否正常
* @geoPoint 本次登錄經緯度
* @evaluateTime 本次登錄時間
* @historygeoPoints 上次登錄經緯度
* @historyLoginTime 上次登錄時間
* */
public boolean doSpeed(GeoPoint geoPoint,Long evaluateTime,GeoPoint historygeoPoints,Long historyLoginTime){
if(historygeoPoints==null | historyLoginTime==null) return false;
//計算距離
double distance = distance(geoPoint, historygeoPoints);
// 計算小時差
double v = (historyLoginTime - evaluateTime) * 1.0 / (3600 * 1000);
//相隔的距離,在這個相差時間能到達需要的速度
double speed= distance/v;
//如果速度大於常規交通速度 則返回true 有風險
return speed> thresholdSpeed;
}
public double distance(GeoPoint geoPoint,GeoPoint historygeoPoints){
//L=R·arc cos[cos(`wA`)cos(`wB`)cos(`jB`-`jA`) + sin(`wA`)sin(`wB`)]
//w 爲緯度 j 爲經度
Double wA=toRadians(geoPoint.getLatitude());//將角度轉換爲弧度
Double jA=toRadians(geoPoint.getLongtitude());
Double wB=toRadians(historygeoPoints.getLatitude());
Double jB=toRadians(historygeoPoints.getLongtitude());
return EARTH_RADIUS * acos(cos(wA)*cos(wB)*cos(jB-jA)+sin(wA)*sin(wB));
}
//小測試下
public static void main(String[] args) throws ParseException {
SpeedEvaluate speedEvaluate = new SpeedEvaluate(600.0);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
long evaluateTime=sdf.parse("2020-04-01 10:10:00").getTime();
GeoPoint p1=new GeoPoint();
p1.setLongtitude(116.2317);//北京
p1.setLatitude(39.5427);
long lastLoginTime=sdf.parse("2020-04-01 08:00:00").getTime();
GeoPoint p2=new GeoPoint();
p2.setLongtitude(114.14);//鄭州
p2.setLatitude(34.16);
System.out.println(speedEvaluate.doSpeed(p1, evaluateTime, p2, lastLoginTime));
}
}