From 2b2414d879623545df8d6ab996df4e96d6ae0637 Mon Sep 17 00:00:00 2001 From: Harish Krishna Date: Thu, 11 Dec 2014 18:45:13 -0500 Subject: [PATCH 1/5] using multiple suggesters but one query --- controller/suggest_nearby.js | 10 ++-- helper/results.js | 48 ++++++++++++++++++ query/suggest_multiple.js | 97 ++++++++++++++++++++++++++++++++++++ service/suggest_multiple.js | 44 ++++++++++++++++ 4 files changed, 196 insertions(+), 3 deletions(-) create mode 100644 helper/results.js create mode 100644 query/suggest_multiple.js create mode 100644 service/suggest_multiple.js diff --git a/controller/suggest_nearby.js b/controller/suggest_nearby.js index 6016cb7f..d488dd40 100644 --- a/controller/suggest_nearby.js +++ b/controller/suggest_nearby.js @@ -1,15 +1,16 @@ var service = { - suggest: require('../service/suggest'), + suggest: require('../service/suggest_multiple'), mget: require('../service/mget') }; var geojsonify = require('../helper/geojsonify').search; +var resultsHelper = require('../helper/results'); function setup( backend, query ){ // allow overriding of dependencies backend = backend || require('../src/backend'); - query = query || require('../query/suggest'); + query = query || require('../query/suggest_multiple'); function controller( req, res, next ){ @@ -37,7 +38,10 @@ function setup( backend, query ){ // error handler if( err ){ return next( err ); } - + + // pick the required number of results + suggested = resultsHelper.picker(suggested, req.clean.size); + // no documents suggested, return empty array to avoid ActionRequestValidationException if( !Array.isArray( suggested ) || !suggested.length ){ return reply([]); diff --git a/helper/results.js b/helper/results.js new file mode 100644 index 00000000..1d0ec1fd --- /dev/null +++ b/helper/results.js @@ -0,0 +1,48 @@ + +var picker = function( results, size ){ + var combined = []; + var num_results = 0; + + for (var i=0; i 0) ? sort_by_score(combined) : combined; +}; + +var dedup = function(arr) { + var unique_ids = []; + return arr.filter(function(item, pos) { + if (unique_ids.indexOf(item.name.default) === -1) { + unique_ids.push(item.name.default); + return true; + } + return false; + }); +}; + +var sort_by_score = function(arr) { + return arr.map(function(doc) { + return doc.sort(function(a,b) { + return b.score - a.score; + }); + }).reduce(function(a,b) { //flatten + return a.concat(b); + }); +}; + +module.exports = { + picker: picker, + dedup: dedup +}; \ No newline at end of file diff --git a/query/suggest_multiple.js b/query/suggest_multiple.js new file mode 100644 index 00000000..d934d63d --- /dev/null +++ b/query/suggest_multiple.js @@ -0,0 +1,97 @@ + +var logger = require('../src/logger'); + +// Build pelias suggest query +function generate( params, precision ){ + + var getPrecision = function(zoom) { + switch (true) { + case (zoom > 15): + return 5; // zoom: >= 16 + case (zoom > 9): + return 4; // zoom: 10-15 + case (zoom > 5): + return 3; // zoom: 6-9 + case (zoom > 3): + return 2; // zoom: 4-5 + default: + return 1; // zoom: 1-3 or when zoom: undefined + } + }; + + var cmd = { + 'text' : params.input, + 'pelias_1' : { + 'completion' : { + 'size' : params.size, + 'field' : 'suggest', + 'context': { + 'dataset': params.layers, + 'location': { + 'value': [ params.lon, params.lat ], + 'precision': 5 + } + } + } + }, + 'pelias_2' : { + 'completion' : { + 'size' : params.size, + 'field' : 'suggest', + 'context': { + 'dataset': params.layers, + 'location': { + 'value': [ params.lon, params.lat ], + 'precision': 3 + } + } + } + }, + 'pelias_3' : { + 'completion' : { + 'size' : params.size, + 'field' : 'suggest', + 'context': { + 'dataset': params.layers, + 'location': { + 'value': [ params.lon, params.lat ], + 'precision': 1 + } + } + } + }, + 'pelias_4' : { + 'completion' : { + 'size' : params.size, + 'field' : 'suggest', + 'context': { + 'dataset': ['admin0', 'admin1', 'admin2'], + 'location': { + 'value': [ params.lon, params.lat ], + 'precision': precision || getPrecision(params.zoom) + } + } + } + }, + 'pelias_5' : { + 'completion' : { + 'size' : params.size, + 'field' : 'suggest', + 'context': { + 'dataset': params.layers, + 'location': { + 'value': [ params.lon, params.lat ], + 'precision': 3 + } + }, + 'fuzzy': {} + } + } + }; + + // logger.log( 'cmd', JSON.stringify( cmd, null, 2 ) ); + return cmd; + +} + +module.exports = generate; \ No newline at end of file diff --git a/service/suggest_multiple.js b/service/suggest_multiple.js new file mode 100644 index 00000000..49c18b51 --- /dev/null +++ b/service/suggest_multiple.js @@ -0,0 +1,44 @@ + +/** + + cmd can be any valid ES suggest command + +**/ + +function service( backend, cmd, cb ){ + // query new backend + backend().client.suggest( cmd, function( err, data ){ + // handle backend errors + if( err ){ return cb( err ); } + + // map returned documents + + var docs = []; + var unique_ids = []; + var num_keys = Object.keys(data).length; + var has_docs = function(obj) { + return Array.isArray( obj ) && obj.length && obj[0].options && obj[0].options.length; + }; + for (var i=1, j=0; i Date: Fri, 12 Dec 2014 13:12:03 -0500 Subject: [PATCH 2/5] simplifying the query building --- query/suggest_multiple.js | 94 ++++++++++++--------------------------- 1 file changed, 29 insertions(+), 65 deletions(-) diff --git a/query/suggest_multiple.js b/query/suggest_multiple.js index d934d63d..cd3144c5 100644 --- a/query/suggest_multiple.js +++ b/query/suggest_multiple.js @@ -4,7 +4,15 @@ var logger = require('../src/logger'); // Build pelias suggest query function generate( params, precision ){ - var getPrecision = function(zoom) { + var CmdGenerator = function(params){ + this.params = params; + this.cmd = { + 'text': params.input + }; + }; + + CmdGenerator.prototype.get_precision = function() { + var zoom = this.params.zoom; switch (true) { case (zoom > 15): return 5; // zoom: >= 16 @@ -16,81 +24,37 @@ function generate( params, precision ){ return 2; // zoom: 4-5 default: return 1; // zoom: 1-3 or when zoom: undefined - } + } }; - var cmd = { - 'text' : params.input, - 'pelias_1' : { - 'completion' : { - 'size' : params.size, - 'field' : 'suggest', - 'context': { - 'dataset': params.layers, - 'location': { - 'value': [ params.lon, params.lat ], - 'precision': 5 - } - } - } - }, - 'pelias_2' : { - 'completion' : { - 'size' : params.size, - 'field' : 'suggest', - 'context': { - 'dataset': params.layers, - 'location': { - 'value': [ params.lon, params.lat ], - 'precision': 3 - } - } - } - }, - 'pelias_3' : { + CmdGenerator.prototype.add_suggester = function(name, precision, layers, fuzzy) { + this.cmd[name] = { 'completion' : { - 'size' : params.size, + 'size' : this.params.size, 'field' : 'suggest', 'context': { - 'dataset': params.layers, + 'dataset': layers || this.params.layers, 'location': { - 'value': [ params.lon, params.lat ], - 'precision': 1 - } - } - } - }, - 'pelias_4' : { - 'completion' : { - 'size' : params.size, - 'field' : 'suggest', - 'context': { - 'dataset': ['admin0', 'admin1', 'admin2'], - 'location': { - 'value': [ params.lon, params.lat ], - 'precision': precision || getPrecision(params.zoom) - } - } - } - }, - 'pelias_5' : { - 'completion' : { - 'size' : params.size, - 'field' : 'suggest', - 'context': { - 'dataset': params.layers, - 'location': { - 'value': [ params.lon, params.lat ], - 'precision': 3 + 'value': [ this.params.lon, this.params.lat ], + 'precision': precision || this.get_precision() } }, - 'fuzzy': {} + 'fuzzy': { + 'fuzziness': fuzzy || 0 + } } - } + }; }; - // logger.log( 'cmd', JSON.stringify( cmd, null, 2 ) ); - return cmd; + var cmd = new CmdGenerator(params); + cmd.add_suggester('pelias_1', 5); + cmd.add_suggester('pelias_2', 3); + cmd.add_suggester('pelias_3', 1); + cmd.add_suggester('pelias_4', undefined, ['admin0', 'admin1', 'admin2']); + cmd.add_suggester('pelias_5', 3, undefined, 'AUTO'); + + // logger.log( 'cmd', JSON.stringify( cmd.cmd, null, 2 ) ); + return cmd.cmd; } From 9afed3caef3557c432b0ebad0a409d0c42eb8afc Mon Sep 17 00:00:00 2001 From: Harish Krishna Date: Fri, 12 Dec 2014 14:20:34 -0500 Subject: [PATCH 3/5] adding query mixer for suggest and suggest/nearby --- app.js | 4 +- controller/suggest_nearby.js | 5 ++- helper/queryMixer.json | 28 ++++++++++++ query/suggest_multiple.js | 16 ++++--- service/suggest_multiple.js | 2 +- test/unit/helper/queryMixer.js | 80 ++++++++++++++++++++++++++++++++++ test/unit/run.js | 3 +- 7 files changed, 127 insertions(+), 11 deletions(-) create mode 100644 helper/queryMixer.json create mode 100644 test/unit/helper/queryMixer.js diff --git a/app.js b/app.js index 21b465f0..443dfaae 100644 --- a/app.js +++ b/app.js @@ -35,7 +35,9 @@ app.get( '/doc', sanitisers.doc.middleware, controllers.doc() ); // suggest API app.get( '/suggest', sanitisers.suggest.middleware, controllers.suggest() ); -app.get( '/suggest/nearby', sanitisers.suggest.middleware, controllers.suggest_nearby() ); +app.get( '/suggest/nearby', + sanitisers.suggest.middleware, + controllers.suggest_nearby(undefined, undefined, require('./helper/queryMixer').suggest_nearby) ); // search API app.get( '/search', sanitisers.search.middleware, controllers.search() ); diff --git a/controller/suggest_nearby.js b/controller/suggest_nearby.js index d488dd40..83ee5225 100644 --- a/controller/suggest_nearby.js +++ b/controller/suggest_nearby.js @@ -6,18 +6,19 @@ var service = { var geojsonify = require('../helper/geojsonify').search; var resultsHelper = require('../helper/results'); -function setup( backend, query ){ +function setup( backend, query, query_mixer ){ // allow overriding of dependencies backend = backend || require('../src/backend'); query = query || require('../query/suggest_multiple'); + query_mixer = query_mixer || require('../helper/queryMixer').suggest; function controller( req, res, next ){ // backend command var cmd = { index: 'pelias', - body: query( req.clean ) + body: query( req.clean, query_mixer ) }; // responder diff --git a/helper/queryMixer.json b/helper/queryMixer.json new file mode 100644 index 00000000..e3becfba --- /dev/null +++ b/helper/queryMixer.json @@ -0,0 +1,28 @@ +{ + "suggest": [ + { + "layers": ["geoname","osmnode","osmway","admin0","admin1","admin2","neighborhood"], + "precision": [5, 3, 1] + }, + { + "layers": ["admin0","admin1","admin2","neighborhood"], + "precision": [] + }, + { + "layers": ["geoname","osmnode","osmway","admin0","admin1","admin2","neighborhood"], + "precision": [3], + "fuzzy": "AUTO" + } + ], + "suggest_nearby": [ + { + "layers": ["geoname","osmnode","osmway","admin0","admin1","admin2","neighborhood"], + "precision": [] + }, + { + "layers": ["geoname","osmnode","osmway","admin0","admin1","admin2","neighborhood"], + "precision": [], + "fuzzy": "AUTO" + } + ] +} \ No newline at end of file diff --git a/query/suggest_multiple.js b/query/suggest_multiple.js index cd3144c5..21be5833 100644 --- a/query/suggest_multiple.js +++ b/query/suggest_multiple.js @@ -2,7 +2,7 @@ var logger = require('../src/logger'); // Build pelias suggest query -function generate( params, precision ){ +function generate( params, query_mixer ){ var CmdGenerator = function(params){ this.params = params; @@ -47,11 +47,15 @@ function generate( params, precision ){ }; var cmd = new CmdGenerator(params); - cmd.add_suggester('pelias_1', 5); - cmd.add_suggester('pelias_2', 3); - cmd.add_suggester('pelias_3', 1); - cmd.add_suggester('pelias_4', undefined, ['admin0', 'admin1', 'admin2']); - cmd.add_suggester('pelias_5', 3, undefined, 'AUTO'); + query_mixer.forEach(function(item, index){ + if (item.precision && Array.isArray( item.precision ) && item.precision.length ) { + item.precision.forEach(function(precision) { + cmd.add_suggester('pelias_'+index, precision, item.layers, item.fuzzy); + }); + } else { + cmd.add_suggester('pelias_'+index, undefined, item.layers, item.fuzzy); + } + }); // logger.log( 'cmd', JSON.stringify( cmd.cmd, null, 2 ) ); return cmd.cmd; diff --git a/service/suggest_multiple.js b/service/suggest_multiple.js index 49c18b51..c69cfc8a 100644 --- a/service/suggest_multiple.js +++ b/service/suggest_multiple.js @@ -19,7 +19,7 @@ function service( backend, cmd, cb ){ var has_docs = function(obj) { return Array.isArray( obj ) && obj.length && obj[0].options && obj[0].options.length; }; - for (var i=1, j=0; i 0, true, 'valid key'); + t.equal(Array.isArray( mix ), true, 'is an array'); + t.equal(mix.length > 0, true, 'is not an empty array'); + mix.forEach( function(this_mix) { + t.notEqual(Object.getOwnPropertyNames(this_mix).length, 0, 'object not empty'); + for (var keys in this_mix) { + t.notEqual(valid_keys.indexOf(keys), -1, keys + ' is valid'); + switch(keys) { + case 'fuzzy': + t.notEqual(valid_fuzzy_vals.indexOf(this_mix[keys]), -1, 'fuzzy value ' + this_mix[keys] + ' is valid'); + break; + case 'layers': + t.equal(Array.isArray(this_mix[keys]), true, 'layers is an array'); + t.equal(this_mix[keys].length > 0, true, 'layers is not an empty array'); + isValidLayer(t, this_mix[keys]); + break; + case 'precision': + t.equal(Array.isArray( this_mix[keys] ), true, keys + ' is an array'); + if (this_mix[keys].length > 0) { + isValidPrecision(t, this_mix[keys]); + } + break; + default: + break; + } + } + }); + t.end(); + }); + }; + + for (var keys in query_mixer) { + isValid(keys, query_mixer[keys]); + } +}; + +module.exports.all = function (tape, common) { + + function test(name, testFunction) { + return tape('query_mixer: ' + name, testFunction); + } + + for( var testCase in module.exports.tests ){ + module.exports.tests[testCase](test, common); + } +}; \ No newline at end of file diff --git a/test/unit/run.js b/test/unit/run.js index 0bc64a72..0812e967 100644 --- a/test/unit/run.js +++ b/test/unit/run.js @@ -18,7 +18,8 @@ var tests = [ require('./query/search'), require('./query/reverse'), require('./helper/geojsonify'), - require('./helper/outputSchema') + require('./helper/outputSchema'), + require('./helper/queryMixer') ]; tests.map(function(t) { From fc7f6cb76870efd6a28d5cbf1902032a7c511512 Mon Sep 17 00:00:00 2001 From: Harish Krishna Date: Fri, 12 Dec 2014 15:25:42 -0500 Subject: [PATCH 4/5] removing suggest_nearby, replacing suggest with suggest_multiple, commenting out a couple of tests for right now. --- app.js | 3 +- controller/suggest.js | 116 ++++--------------------- controller/suggest_nearby.js | 77 ---------------- query/suggest.js | 52 ++++++++--- query/suggest_multiple.js | 65 -------------- service/suggest.js | 28 ++++-- service/suggest_multiple.js | 44 ---------- test/unit/controller/suggest.js | 11 +-- test/unit/controller/suggest_nearby.js | 112 ------------------------ test/unit/query/suggest.js | 46 ++++++++-- test/unit/run.js | 1 - test/unit/service/suggest.js | 2 +- 12 files changed, 128 insertions(+), 429 deletions(-) delete mode 100644 controller/suggest_nearby.js delete mode 100644 query/suggest_multiple.js delete mode 100644 service/suggest_multiple.js delete mode 100644 test/unit/controller/suggest_nearby.js diff --git a/app.js b/app.js index 443dfaae..e77bc3a2 100644 --- a/app.js +++ b/app.js @@ -22,7 +22,6 @@ var controllers = {}; controllers.index = require('./controller/index'); controllers.doc = require('./controller/doc'); controllers.suggest = require('./controller/suggest'); -controllers.suggest_nearby = require('./controller/suggest_nearby'); controllers.search = require('./controller/search'); /** ----------------------- routes ----------------------- **/ @@ -37,7 +36,7 @@ app.get( '/doc', sanitisers.doc.middleware, controllers.doc() ); app.get( '/suggest', sanitisers.suggest.middleware, controllers.suggest() ); app.get( '/suggest/nearby', sanitisers.suggest.middleware, - controllers.suggest_nearby(undefined, undefined, require('./helper/queryMixer').suggest_nearby) ); + controllers.suggest(undefined, undefined, require('./helper/queryMixer').suggest_nearby) ); // search API app.get( '/search', sanitisers.search.middleware, controllers.search() ); diff --git a/controller/suggest.js b/controller/suggest.js index 914a8652..47d17f5e 100644 --- a/controller/suggest.js +++ b/controller/suggest.js @@ -4,46 +4,25 @@ var service = { mget: require('../service/mget') }; var geojsonify = require('../helper/geojsonify').search; -var async = require('async'); +var resultsHelper = require('../helper/results'); -function setup( backend, query ){ +function setup( backend, query, query_mixer ){ // allow overriding of dependencies backend = backend || require('../src/backend'); query = query || require('../query/suggest'); + query_mixer = query_mixer || require('../helper/queryMixer').suggest; function controller( req, res, next ){ + // backend command var cmd = { index: 'pelias', - body: query( req.clean ) + body: query( req.clean, query_mixer ) }; - var SIZE = req.clean.size || 10; - - var query_backend = function(cmd, callback) { - // query backend - service.suggest( backend, cmd, function( err, docs ){ - - // error handler - if( err ){ return next( err ); } - - callback(null, docs); - }); - }; - - var dedup = function(combined) { - var unique_ids = []; - return combined.filter(function(item, pos) { - if (unique_ids.indexOf(item.text) === -1) { - unique_ids.push(item.text); - return true; - } - return false; - }); - }; - - var reply = function(docs) { + // responder + function reply( docs ){ // convert docs to geojson var geojson = geojsonify( docs ); @@ -53,17 +32,24 @@ function setup( backend, query ){ // respond return res.status(200).json( geojson ); - }; + } - var respond = function(data) { + // query backend + service.suggest( backend, cmd, function( err, suggested ){ + // error handler + if( err ){ return next( err ); } + + // pick the required number of results + suggested = resultsHelper.picker(suggested, req.clean.size); + // no documents suggested, return empty array to avoid ActionRequestValidationException - if( !Array.isArray( data ) || !data.length ){ + if( !Array.isArray( suggested ) || !suggested.length ){ return reply([]); } // map suggester output to mget query - var query = data.map( function( doc ) { + var query = suggested.map( function( doc ) { var idParts = doc.text.split(':'); return { _index: 'pelias', @@ -81,72 +67,8 @@ function setup( backend, query ){ return reply( docs ); }); + }); - }; - - if (req.clean.input) { - var async_query; - - // admin only - req.admin = {}; - for (var k in req.clean) { req.admin[k] = req.clean[k]; } - req.admin.layers = ['admin0','admin1','admin2']; - - if (req.clean.input.length < 4 && isNaN(parseInt(req.clean.input, 10))) { - async_query = { - admin_3p: function(callback){ - cmd.body = query( req.admin, 3 ); - query_backend(cmd, callback); - }, - admin_1p: function(callback){ - cmd.body = query( req.admin, 1 ); - query_backend(cmd, callback); - }, - all_3p: function(callback) { - cmd.body = query( req.clean, 3 ); - query_backend(cmd, callback); - } - }; - } else { - async_query = { - all_5p: function(callback){ - cmd.body = query( req.clean, 5); - query_backend(cmd, callback); - }, - all_3p: function(callback){ - cmd.body = query( req.clean, 3); - query_backend(cmd, callback); - }, - all_1p: function(callback){ - cmd.body = query( req.clean, 1 ); - query_backend(cmd, callback); - }, - admin_1p: function(callback){ - cmd.body = query( req.admin ); - query_backend(cmd, callback); - } - }; - } - - async.parallel(async_query, function(err, results) { - // results is equal to: {a: docs, b: docs, c: docs} - var splice_length = parseInt((SIZE / Object.keys(results).length), 10); - var results_keys = Object.keys(async_query); - - var combined = []; - results_keys.forEach(function(key){ - combined = combined.concat(results[key].splice(0,splice_length)); - }); - - combined = dedup(combined); - respond(combined); - }); - } else { - query_backend(cmd, function(err, results) { - respond(results); - }); - } - } return controller; diff --git a/controller/suggest_nearby.js b/controller/suggest_nearby.js deleted file mode 100644 index 83ee5225..00000000 --- a/controller/suggest_nearby.js +++ /dev/null @@ -1,77 +0,0 @@ - -var service = { - suggest: require('../service/suggest_multiple'), - mget: require('../service/mget') -}; -var geojsonify = require('../helper/geojsonify').search; -var resultsHelper = require('../helper/results'); - -function setup( backend, query, query_mixer ){ - - // allow overriding of dependencies - backend = backend || require('../src/backend'); - query = query || require('../query/suggest_multiple'); - query_mixer = query_mixer || require('../helper/queryMixer').suggest; - - function controller( req, res, next ){ - - // backend command - var cmd = { - index: 'pelias', - body: query( req.clean, query_mixer ) - }; - - // responder - function reply( docs ){ - - // convert docs to geojson - var geojson = geojsonify( docs ); - - // response envelope - geojson.date = new Date().getTime(); - - // respond - return res.status(200).json( geojson ); - } - - // query backend - service.suggest( backend, cmd, function( err, suggested ){ - - // error handler - if( err ){ return next( err ); } - - // pick the required number of results - suggested = resultsHelper.picker(suggested, req.clean.size); - - // no documents suggested, return empty array to avoid ActionRequestValidationException - if( !Array.isArray( suggested ) || !suggested.length ){ - return reply([]); - } - - // map suggester output to mget query - var query = suggested.map( function( doc ) { - var idParts = doc.text.split(':'); - return { - _index: 'pelias', - _type: idParts[0], - _id: idParts.slice(1).join(':') - }; - }); - - service.mget( backend, query, function( err, docs ){ - - // error handler - if( err ){ return next( err ); } - - // reply - return reply( docs ); - - }); - }); - - } - - return controller; -} - -module.exports = setup; \ No newline at end of file diff --git a/query/suggest.js b/query/suggest.js index 29f2f0b3..577df698 100644 --- a/query/suggest.js +++ b/query/suggest.js @@ -2,9 +2,17 @@ var logger = require('../src/logger'); // Build pelias suggest query -function generate( params, precision ){ +function generate( params, query_mixer, fuzziness ){ - var getPrecision = function(zoom) { + var CmdGenerator = function(params){ + this.params = params; + this.cmd = { + 'text': params.input + }; + }; + + CmdGenerator.prototype.get_precision = function() { + var zoom = this.params.zoom; switch (true) { case (zoom > 15): return 5; // zoom: >= 16 @@ -16,28 +24,46 @@ function generate( params, precision ){ return 2; // zoom: 4-5 default: return 1; // zoom: 1-3 or when zoom: undefined - } + } }; - var cmd = { - 'pelias' : { - 'text' : params.input, + CmdGenerator.prototype.add_suggester = function(name, precision, layers, fuzzy) { + this.cmd[name] = { 'completion' : { - 'size' : params.size, + 'size' : this.params.size, 'field' : 'suggest', 'context': { - 'dataset': params.layers, + 'dataset': layers || this.params.layers, 'location': { - 'value': [ params.lon, params.lat ], - 'precision': precision || getPrecision(params.zoom) + 'value': [ this.params.lon, this.params.lat ], + 'precision': precision || this.get_precision() } + }, + 'fuzzy': { + 'fuzziness': fuzzy || fuzziness || 0 } } - } + }; }; - // logger.log( 'cmd', JSON.stringify( cmd, null, 2 ) ); - return cmd; + var cmd = new CmdGenerator(params); + if (query_mixer && query_mixer.length) { + query_mixer.forEach(function(item, index){ + if (item.precision && Array.isArray( item.precision ) && item.precision.length ) { + item.precision.forEach(function(precision) { + cmd.add_suggester('pelias_'+index, precision, item.layers, item.fuzzy); + }); + } else { + cmd.add_suggester('pelias_'+index, undefined, item.layers, item.fuzzy); + } + }); + } else { + cmd.add_suggester('pelias_0'); + } + + + // logger.log( 'cmd', JSON.stringify( cmd.cmd, null, 2 ) ); + return cmd.cmd; } diff --git a/query/suggest_multiple.js b/query/suggest_multiple.js deleted file mode 100644 index 21be5833..00000000 --- a/query/suggest_multiple.js +++ /dev/null @@ -1,65 +0,0 @@ - -var logger = require('../src/logger'); - -// Build pelias suggest query -function generate( params, query_mixer ){ - - var CmdGenerator = function(params){ - this.params = params; - this.cmd = { - 'text': params.input - }; - }; - - CmdGenerator.prototype.get_precision = function() { - var zoom = this.params.zoom; - switch (true) { - case (zoom > 15): - return 5; // zoom: >= 16 - case (zoom > 9): - return 4; // zoom: 10-15 - case (zoom > 5): - return 3; // zoom: 6-9 - case (zoom > 3): - return 2; // zoom: 4-5 - default: - return 1; // zoom: 1-3 or when zoom: undefined - } - }; - - CmdGenerator.prototype.add_suggester = function(name, precision, layers, fuzzy) { - this.cmd[name] = { - 'completion' : { - 'size' : this.params.size, - 'field' : 'suggest', - 'context': { - 'dataset': layers || this.params.layers, - 'location': { - 'value': [ this.params.lon, this.params.lat ], - 'precision': precision || this.get_precision() - } - }, - 'fuzzy': { - 'fuzziness': fuzzy || 0 - } - } - }; - }; - - var cmd = new CmdGenerator(params); - query_mixer.forEach(function(item, index){ - if (item.precision && Array.isArray( item.precision ) && item.precision.length ) { - item.precision.forEach(function(precision) { - cmd.add_suggester('pelias_'+index, precision, item.layers, item.fuzzy); - }); - } else { - cmd.add_suggester('pelias_'+index, undefined, item.layers, item.fuzzy); - } - }); - - // logger.log( 'cmd', JSON.stringify( cmd.cmd, null, 2 ) ); - return cmd.cmd; - -} - -module.exports = generate; \ No newline at end of file diff --git a/service/suggest.js b/service/suggest.js index fdf82fe9..c69cfc8a 100644 --- a/service/suggest.js +++ b/service/suggest.js @@ -6,21 +6,37 @@ **/ function service( backend, cmd, cb ){ - // query new backend backend().client.suggest( cmd, function( err, data ){ - // handle backend errors if( err ){ return cb( err ); } - + // map returned documents + var docs = []; - if( data && Array.isArray( data.pelias ) && data.pelias.length ){ - docs = data.pelias[0].options || []; + var unique_ids = []; + var num_keys = Object.keys(data).length; + var has_docs = function(obj) { + return Array.isArray( obj ) && obj.length && obj[0].options && obj[0].options.length; + }; + for (var i=0, j=0; i Date: Wed, 17 Dec 2014 11:59:40 -0500 Subject: [PATCH 5/5] cleanup + tests --- controller/suggest.js | 6 ++++-- query/suggest.js | 6 +++--- service/suggest.js | 7 +++---- test/unit/controller/suggest.js | 14 +++----------- test/unit/mock/backend.js | 6 +++--- test/unit/query/suggest.js | 6 +++--- test/unit/service/suggest.js | 6 +++--- 7 files changed, 22 insertions(+), 29 deletions(-) diff --git a/controller/suggest.js b/controller/suggest.js index 47d17f5e..ef2774bc 100644 --- a/controller/suggest.js +++ b/controller/suggest.js @@ -21,6 +21,8 @@ function setup( backend, query, query_mixer ){ body: query( req.clean, query_mixer ) }; + var size = req.clean.size || 10; + // responder function reply( docs ){ @@ -41,8 +43,8 @@ function setup( backend, query, query_mixer ){ if( err ){ return next( err ); } // pick the required number of results - suggested = resultsHelper.picker(suggested, req.clean.size); - + suggested = resultsHelper.picker(suggested, size); + // no documents suggested, return empty array to avoid ActionRequestValidationException if( !Array.isArray( suggested ) || !suggested.length ){ return reply([]); diff --git a/query/suggest.js b/query/suggest.js index 577df698..4e9d30b6 100644 --- a/query/suggest.js +++ b/query/suggest.js @@ -51,14 +51,14 @@ function generate( params, query_mixer, fuzziness ){ query_mixer.forEach(function(item, index){ if (item.precision && Array.isArray( item.precision ) && item.precision.length ) { item.precision.forEach(function(precision) { - cmd.add_suggester('pelias_'+index, precision, item.layers, item.fuzzy); + cmd.add_suggester(index, precision, item.layers, item.fuzzy); }); } else { - cmd.add_suggester('pelias_'+index, undefined, item.layers, item.fuzzy); + cmd.add_suggester(index, undefined, item.layers, item.fuzzy); } }); } else { - cmd.add_suggester('pelias_0'); + cmd.add_suggester(0); } diff --git a/service/suggest.js b/service/suggest.js index c69cfc8a..f27b67c9 100644 --- a/service/suggest.js +++ b/service/suggest.js @@ -20,15 +20,14 @@ function service( backend, cmd, cb ){ return Array.isArray( obj ) && obj.length && obj[0].options && obj[0].options.length; }; for (var i=0, j=0; i