Improve location estimation
This commit is contained in:
@@ -8,7 +8,8 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
earthCircumferenceInKm float64 = 40100 // earth circumference in km
|
||||
earthCircumferenceInKm = 40100 // earth circumference in km
|
||||
defaultLocationAccuracy = 100
|
||||
)
|
||||
|
||||
// Location holds information regarding the geographical and network location of an IP address.
|
||||
@@ -30,52 +31,75 @@ type Coordinates struct {
|
||||
Longitude float64 `maxminddb:"longitude"`
|
||||
}
|
||||
|
||||
/*
|
||||
Location Estimation
|
||||
|
||||
Distance Value
|
||||
|
||||
- 0: Other side of the Internet.
|
||||
- 100: Very near, up to same network / datacenter.
|
||||
|
||||
Weighting Goal
|
||||
|
||||
- Exposure to different networks shall be limited as much as possible.
|
||||
- A single network should not see a connection over a large distance.
|
||||
- Latency should be low.
|
||||
|
||||
Weighting Intentions
|
||||
|
||||
- Being on the same continent is better than being in the same AS.
|
||||
- Being in the same country is better than having low coordinate distance.
|
||||
- Coordinate distance is only a tie breaker, as accuracy varies heavily.
|
||||
- Same AS with lower coordinate distance beats being on the same continent.
|
||||
|
||||
Weighting Configuration
|
||||
*/
|
||||
|
||||
const (
|
||||
weightContinentMatch = 25
|
||||
weightCountryMatch = 20
|
||||
weightASOrgMatch = 15
|
||||
weightASNMatch = 10
|
||||
weightCoordinateDistance = 30
|
||||
)
|
||||
|
||||
/*
|
||||
About the Accuracy Radius
|
||||
|
||||
- Range: 1-1000
|
||||
- Seen values (estimation): 1,5,10,20,50,100,200,500,1000
|
||||
- The default seems to be 100.
|
||||
|
||||
Cxamples
|
||||
|
||||
- 1.1.1/24 has 1000: Anycast
|
||||
- 8.8.0/19 has 1000: Anycast
|
||||
- 8.8.52/22 has 1: City of Westfield
|
||||
|
||||
Conclusion
|
||||
|
||||
- Ignore or penalize high accuracy radius.
|
||||
*/
|
||||
|
||||
// EstimateNetworkProximity aims to calculate the distance between two network locations. Returns a proximity value between 0 (far away) and 100 (nearby).
|
||||
func (l *Location) EstimateNetworkProximity(to *Location) (proximity int) {
|
||||
/*
|
||||
Distance Value
|
||||
|
||||
- 0: Other side of the Internet.
|
||||
- 100: Very near, up to same network / datacenter.
|
||||
|
||||
Weighting Goal
|
||||
|
||||
- Exposure to different networks shall be limited as much as possible.
|
||||
- A single network should not see a connection over a large distance.
|
||||
- Latency should be low.
|
||||
|
||||
Weighting Intentions
|
||||
|
||||
- Being on the same continent is better than being in the same AS.
|
||||
- Being in the same country is better than having low coordinate distance.
|
||||
- Coordinate distance is only a tie breaker, as accuracy varies heavily.
|
||||
- Same AS with lower coordinate distance beats being on the same continent.
|
||||
|
||||
Weighting Configuration
|
||||
|
||||
- Continent match: 30
|
||||
- Country match: 25
|
||||
- ASOrg match: 20
|
||||
- ASN match: 15
|
||||
- Coordinate distance: 0-10
|
||||
*/
|
||||
|
||||
if l.Continent.Code != "" &&
|
||||
l.Continent.Code == to.Continent.Code {
|
||||
proximity += 30
|
||||
if l.Country.ISOCode != "" &&
|
||||
l.Country.ISOCode == to.Country.ISOCode {
|
||||
proximity += 25
|
||||
}
|
||||
func (l *Location) EstimateNetworkProximity(to *Location) (proximity float32) {
|
||||
switch {
|
||||
case l.Country.ISOCode != "" && l.Country.ISOCode == to.Country.ISOCode:
|
||||
// Rely more on the Country Code data, as it is more accurate than the
|
||||
// Continent Code, especially when combining location data from multiple
|
||||
// sources.
|
||||
proximity += weightContinentMatch + weightCountryMatch
|
||||
case l.Continent.Code != "" && l.Continent.Code == to.Continent.Code:
|
||||
proximity += weightContinentMatch
|
||||
}
|
||||
|
||||
if l.AutonomousSystemOrganization != "" &&
|
||||
l.AutonomousSystemOrganization == to.AutonomousSystemOrganization {
|
||||
proximity += 20
|
||||
if l.AutonomousSystemNumber != 0 &&
|
||||
l.AutonomousSystemNumber == to.AutonomousSystemNumber {
|
||||
proximity += 15
|
||||
}
|
||||
switch {
|
||||
case l.AutonomousSystemNumber != 0 && l.AutonomousSystemNumber == to.AutonomousSystemNumber:
|
||||
// Rely more on the ASN data, as it is more accurate than the ASOrg data,
|
||||
// especially when combining location data from multiple sources.
|
||||
proximity += weightASOrgMatch + weightASNMatch
|
||||
case l.AutonomousSystemOrganization != "" && l.AutonomousSystemOrganization == to.AutonomousSystemOrganization:
|
||||
proximity += weightASOrgMatch
|
||||
}
|
||||
|
||||
// Check coordinates and adjust accuracy value.
|
||||
@@ -91,23 +115,10 @@ func (l *Location) EstimateNetworkProximity(to *Location) (proximity int) {
|
||||
accuracy = to.Coordinates.AccuracyRadius
|
||||
}
|
||||
|
||||
/*
|
||||
About the Accuracy Radius
|
||||
|
||||
- Range: 1-1000
|
||||
- Seen values (estimation): 1,5,10,20,50,100,200,500,1000
|
||||
- The default seems to be 100.
|
||||
|
||||
Cxamples
|
||||
|
||||
- 1.1.1/24 has 1000: Anycast
|
||||
- 8.8.0/19 has 1000: Anycast
|
||||
- 8.8.52/22 has 1: City of Westfield
|
||||
|
||||
Conclusion
|
||||
|
||||
- Ignore or penalize high accuracy radius.
|
||||
*/
|
||||
// Apply the default location accuracy if there is none.
|
||||
if accuracy == 0 {
|
||||
accuracy = defaultLocationAccuracy
|
||||
}
|
||||
|
||||
// Calculate coordinate distance in kilometers.
|
||||
fromCoords := haversine.Coord{Lat: l.Coordinates.Latitude, Lon: l.Coordinates.Longitude}
|
||||
@@ -116,14 +127,21 @@ func (l *Location) EstimateNetworkProximity(to *Location) (proximity int) {
|
||||
|
||||
if km <= 50 && accuracy <= 100 {
|
||||
// Give a flat out ten for highly accurate coordinates within 50km.
|
||||
proximity += 10
|
||||
proximity += weightCoordinateDistance
|
||||
} else {
|
||||
// Else, take a percentage.
|
||||
distanceInPercent := (earthCircumferenceInKm - km) * 100 / earthCircumferenceInKm
|
||||
proximityInPercent := (earthCircumferenceInKm - km) / earthCircumferenceInKm
|
||||
|
||||
// Apply penalty for locations with low accuracy (targeting accuracy radius >100).
|
||||
// Take away at most 50% of the weight through inaccuracy.
|
||||
accuracyModifier := 1 - float64(accuracy)/2000
|
||||
proximity += int(distanceInPercent * 0.10 * accuracyModifier)
|
||||
|
||||
// Add proximiy weight.
|
||||
proximity += float32(
|
||||
weightCoordinateDistance * // Maxmimum weight for this data point.
|
||||
proximityInPercent * // Range: 0-1
|
||||
accuracyModifier, // Range: 0.5-1
|
||||
)
|
||||
}
|
||||
|
||||
return proximity
|
||||
|
||||
Reference in New Issue
Block a user