Browse Source

initial stab at confidence score calculation based on distance from point.lat and point.lon

pull/274/head
Stephen Hess 9 years ago
parent
commit
0b5172a452
  1. 60
      middleware/confidenceScoreReverse.js
  2. 5
      routes/v1.js
  3. 185
      test/unit/middleware/confidenceScoreReverse.js
  4. 1
      test/unit/run.js

60
middleware/confidenceScoreReverse.js

@ -0,0 +1,60 @@
var logger = require('pelias-logger').get('api');
var _ = require('lodash');
// these are subjective terms, but wanted to add shortcuts to denote something
// about importance
var confidence = {
exact: 1.0,
excellent: 0.9,
good: 0.8,
okay: 0.7,
poor: 0.6,
none: 0.5
};
function setup(peliasConfig) {
return computeScores;
}
function computeScores(req, res, next) {
// do nothing if no result data set
if (!req.results || !req.results.data) {
return next();
}
// loop through data items and determine confidence scores
req.results.data = req.results.data.map(computeConfidenceScore.bind(null, req));
next();
}
function computeConfidenceScore(req, hit) {
// non-number or invalid distance should be given confidence 0.0
if (typeof hit.distance !== 'number' || hit.distance < 0) {
hit.confidence = 0.0;
return hit;
}
var meters = hit.distance * 1000;
// figure out which range the distance lies in and assign confidence accordingly
// TODO: this could probably be made more node-y with a map of function->number
if (meters === 0) {
hit.confidence = confidence.exact;
} else if (_.inRange(meters, 0, 10)) {
hit.confidence = confidence.excellent;
} else if (_.inRange(meters, 10, 100)) {
hit.confidence = confidence.good;
} else if (_.inRange(meters, 100, 250)) {
hit.confidence = confidence.okay;
} else if (_.inRange(meters, 250, 1000)) {
hit.confidence = confidence.poor;
} else {
hit.confidence = confidence.none;
}
return hit;
}
module.exports = setup;

5
routes/v1.js

@ -29,6 +29,7 @@ var controllers = {
var postProc = { var postProc = {
distances: require('../middleware/distance'), distances: require('../middleware/distance'),
confidenceScores: require('../middleware/confidenceScore'), confidenceScores: require('../middleware/confidenceScore'),
confidenceScoresReverse: require('../middleware/confidenceScoreReverse'),
renamePlacenames: require('../middleware/renamePlacenames'), renamePlacenames: require('../middleware/renamePlacenames'),
geocodeJSON: require('../middleware/geocodeJSON'), geocodeJSON: require('../middleware/geocodeJSON'),
sendJSON: require('../middleware/sendJSON') sendJSON: require('../middleware/sendJSON')
@ -73,8 +74,10 @@ function addRoutes(app, peliasConfig) {
sanitisers.reverse.middleware, sanitisers.reverse.middleware,
middleware.types, middleware.types,
controllers.search(undefined, reverseQuery), controllers.search(undefined, reverseQuery),
// TODO: add confidence scores
postProc.distances(), postProc.distances(),
// reverse confidence scoring depends on distance from origin
// so it must be calculated first
postProc.confidenceScoresReverse(peliasConfig),
postProc.renamePlacenames(), postProc.renamePlacenames(),
postProc.geocodeJSON(peliasConfig), postProc.geocodeJSON(peliasConfig),
postProc.sendJSON postProc.sendJSON

185
test/unit/middleware/confidenceScoreReverse.js

@ -0,0 +1,185 @@
var confidenceScoreReverse = require('../../../middleware/confidenceScoreReverse')();
module.exports.tests = {};
module.exports.tests.confidenceScoreReverse = function(test, common) {
test('distance == 0m should be given score 1.0', function(t) {
var req = {
results: {
data: [
{
distance: 0
}
]
}
};
confidenceScoreReverse(req, null, function() {
t.equal(req.results.data[0].confidence, 1.0, 'score should be exact confidence');
t.end();
});
});
test('0m < distance < 10m should be given score 0.9', function(t) {
var req = {
results: {
data: [
{
distance: 0.0001
},
{
distance: 0.0099
}
]
}
};
confidenceScoreReverse(req, null, function() {
t.equal(req.results.data[0].confidence, 0.9, 'score should be excellent confidence');
t.equal(req.results.data[1].confidence, 0.9, 'score should be excellent confidence');
t.end();
});
});
test('10m <= distance < 100m should be given score 0.8', function(t) {
var req = {
results: {
data: [
{
distance: 0.010
},
{
distance: 0.099
}
]
}
};
confidenceScoreReverse(req, null, function() {
t.equal(req.results.data[0].confidence, 0.8, 'score should be good confidence');
t.equal(req.results.data[1].confidence, 0.8, 'score should be good confidence');
t.end();
});
});
test('100m <= distance < 250m should be given score 0.7', function(t) {
var req = {
results: {
data: [
{
distance: 0.100
},
{
distance: 0.249
}
]
}
};
confidenceScoreReverse(req, null, function() {
t.equal(req.results.data[0].confidence, 0.7, 'score should be okay confidence');
t.equal(req.results.data[1].confidence, 0.7, 'score should be okay confidence');
t.end();
});
});
test('250m <= distance < 1000m should be given score 0.6', function(t) {
var req = {
results: {
data: [
{
distance: 0.250
},
{
distance: 0.999
}
]
}
};
confidenceScoreReverse(req, null, function() {
t.equal(req.results.data[0].confidence, 0.6, 'score should be poor confidence');
t.equal(req.results.data[1].confidence, 0.6, 'score should be poor confidence');
t.end();
});
});
test('distance >= 1000m should be given score 0.5', function(t) {
var req = {
results: {
data: [
{
distance: 1
},
{
distance: 2
}
]
}
};
confidenceScoreReverse(req, null, function() {
t.equal(req.results.data[0].confidence, 0.5, 'score should be least confidence');
t.equal(req.results.data[1].confidence, 0.5, 'score should be least confidence');
t.end();
});
});
test('distance < 0 (invalid) should be given score 0.0', function(t) {
var req = {
results: {
data: [
{
distance: -0.0001
}
]
}
};
confidenceScoreReverse(req, null, function() {
t.equal(req.results.data[0].confidence, 0.0, 'score should be 0.0 confidence');
t.end();
});
});
test('non-number-type (invalid) distance should be given score 0.0', function(t) {
var req = {
results: {
data: [
{},
{ distance: [] },
{ distance: {} },
{ distance: 'this is not a number' }
]
}
};
confidenceScoreReverse(req, null, function() {
t.equal(req.results.data[0].confidence, 0.0, 'score should be 0.0 confidence');
t.equal(req.results.data[1].confidence, 0.0, 'score should be 0.0 confidence');
t.equal(req.results.data[2].confidence, 0.0, 'score should be 0.0 confidence');
t.equal(req.results.data[3].confidence, 0.0, 'score should be 0.0 confidence');
t.end();
});
});
};
module.exports.all = function (tape, common) {
function test(name, testFunction) {
return tape('[middleware] confidenceScoreReverse: ' + name, testFunction);
}
for( var testCase in module.exports.tests ){
module.exports.tests[testCase](test, common);
}
};

1
test/unit/run.js

@ -27,6 +27,7 @@ var tests = [
require('./helper/types'), require('./helper/types'),
require('./sanitiser/_geo_common'), require('./sanitiser/_geo_common'),
require('./middleware/distance'), require('./middleware/distance'),
require('./middleware/confidenceScoreReverse'),
]; ];
tests.map(function(t) { tests.map(function(t) {

Loading…
Cancel
Save