diff --git a/query/reverse.js b/query/reverse.js index fd835e8f..4e8b13c5 100644 --- a/query/reverse.js +++ b/query/reverse.js @@ -1,33 +1,52 @@ -var queries = require('geopipes-elasticsearch-backend').queries, +var peliasQuery = require('pelias-query'), sort = require('./sort'); -function generate( params ){ +//------------------------------ +// reverse geocode query +//------------------------------ +var query = new peliasQuery.layout.FilteredBooleanQuery(); - var centroid = { - lat: params.lat, - lon: params.lon - }; +// scoring boost +query.sort( peliasQuery.view.sort_distance ); - var query = queries.distance( centroid, { - size: params.size || 1, - sort: true, - distance: '500km' +// non-scoring hard filters +query.filter( peliasQuery.view.boundary_circle ); + +// -------------------------------- + +function generateQuery( clean ){ + + var vs = new peliasQuery.Vars( peliasQuery.defaults ); + + // set defaults + vs.set({ + 'size': 1, + 'boundary:circle:radius': '500km' }); - query.sort = query.sort.concat( sort( params ) ); + // set size + if( clean.size ){ + vs.var( 'size', clean.size ); + } - if ( params.categories && params.categories.length > 0 ) { - addCategoriesFilter( query, params.categories ); + // focus point centroid + if( clean.lat && clean.lon ){ + vs.set({ + // focus point to score by distance + 'focus:point:lat': clean.lat, + 'focus:point:lon': clean.lon, + + // bounding circle + 'boundary:circle:lat': clean.lat, + 'boundary:circle:lon': clean.lon, + }); } - return query; -} + var result = query.render( vs ); -function addCategoriesFilter( query, categories ) { - query.query.filtered.filter.bool.must.push({ - terms: { category: categories } - }); + // @todo: remove this hack + return JSON.parse( JSON.stringify( result ) ); } -module.exports = generate; +module.exports = generateQuery; diff --git a/query/search.js b/query/search.js index 4ba311c9..de523c20 100644 --- a/query/search.js +++ b/query/search.js @@ -32,12 +32,12 @@ query.score( peliasQuery.view.admin('locality') ); query.score( peliasQuery.view.admin('neighborhood') ); // non-scoring hard filters -query.filter( peliasQuery.view.boundary_circle, 'must' ); -query.filter( peliasQuery.view.boundary_rect, 'must' ); +query.filter( peliasQuery.view.boundary_circle ); +query.filter( peliasQuery.view.boundary_rect ); // -------------------------------- -function generate( clean ){ +function generateQuery( clean ){ var vs = new peliasQuery.Vars( peliasQuery.defaults ); @@ -125,7 +125,7 @@ function generate( clean ){ // ==== deal with the 'leftover' components ==== // @todo: clean up this code - // a concept called 'leftovers' which is just 'admin_parts' plus 'regions'. + // a concept called 'leftovers' which is just 'admin_parts' /or 'regions'. var leftoversString = ''; if( clean.parsed_input.hasOwnProperty('admin_parts') ){ leftoversString = clean.parsed_input.admin_parts; @@ -150,10 +150,12 @@ function generate( clean ){ } var result = query.render( vs ); + + // @todo: remove unnessesary sort conditions result.sort = result.sort.concat( sort( clean ) ); // @todo: remove this hack return JSON.parse( JSON.stringify( result ) ); } -module.exports = generate; +module.exports = generateQuery; diff --git a/test/unit/fixture/reverse_standard.js b/test/unit/fixture/reverse_standard.js new file mode 100644 index 00000000..b7cc058f --- /dev/null +++ b/test/unit/fixture/reverse_standard.js @@ -0,0 +1,43 @@ + +module.exports = { + 'query': { + 'filtered': { + 'query': { + 'bool': {} + }, + 'filter': { + 'bool': { + 'must': [ + { + 'geo_distance': { + 'distance': '500km', + 'distance_type': 'plane', + 'optimize_bbox': 'indexed', + '_cache': true, + 'center_point': { + 'lat': 29.49136, + 'lon': -82.50622 + } + } + } + ] + } + } + } + }, + 'sort': [ + '_score', + { + '_geo_distance': { + 'center_point': { + 'lat': 29.49136, + 'lon': -82.50622 + }, + 'order': 'asc', + 'distance_type': 'plane' + } + } + ], + 'size': 1, + 'track_scores': true +}; \ No newline at end of file diff --git a/test/unit/query/reverse.js b/test/unit/query/reverse.js index e200b832..a8dde064 100644 --- a/test/unit/query/reverse.js +++ b/test/unit/query/reverse.js @@ -1,15 +1,16 @@ var generate = require('../../../query/reverse'); -var admin_boost = 'admin_boost'; -var population = 'population'; -var popularity = 'popularity'; -var category = 'category'; -var category_weights = require('../../../helper/category_weights'); -var admin_weights = require('../../../helper/admin_weights'); -var weights = require('pelias-suggester-pipeline').weights; module.exports.tests = {}; +function debug( a,b ){ + console.log( '----------------------' ); + console.log( JSON.stringify( a, null, 2 ) ); + console.log( '----------------------' ); + console.log( JSON.stringify( b, null, 2 ) ); + console.log( '----------------------' ); +} + module.exports.tests.interface = function(test, common) { test('valid interface', function(t) { t.equal(typeof generate, 'function', 'valid function'); @@ -17,185 +18,25 @@ module.exports.tests.interface = function(test, common) { }); }; -var sort = [ - '_score', - { - '_script': { - 'file': admin_boost, - 'type': 'number', - 'order': 'desc' - } - }, - { - '_script': { - 'file': popularity, - 'type': 'number', - 'order': 'desc' - } - }, - { - '_script': { - 'file': population, - 'type': 'number', - 'order': 'desc' - } - }, - { - '_script': { - 'params': { - 'weights': admin_weights - }, - 'file': 'weights', - 'type': 'number', - 'order': 'desc' - } - }, - { - '_script': { - 'params': { - 'category_weights': category_weights.default - }, - 'file': category, - 'type': 'number', - 'order': 'desc' - } - }, - { - '_script': { - 'params': { - 'weights': weights - }, - 'file': 'weights', - 'type': 'number', - 'order': 'desc' - } - } -]; - module.exports.tests.query = function(test, common) { test('valid query', function(t) { var query = generate({ lat: 29.49136, lon: -82.50622 }); - var expected = { - 'query': { - 'filtered': { - 'query': { - 'match_all': {} - }, - 'filter': { - 'bool': { - 'must': [ - { - 'geo_distance': { - 'distance': '500km', - 'distance_type': 'plane', - 'optimize_bbox': 'indexed', - '_cache': true, - 'center_point': { - 'lat': '29.49', - 'lon': '-82.51' - } - } - } - ] - } - } - } - }, - 'sort': [ - '_score', - { - '_geo_distance': { - 'center_point': { - 'lat': 29.49136, - 'lon': -82.50622 - }, - 'order': 'asc', - 'unit': 'km' - } - } - ].concat(sort.slice(1)), - 'size': 1, - 'track_scores': true - }; - + var expected = require('../fixture/reverse_standard'); t.deepEqual(query, expected, 'valid reverse query'); - + t.end(); + }); + test('size fuzz test', function(t) { // test different sizes var sizes = [1,2,10,undefined,null]; - sizes.forEach( function(size) { - query = generate({ + sizes.forEach( function( size ){ + var query = generate({ lat: 29.49136, lon: -82.50622, size: size }); - expected.size = size ? size : 1; - t.deepEqual(query, expected, 'valid reverse query for size: '+ size); - }); - t.end(); - }); - - test('valid query with categories', function(t) { - var params = { lat: 29.49136, lon: -82.50622, categories: ['food', 'education', 'entertainment'] }; - var query = generate(params); - - var expected = { - 'query': { - 'filtered': { - 'query': { - 'match_all': {} - }, - 'filter': { - 'bool': { - 'must': [ - { - 'geo_distance': { - 'distance': '500km', - 'distance_type': 'plane', - 'optimize_bbox': 'indexed', - '_cache': true, - 'center_point': { - 'lat': '29.49', - 'lon': '-82.51' - } - } - }, - { - 'terms': { - 'category': params.categories - } - } - ] - } - } - } - }, - 'sort': [ - '_score', - { - '_geo_distance': { - 'center_point': { - 'lat': 29.49136, - 'lon': -82.50622 - }, - 'order': 'asc', - 'unit': 'km' - } - } - ].concat(sort.slice(1)), - 'size': 1, - 'track_scores': true - }; - t.deepEqual(query, expected, 'valid reverse query with categories'); - - // test different sizes - var sizes = [1,2,10,undefined,null]; - sizes.forEach( function(size) { - params.size = size; - query = generate(params); - expected.size = size ? size : 1; - t.deepEqual(query, expected, 'valid reverse query for size: '+ size); + t.equal( query.size, size ? size : 1, 'valid reverse query for size: '+ size); }); t.end(); });