diff --git a/query/search.js b/query/search.js index 57fab047..147e2dfa 100644 --- a/query/search.js +++ b/query/search.js @@ -1,7 +1,8 @@ var peliasQuery = require('pelias-query'), defaults = require('./defaults'), textParser = require('./text_parser'), - check = require('check-types'); + check = require('check-types'), + geolib = require('geolib'); //------------------------------ // general-purpose search query @@ -74,10 +75,10 @@ function generateQuery( clean ){ check.number(clean['focus.viewport.min_lon']) && check.number(clean['focus.viewport.max_lon']) ) { // calculate the centroid from the viewport box - // simply set focus:point:lat/lon, until we improve this with a radius vs.set({ 'focus:point:lat': clean['focus.viewport.min_lat'] + ( clean['focus.viewport.max_lat'] - clean['focus.viewport.min_lat'] ) / 2, - 'focus:point:lon': clean['focus.viewport.min_lon'] + ( clean['focus.viewport.max_lon'] - clean['focus.viewport.min_lon'] ) / 2 + 'focus:point:lon': clean['focus.viewport.min_lon'] + ( clean['focus.viewport.max_lon'] - clean['focus.viewport.min_lon'] ) / 2, + 'focus:scale': calculateDiagonalDistance(clean) + 'km' }); } @@ -125,4 +126,20 @@ function generateQuery( clean ){ return query.render( vs ); } +// return diagonal distance in km, with min=1 +function calculateDiagonalDistance(clean) { + var diagonalDistance = geolib.getDistance( + { latitude: clean['focus.viewport.min_lat'], longitude: clean['focus.viewport.min_lon'] }, + { latitude: clean['focus.viewport.max_lat'], longitude: clean['focus.viewport.max_lon'] }, + 1000 + ) / 1000; + + if (diagonalDistance === 0) { + return 1; + } + + return diagonalDistance; + +} + module.exports = generateQuery; diff --git a/test/unit/fixture/search_linguistic_viewport.js b/test/unit/fixture/search_linguistic_viewport.js index 7c101db0..f0e3132a 100644 --- a/test/unit/fixture/search_linguistic_viewport.js +++ b/test/unit/fixture/search_linguistic_viewport.js @@ -44,7 +44,7 @@ module.exports = { 'lon': -82.50622 }, 'offset': '1km', - 'scale': '50km', + 'scale': '994km', 'decay': 0.5 } } diff --git a/test/unit/fixture/search_linguistic_viewport_min_diagonal.js b/test/unit/fixture/search_linguistic_viewport_min_diagonal.js new file mode 100644 index 00000000..36b8a0ac --- /dev/null +++ b/test/unit/fixture/search_linguistic_viewport_min_diagonal.js @@ -0,0 +1,105 @@ + +module.exports = { + 'query': { + 'filtered': { + 'query': { + 'bool': { + 'must': [{ + 'match': { + 'name.default': { + 'query': 'test', + 'boost': 1, + 'analyzer': 'peliasOneEdgeGram' + } + } + }], + 'should': [{ + 'match': { + 'phrase.default': { + 'query': 'test', + 'analyzer': 'peliasPhrase', + 'type': 'phrase', + 'boost': 1, + 'slop': 2 + } + } + }, { + 'function_score': { + 'query': { + 'match': { + 'phrase.default': { + 'analyzer': 'peliasPhrase', + 'type': 'phrase', + 'boost': 1, + 'slop': 2, + 'query': 'test' + } + } + }, + 'functions': [{ + 'linear': { + 'center_point': { + 'origin': { + 'lat': 28.49136, + 'lon': -87.50623 + }, + 'offset': '1km', + 'scale': '1km', + 'decay': 0.5 + } + } + }], + 'score_mode': 'avg', + 'boost_mode': 'replace' + } + }, + { + 'function_score': { + 'query': { + 'filtered': { + 'filter': { + 'exists': { + 'field': 'popularity' + } + } + } + }, + 'max_boost': 2, + 'score_mode': 'first', + 'boost_mode': 'replace', + 'filter': { + 'or': [ + { + 'type': { + 'value': 'admin0' + } + }, + { + 'type': { + 'value': 'admin1' + } + }, + { + 'type': { + 'value': 'admin2' + } + } + ] + }, + 'functions': [{ + 'field_value_factor': { + 'modifier': 'sqrt', + 'field': 'popularity' + }, + 'weight': 1 + }] + } + }] + } + } + } + }, + 'sort': [ '_sort' ], + 'size': 10, + 'track_scores': true +}; diff --git a/test/unit/query/search.js b/test/unit/query/search.js index cb2a6d25..d543c7c7 100644 --- a/test/unit/query/search.js +++ b/test/unit/query/search.js @@ -97,6 +97,24 @@ module.exports.tests.query = function(test, common) { t.end(); }); + test('search with viewport diagonal < 1km should set scale to 1km', function(t) { + var query = generate({ + text: 'test', size: 10, + 'focus.viewport.min_lat': 28.49135, + 'focus.viewport.max_lat': 28.49137, + 'focus.viewport.min_lon': -87.50622, + 'focus.viewport.max_lon': -87.50624, + layers: ['test'] + }); + + var compiled = JSON.parse( JSON.stringify( query ) ); + var expected = require('../fixture/search_linguistic_viewport_min_diagonal'); + expected.sort = sort; + + t.deepEqual(compiled, expected, 'valid search query'); + t.end(); + }); + test('search search + focus on null island', function(t) { var query = generate({ text: 'test', size: 10,