diff --git a/query/autocomplete.js b/query/autocomplete.js index 416b255b..bf5f76aa 100644 --- a/query/autocomplete.js +++ b/query/autocomplete.js @@ -6,47 +6,10 @@ var peliasQuery = require('pelias-query'), // additional views (these may be merged in to pelias/query at a later date) var views = { - ngrams_strict: require('./view/ngrams_strict'), - focus_selected_layers: require('./view/focus_selected_layers') -}; - -var ngrams_last_only = function( vs ){ - - // hack to disable ngrams when query parsing enabled - if( vs.var('parsed_text').get() ){ - return null; - } - - var name = vs.var('input:name').get(); - - var vs2 = new peliasQuery.Vars( vs.export() ); - vs2.var('input:name').set( name.substr( name.lastIndexOf(' ')+1 ) ); - - var view = views.ngrams_strict( vs2 ); - view.match['name.default'].analyzer = 'peliasPhrase'; - - return view; -}; - -var phrase_first_only = function( vs ){ - - // hack to disable substr when query parsing enabled - if( !vs.var('parsed_text').get() ){ - - var name = vs.var('input:name').get(); - var s = name.split(' '); - - // single token only, abort - if( s.length < 2 ){ - return null; - } - - var vs2 = new peliasQuery.Vars( vs.export() ); - vs2.var('input:name').set( name.substr(0, name.lastIndexOf(' ') ) ); - return peliasQuery.view.phrase( vs2 ); - } - - return peliasQuery.view.phrase( vs ); + ngrams_strict: require('./view/ngrams_strict'), + focus_selected_layers: require('./view/focus_selected_layers'), + ngrams_last_token_only: require('./view/ngrams_last_token_only'), + phrase_first_tokens_only: require('./view/phrase_first_tokens_only') }; //------------------------------ @@ -55,8 +18,8 @@ var phrase_first_only = function( vs ){ var query = new peliasQuery.layout.FilteredBooleanQuery(); // mandatory matches -query.score( phrase_first_only, 'must' ); -query.score( ngrams_last_only, 'must' ); +query.score( views.phrase_first_tokens_only, 'must' ); +query.score( views.ngrams_last_token_only, 'must' ); // address components query.score( peliasQuery.view.address('housenumber') ); @@ -87,16 +50,26 @@ query.score( peliasQuery.view.population( views.ngrams_strict ) ); function generateQuery( clean ){ var vs = new peliasQuery.Vars( defaults ); - vs.var( 'parsed_text', false ); - // remove single grams at end + // mark the name as incomplete (user has not yet typed a comma) + vs.var( 'input:name:isComplete', false ); + + // perform some operations on 'clean.text': + // 1. if there is a space followed by a single char, remove them. + // - this is required as the index uses 2grams and sending 1grams + // - to a 2gram index when using 'type:phrase' or 'operator:and' will + // - result in a complete failure of the query. + // 2. trim leading and trailing whitespace. var text = clean.text.replace(/( .$)/g,'').trim(); - if( clean.hasOwnProperty('parsed_text') ){ - if( clean.parsed_text.hasOwnProperty('name') ){ - vs.var( 'parsed_text', true ); - text = clean.parsed_text.name; - } + // if the input parser has run and suggested a 'parsed_text.name' to use. + if( clean.hasOwnProperty('parsed_text') && clean.parsed_text.hasOwnProperty('name') ){ + + // mark the name as complete (user has already typed a comma) + vs.var( 'input:name:isComplete', true ); + + // use 'parsed_text.name' instead of 'clean.text'. + text = clean.parsed_text.name; } // input text diff --git a/query/view/ngrams_last_token_only.js b/query/view/ngrams_last_token_only.js new file mode 100644 index 00000000..3e3315f7 --- /dev/null +++ b/query/view/ngrams_last_token_only.js @@ -0,0 +1,37 @@ + +var peliasQuery = require('pelias-query'), + ngrams_strict = require('./ngrams_strict'); + +/** + Ngrams view which trims the 'input:name' and only uses the LAST TOKEN. + + eg. if the input was "100 foo str", then 'input:name' would only be 'str' + note: it is assumed that the rest of the input is matched using another view. + + there is an additional flag 'input:name:isComplete' used to disable this view + selectively, see that section for more info. + + code notes: this view makes a copy of the $vs object in order to change their + values without mutating the original values, which may be expected in their + unaltered form by other views. +**/ + +module.exports = function( vs ){ + + // Totally disable this view when bool value 'input:name:isComplete' is true. + // This is the case when the user has typed a comma, so we can assume + // that the 'name' part of the query is now complete. + if( vs.var('input:name:isComplete').get() ){ return null; } + + // make a copy Vars so we don't mutate the original + var vsCopy = new peliasQuery.Vars( vs.export() ); + + // get the input 'name' variable + var name = vs.var('input:name').get(); + + // set the 'name' variable in the copy to only the last token + vsCopy.var('input:name').set( name.substr( name.lastIndexOf(' ')+1 ) ); + + // return the view rendered using the copy + return ngrams_strict( vsCopy ); +}; diff --git a/query/view/phrase_first_tokens_only.js b/query/view/phrase_first_tokens_only.js new file mode 100644 index 00000000..b047b30f --- /dev/null +++ b/query/view/phrase_first_tokens_only.js @@ -0,0 +1,44 @@ + +var peliasQuery = require('pelias-query'); + +/** + Phrase view which trims the 'input:name' and uses ALL BUT the last token. + + eg. if the input was "100 foo str", then 'input:name' would only be '100 foo' + note: it is assumed that the rest of the input is matched using another view. + + there is an additional flag 'input:name:isComplete' used to disable this view + selectively, see that section for more info. + + code notes: this view makes a copy of the $vs object in order to change their + values without mutating the original values, which may be expected in their + unaltered form by other views. +**/ + +module.exports = function( vs ){ + + // Don't mutate the name variable when 'input:name:isComplete' is true. + // This is the case when the user has typed a comma, so we can assume + // that the 'name' part of the query is now complete. + if( vs.var('input:name:isComplete').get() ){ + // return the view rendered using the original vars + return peliasQuery.view.phrase( vs ); + } + + // make a copy Vars so we don't mutate the original + var vsCopy = new peliasQuery.Vars( vs.export() ); + + // get the input 'name' variable and split in to tokens + var name = vs.var('input:name').get(), + tokens = name.split(' '); + + // single token only, abort (we don't want the *last* token) + // return null here will completely disable the view. + if( tokens.length < 2 ){ return null; } + + // set the 'name' variable in the copy to all but the last token + vsCopy.var('input:name').set( name.substr( 0, name.lastIndexOf(' ') ) ); + + // return the view rendered using the copy + return peliasQuery.view.phrase( vsCopy ); +};