mirror of https://github.com/pelias/api.git
Stephen K Hess
8 years ago
committed by
GitHub
74 changed files with 7079 additions and 1760 deletions
@ -0,0 +1,177 @@
|
||||
var _ = require('lodash'); |
||||
var placeTypes = require('./placeTypes'); |
||||
|
||||
/** |
||||
* Compare the layer properties if they exist. |
||||
* Returns false if the objects are the same, and throws |
||||
* an exception with the message 'different' if not. |
||||
* |
||||
* @param {object} item1 |
||||
* @param {object} item2 |
||||
* @returns {boolean} |
||||
* @throws {Error} |
||||
*/ |
||||
function assertLayerMatch(item1, item2) { |
||||
if (item1.layer === item2.layer) { |
||||
return false; |
||||
} |
||||
|
||||
throw new Error('different'); |
||||
} |
||||
|
||||
/** |
||||
* Compare the parent.*_id properties if they exist. |
||||
* Returns false if the objects are the same, and throws |
||||
* an exception with the message 'different' if not. |
||||
* |
||||
* @param {object} item1 |
||||
* @param {object} item2 |
||||
* @returns {boolean} |
||||
* @throws {Error} |
||||
*/ |
||||
function assertParentHierarchyMatch(item1, item2) { |
||||
// if neither object has parent, assume same
|
||||
if (!item1.hasOwnProperty('parent') && !item2.hasOwnProperty('parent')) { |
||||
return false; |
||||
} |
||||
|
||||
// if both have parent, do the rest of the checking
|
||||
if (item1.hasOwnProperty('parent') && item2.hasOwnProperty('parent')) { |
||||
placeTypes.forEach(function (placeType) { |
||||
// don't consider its own id
|
||||
if (placeType === item1.layer) { |
||||
return; |
||||
} |
||||
propMatch(item1.parent, item2.parent, placeType + '_id'); |
||||
}); |
||||
return false; |
||||
} |
||||
|
||||
// if one has parent and the other doesn't consider different
|
||||
throw new Error('different'); |
||||
} |
||||
|
||||
/** |
||||
* Compare the name.* properties if they exist. |
||||
* Returns false if the objects are the same, and throws |
||||
* an exception with the message 'different' if not. |
||||
* |
||||
* @param {object} item1 |
||||
* @param {object} item2 |
||||
* @returns {boolean} |
||||
* @throws {Error} |
||||
*/ |
||||
function assertNameMatch(item1, item2) { |
||||
if (item1.hasOwnProperty('name') && item2.hasOwnProperty('name')) { |
||||
for (var lang in item1.name) { |
||||
if(item2.name.hasOwnProperty(lang) || lang === 'default') { |
||||
// do not consider absence of an additional name as a difference
|
||||
propMatch(item1.name, item2.name, lang); |
||||
} |
||||
} |
||||
} |
||||
else { |
||||
propMatch(item1, item2, 'name'); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Compare the address_parts properties if they exist. |
||||
* Returns false if the objects are the same, and throws |
||||
* an exception with the message 'different' if not. |
||||
* |
||||
* @param {object} item1 |
||||
* @param {object} item2 |
||||
* @returns {boolean} |
||||
* @throws {Error} |
||||
*/ |
||||
function assertAddressMatch(item1, item2) { |
||||
// if neither record has address, assume same
|
||||
if (!item1.hasOwnProperty('address_parts') && !item2.hasOwnProperty('address_parts')) { |
||||
return false; |
||||
} |
||||
|
||||
// if both have address, check parts
|
||||
if (item1.hasOwnProperty('address_parts') && item2.hasOwnProperty('address_parts')) { |
||||
propMatch(item1.address_parts, item2.address_parts, 'number'); |
||||
propMatch(item1.address_parts, item2.address_parts, 'street'); |
||||
|
||||
// only compare zip if both records have it, otherwise just ignore and assume it's the same
|
||||
// since by this time we've already compared parent hierarchies
|
||||
if (item1.address_parts.hasOwnProperty('zip') && item2.address_parts.hasOwnProperty('zip')) { |
||||
propMatch(item1.address_parts, item2.address_parts, 'zip'); |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
// one has address and the other doesn't, different!
|
||||
throw new Error('different'); |
||||
} |
||||
|
||||
/** |
||||
* Compare the two records and return true if they differ and false if same. |
||||
* |
||||
* @param {object} item1 |
||||
* @param {object} item2 |
||||
* @returns {boolean} |
||||
* @throws {Error} |
||||
*/ |
||||
function isDifferent(item1, item2) { |
||||
try { |
||||
assertLayerMatch(item1, item2); |
||||
assertParentHierarchyMatch(item1, item2); |
||||
assertNameMatch(item1, item2); |
||||
assertAddressMatch(item1, item2); |
||||
} |
||||
catch (err) { |
||||
if (err.message === 'different') { |
||||
return true; |
||||
} |
||||
throw err; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Throw exception if properties are different |
||||
* |
||||
* @param {object} item1 |
||||
* @param {object} item2 |
||||
* @param {string} prop |
||||
* @throws {Error} |
||||
*/ |
||||
function propMatch(item1, item2, prop) { |
||||
var prop1 = item1[prop]; |
||||
var prop2 = item2[prop]; |
||||
|
||||
// in the case the property is an array (currently only in parent schema)
|
||||
// simply take the 1st item. this will change in the near future to support multiple hierarchies
|
||||
if (_.isArray(prop1)) { prop1 = prop1[0]; } |
||||
if (_.isArray(prop2)) { prop2 = prop2[0]; } |
||||
|
||||
if (normalizeString(prop1) !== normalizeString(prop2)) { |
||||
throw new Error('different'); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Remove punctuation and lowercase |
||||
* |
||||
* @param {string} str |
||||
* @returns {string} |
||||
*/ |
||||
function normalizeString(str) { |
||||
if (!_.isString(str)) { |
||||
return str; |
||||
} |
||||
|
||||
if (_.isEmpty(str)) { |
||||
return ''; |
||||
} |
||||
|
||||
return str.toLowerCase().split(/[ ,-]+/).join(' '); |
||||
} |
||||
|
||||
module.exports.isDifferent = isDifferent; |
@ -0,0 +1,57 @@
|
||||
/** |
||||
* |
||||
* Accuracy level should be set for each item in the results. |
||||
* The level can be any of the following: |
||||
* - point |
||||
* - interpolated |
||||
* - centroid |
||||
*/ |
||||
|
||||
var check = require('check-types'); |
||||
|
||||
var accuracyLevelPoint = 'point'; |
||||
var accuracyLevelInterpolated = 'interpolated'; |
||||
var accuracyLevelCentroid = 'centroid'; |
||||
|
||||
|
||||
function setup() { |
||||
return computeAccuracy; |
||||
} |
||||
|
||||
function computeAccuracy(req, res, next) { |
||||
// do nothing if no result data set
|
||||
if (check.undefined(res) || check.undefined(res.data)) { |
||||
return next(); |
||||
} |
||||
|
||||
// loop through data items and determine accuracy levels
|
||||
res.data = res.data.map(computeAccuracyLevelForResult); |
||||
|
||||
next(); |
||||
} |
||||
|
||||
/** |
||||
* Determine accuracy level based on the type of result being returned. |
||||
* |
||||
* @param {object} hit |
||||
* @returns {object} |
||||
*/ |
||||
function computeAccuracyLevelForResult(hit) { |
||||
|
||||
// TODO: add a check for interpolated addresses when that feature lands
|
||||
|
||||
switch (hit.layer) { |
||||
case 'venue': |
||||
case 'address': |
||||
hit.accuracy = accuracyLevelPoint; |
||||
break; |
||||
// this means it's a street or admin area
|
||||
default: |
||||
hit.accuracy = accuracyLevelCentroid; |
||||
break; |
||||
} |
||||
|
||||
return hit; |
||||
} |
||||
|
||||
module.exports = setup; |
@ -0,0 +1,118 @@
|
||||
/** |
||||
* |
||||
* Basic confidence score should be computed and returned for each item in the results. |
||||
* The score should range between 0-1, and take into consideration as many factors as possible. |
||||
* |
||||
* Some factors to consider: |
||||
* |
||||
* - number of results from ES |
||||
* - fallback status (aka layer match between expected and actual) |
||||
*/ |
||||
|
||||
var check = require('check-types'); |
||||
var logger = require('pelias-logger').get('api-confidence'); |
||||
|
||||
function setup() { |
||||
return computeScores; |
||||
} |
||||
|
||||
function computeScores(req, res, next) { |
||||
// do nothing if no result data set or if the query is not of the fallback variety
|
||||
// later add disambiguation to this list
|
||||
if (check.undefined(req.clean) || check.undefined(res) || |
||||
check.undefined(res.data) || check.undefined(res.meta) || |
||||
res.meta.query_type !== 'fallback') { |
||||
return next(); |
||||
} |
||||
|
||||
// loop through data items and determine confidence scores
|
||||
res.data = res.data.map(computeConfidenceScore.bind(null, req)); |
||||
|
||||
next(); |
||||
} |
||||
|
||||
/** |
||||
* Check all types of things to determine how confident we are that this result |
||||
* is correct. |
||||
* |
||||
* @param {object} req |
||||
* @param {object} hit |
||||
* @returns {object} |
||||
*/ |
||||
function computeConfidenceScore(req, hit) { |
||||
|
||||
// if parsed text doesn't exist, which it never should, just assign a low confidence and move on
|
||||
if (!req.clean.hasOwnProperty('parsed_text')) { |
||||
hit.confidence = 0.1; |
||||
hit.match_type = 'unknown'; |
||||
return hit; |
||||
} |
||||
|
||||
// start with a confidence level of 1 because we trust ES queries to be accurate
|
||||
hit.confidence = 1.0; |
||||
|
||||
// in the case of fallback there might be deductions
|
||||
hit.confidence *= checkFallbackLevel(req, hit); |
||||
|
||||
// truncate the precision
|
||||
hit.confidence = Number((hit.confidence).toFixed(3)); |
||||
|
||||
return hit; |
||||
} |
||||
|
||||
function checkFallbackLevel(req, hit) { |
||||
if (checkFallbackOccurred(req, hit)) { |
||||
hit.match_type = 'fallback'; |
||||
|
||||
// if we know a fallback occurred, deduct points based on layer granularity
|
||||
switch (hit.layer) { |
||||
case 'venue': |
||||
case 'address': |
||||
logger.warn('Fallback scenarios should not result in address or venue records!', req.clean.parsed_text); |
||||
return 0.8; |
||||
case 'street': |
||||
return 0.8; |
||||
case 'locality': |
||||
case 'borough': |
||||
case 'neighbourhood': |
||||
return 0.6; |
||||
case 'macrocounty': |
||||
case 'county': |
||||
case 'localadmin': |
||||
return 0.4; |
||||
case 'region': |
||||
return 0.3; |
||||
case 'country': |
||||
case 'dependency': |
||||
case 'macroregion': |
||||
return 0.1; |
||||
default: |
||||
return 0.1; |
||||
} |
||||
} |
||||
|
||||
hit.match_type = 'exact'; |
||||
return 1.0; |
||||
} |
||||
|
||||
function checkFallbackOccurred(req, hit) { |
||||
// at this time we only do this for address queries, so keep this simple
|
||||
// TODO: add other layer checks once we start handling disambiguation
|
||||
|
||||
return (requestedAddress(req) && hit.layer !== 'address') || |
||||
(requestedStreet(req) && hit.layer !== 'street'); |
||||
} |
||||
|
||||
function requestedAddress(req) { |
||||
// house number and street name were specified
|
||||
return req.clean.parsed_text.hasOwnProperty('number') && |
||||
req.clean.parsed_text.hasOwnProperty('street'); |
||||
} |
||||
|
||||
function requestedStreet(req) { |
||||
// only street name was specified
|
||||
return !req.clean.parsed_text.hasOwnProperty('number') && |
||||
req.clean.parsed_text.hasOwnProperty('street'); |
||||
} |
||||
|
||||
module.exports = setup; |
@ -0,0 +1,74 @@
|
||||
var _ = require('lodash'); |
||||
|
||||
// This middleware component trims the results array by granularity when
|
||||
// FallbackQuery was used. FallbackQuery is used for inputs like
|
||||
// `1090 N Charlotte St, Lancaster, PA` where the address may not exist and
|
||||
// we must fall back to trying `Lancaster, PA`. If the address does exist then
|
||||
// FallbackQuery will return results for:
|
||||
// - address+city+state
|
||||
// - city+state
|
||||
// - state
|
||||
//
|
||||
// Because the address matched, we're not interested in city+state or state, so
|
||||
// this component removes results that aren't the most granular.
|
||||
|
||||
// layers in increasing order of granularity
|
||||
var layers = [ |
||||
'venue', |
||||
'address', |
||||
'street', |
||||
'neighbourhood', |
||||
'borough', |
||||
'locality', |
||||
'localadmin', |
||||
'county', |
||||
'macrocounty', |
||||
'region', |
||||
'macroregion', |
||||
'dependency', |
||||
'country' |
||||
]; |
||||
|
||||
// this helper method returns `true` if every result has a matched_query
|
||||
// starting with `fallback.`
|
||||
function isFallbackQuery(results) { |
||||
return results.every(function(result) { |
||||
return result.hasOwnProperty('_matched_queries') && |
||||
!_.isEmpty(result._matched_queries) && |
||||
_.startsWith(result._matched_queries[0], 'fallback.'); |
||||
}); |
||||
} |
||||
|
||||
function hasRecordsAtLayers(results, layer) { |
||||
return results.some(function(result) { |
||||
return result._matched_queries[0] === 'fallback.' + layer; |
||||
}); |
||||
} |
||||
|
||||
function retainRecordsAtLayers(results, layer) { |
||||
return results.filter(function(result) { |
||||
return result._matched_queries[0] === 'fallback.' + layer; |
||||
}); |
||||
} |
||||
|
||||
function setup() { |
||||
return function trim(req, res, next) { |
||||
// don't do anything if there are no results or there are non-fallback.* named queries
|
||||
// there should never be a mixture of fallback.* and non-fallback.* named queries
|
||||
if (_.isUndefined(res.data) || !isFallbackQuery(res.data)) { |
||||
return next(); |
||||
} |
||||
|
||||
// start at the most granular possible layer. if there are results at a layer
|
||||
// then remove everything not at that layer.
|
||||
layers.forEach(function(layer) { |
||||
if (hasRecordsAtLayers(res.data, layer )) { |
||||
res.data = retainRecordsAtLayers(res.data, layer); |
||||
} |
||||
}); |
||||
|
||||
next(); |
||||
}; |
||||
} |
||||
|
||||
module.exports = setup; |
@ -0,0 +1,135 @@
|
||||
var peliasQuery = require('pelias-query'), |
||||
defaults = require('./search_defaults'), |
||||
textParser = require('./text_parser_addressit'), |
||||
check = require('check-types'); |
||||
|
||||
var placeTypes = require('../helper/placeTypes'); |
||||
|
||||
// region_a is also an admin field. addressit tries to detect
|
||||
// region_a, in which case we use a match query specifically for it.
|
||||
// but address it doesn't know about all of them so it helps to search
|
||||
// against this with the other admin parts as a fallback
|
||||
var adminFields = placeTypes.concat(['region_a']); |
||||
|
||||
//------------------------------
|
||||
// general-purpose search query
|
||||
//------------------------------
|
||||
var query = new peliasQuery.layout.FilteredBooleanQuery(); |
||||
|
||||
// mandatory matches
|
||||
query.score( peliasQuery.view.boundary_country, 'must' ); |
||||
query.score( peliasQuery.view.ngrams, 'must' ); |
||||
|
||||
// scoring boost
|
||||
query.score( peliasQuery.view.phrase ); |
||||
query.score( peliasQuery.view.focus( peliasQuery.view.phrase ) ); |
||||
query.score( peliasQuery.view.popularity( peliasQuery.view.phrase ) ); |
||||
query.score( peliasQuery.view.population( peliasQuery.view.phrase ) ); |
||||
|
||||
// address components
|
||||
query.score( peliasQuery.view.address('housenumber') ); |
||||
query.score( peliasQuery.view.address('street') ); |
||||
query.score( peliasQuery.view.address('postcode') ); |
||||
|
||||
// admin components
|
||||
// country_a and region_a are left as matches here because the text-analyzer
|
||||
// can sometimes detect them, in which case a query more specific than a
|
||||
// multi_match is appropriate.
|
||||
query.score( peliasQuery.view.admin('country_a') ); |
||||
query.score( peliasQuery.view.admin('region_a') ); |
||||
query.score( peliasQuery.view.admin_multi_match(adminFields, 'peliasAdmin') ); |
||||
|
||||
// non-scoring hard filters
|
||||
query.filter( peliasQuery.view.boundary_circle ); |
||||
query.filter( peliasQuery.view.boundary_rect ); |
||||
query.filter( peliasQuery.view.sources ); |
||||
query.filter( peliasQuery.view.layers ); |
||||
query.filter( peliasQuery.view.categories ); |
||||
|
||||
// --------------------------------
|
||||
|
||||
/** |
||||
map request variables to query variables for all inputs |
||||
provided by this HTTP request. |
||||
**/ |
||||
function generateQuery( clean ){ |
||||
|
||||
var vs = new peliasQuery.Vars( defaults ); |
||||
|
||||
// input text
|
||||
vs.var( 'input:name', clean.text ); |
||||
|
||||
// sources
|
||||
vs.var( 'sources', clean.sources); |
||||
|
||||
// layers
|
||||
vs.var( 'layers', clean.layers); |
||||
|
||||
// categories
|
||||
if (clean.categories) { |
||||
vs.var('input:categories', clean.categories); |
||||
} |
||||
|
||||
// size
|
||||
if( clean.querySize ) { |
||||
vs.var( 'size', clean.querySize ); |
||||
} |
||||
|
||||
// focus point
|
||||
if( check.number(clean['focus.point.lat']) && |
||||
check.number(clean['focus.point.lon']) ){ |
||||
vs.set({ |
||||
'focus:point:lat': clean['focus.point.lat'], |
||||
'focus:point:lon': clean['focus.point.lon'] |
||||
}); |
||||
} |
||||
|
||||
// boundary rect
|
||||
if( check.number(clean['boundary.rect.min_lat']) && |
||||
check.number(clean['boundary.rect.max_lat']) && |
||||
check.number(clean['boundary.rect.min_lon']) && |
||||
check.number(clean['boundary.rect.max_lon']) ){ |
||||
vs.set({ |
||||
'boundary:rect:top': clean['boundary.rect.max_lat'], |
||||
'boundary:rect:right': clean['boundary.rect.max_lon'], |
||||
'boundary:rect:bottom': clean['boundary.rect.min_lat'], |
||||
'boundary:rect:left': clean['boundary.rect.min_lon'] |
||||
}); |
||||
} |
||||
|
||||
// boundary circle
|
||||
// @todo: change these to the correct request variable names
|
||||
if( check.number(clean['boundary.circle.lat']) && |
||||
check.number(clean['boundary.circle.lon']) ){ |
||||
vs.set({ |
||||
'boundary:circle:lat': clean['boundary.circle.lat'], |
||||
'boundary:circle:lon': clean['boundary.circle.lon'] |
||||
}); |
||||
|
||||
if( check.number(clean['boundary.circle.radius']) ){ |
||||
vs.set({ |
||||
'boundary:circle:radius': Math.round( clean['boundary.circle.radius'] ) + 'km' |
||||
}); |
||||
} |
||||
} |
||||
|
||||
// boundary country
|
||||
if( check.string(clean['boundary.country']) ){ |
||||
vs.set({ |
||||
'boundary:country': clean['boundary.country'] |
||||
}); |
||||
} |
||||
|
||||
// run the address parser
|
||||
if( clean.parsed_text ){ |
||||
textParser( clean.parsed_text, vs ); |
||||
} |
||||
|
||||
return { |
||||
type: 'original', |
||||
body: query.render(vs) |
||||
}; |
||||
} |
||||
|
||||
|
||||
module.exports = generateQuery; |
@ -0,0 +1,99 @@
|
||||
|
||||
var logger = require('pelias-logger').get('api'); |
||||
var placeTypes = require('../helper/placeTypes'); |
||||
|
||||
/* |
||||
This list should only contain admin fields we are comfortable matching in the case |
||||
when we can't identify parts of an address. This shouldn't contain fields like country_a |
||||
or postalcode because we should only try to match those when we're sure that's what they are. |
||||
*/ |
||||
var adminFields = placeTypes.concat([ |
||||
'region_a' |
||||
]); |
||||
|
||||
/** |
||||
@todo: refactor me |
||||
**/ |
||||
|
||||
// all the address parsing logic
|
||||
function addParsedVariablesToQueryVariables( parsed_text, vs ){ |
||||
|
||||
// is it a street address?
|
||||
var isStreetAddress = parsed_text.hasOwnProperty('number') && parsed_text.hasOwnProperty('street'); |
||||
if( isStreetAddress ){ |
||||
vs.var( 'input:name', parsed_text.number + ' ' + parsed_text.street ); |
||||
} |
||||
|
||||
// ?
|
||||
else if( parsed_text.admin_parts ) { |
||||
vs.var( 'input:name', parsed_text.name ); |
||||
} |
||||
|
||||
// ?
|
||||
else { |
||||
logger.warn( 'chaos monkey asks: what happens now?' ); |
||||
logger.warn( parsed_text ); |
||||
try{ throw new Error(); } catch(e){ logger.warn( e.stack ); } // print a stack trace
|
||||
} |
||||
|
||||
// ==== add parsed matches [address components] ====
|
||||
|
||||
// house number
|
||||
if( parsed_text.hasOwnProperty('number') ){ |
||||
vs.var( 'input:housenumber', parsed_text.number ); |
||||
} |
||||
|
||||
// street name
|
||||
if( parsed_text.hasOwnProperty('street') ){ |
||||
vs.var( 'input:street', parsed_text.street ); |
||||
} |
||||
|
||||
// postal code
|
||||
if( parsed_text.hasOwnProperty('postalcode') ){ |
||||
vs.var( 'input:postcode', parsed_text.postalcode ); |
||||
} |
||||
|
||||
// ==== add parsed matches [admin components] ====
|
||||
|
||||
// city
|
||||
if( parsed_text.hasOwnProperty('city') ){ |
||||
vs.var( 'input:county', parsed_text.city ); |
||||
} |
||||
|
||||
// state
|
||||
if( parsed_text.hasOwnProperty('state') ){ |
||||
vs.var( 'input:region_a', parsed_text.state ); |
||||
} |
||||
|
||||
// country
|
||||
if( parsed_text.hasOwnProperty('country') ){ |
||||
vs.var( 'input:country_a', parsed_text.country ); |
||||
} |
||||
|
||||
// ==== deal with the 'leftover' components ====
|
||||
// @todo: clean up this code
|
||||
|
||||
// a concept called 'leftovers' which is just 'admin_parts' /or 'regions'.
|
||||
var leftoversString = ''; |
||||
if( parsed_text.hasOwnProperty('admin_parts') ){ |
||||
leftoversString = parsed_text.admin_parts; |
||||
} |
||||
else if( parsed_text.hasOwnProperty('regions') ){ |
||||
leftoversString = parsed_text.regions.join(' '); |
||||
} |
||||
|
||||
// if we have 'leftovers' then assign them to any fields which
|
||||
// currently don't have a value assigned.
|
||||
if( leftoversString.length ){ |
||||
|
||||
// cycle through fields and set fields which
|
||||
// are still currently unset
|
||||
adminFields.forEach( function( key ){ |
||||
if( !vs.isset( 'input:' + key ) ){ |
||||
vs.var( 'input:' + key, leftoversString ); |
||||
} |
||||
}); |
||||
} |
||||
} |
||||
|
||||
module.exports = addParsedVariablesToQueryVariables; |
@ -0,0 +1,110 @@
|
||||
var check = require('check-types'); |
||||
var parser = require('addressit'); |
||||
var extend = require('extend'); |
||||
var _ = require('lodash'); |
||||
var logger = require('pelias-logger').get('api'); |
||||
|
||||
// validate texts, convert types and apply defaults
|
||||
function sanitize( raw, clean ){ |
||||
|
||||
// error & warning messages
|
||||
var messages = { errors: [], warnings: [] }; |
||||
|
||||
// invalid input 'text'
|
||||
if( !check.nonEmptyString( raw.text ) ){ |
||||
messages.errors.push('invalid param \'text\': text length, must be >0'); |
||||
} |
||||
|
||||
// valid input 'text'
|
||||
else { |
||||
|
||||
// valid text
|
||||
clean.text = raw.text; |
||||
|
||||
// remove anything that may have been parsed before
|
||||
delete clean.parsed_text; |
||||
|
||||
// parse text with query parser
|
||||
var parsed_text = parse(clean.text); |
||||
if (check.assigned(parsed_text)) { |
||||
clean.parsed_text = parsed_text; |
||||
} |
||||
} |
||||
|
||||
return messages; |
||||
} |
||||
|
||||
// export function
|
||||
module.exports = sanitize; |
||||
|
||||
|
||||
|
||||
// this is the addressit functionality from https://github.com/pelias/text-analyzer/blob/master/src/addressItParser.js
|
||||
var DELIM = ','; |
||||
|
||||
function parse(query) { |
||||
var getAdminPartsBySplittingOnDelim = function(queryParts) { |
||||
// naive approach - for admin matching during query time
|
||||
// split 'flatiron, new york, ny' into 'flatiron' and 'new york, ny'
|
||||
|
||||
var address = {}; |
||||
|
||||
if (queryParts.length > 1) { |
||||
address.name = queryParts[0].trim(); |
||||
|
||||
// 1. slice away all parts after the first one
|
||||
// 2. trim spaces from each part just in case
|
||||
// 3. join the parts back together with appropriate delimiter and spacing
|
||||
address.admin_parts = queryParts.slice(1) |
||||
.map(function (part) { return part.trim(); }) |
||||
.join(DELIM + ' '); |
||||
} |
||||
|
||||
return address; |
||||
}; |
||||
|
||||
var getAddressParts = function(query) { |
||||
// perform full address parsing
|
||||
// except on queries so short they obviously can't contain an address
|
||||
if (query.length > 3) { |
||||
return parser( query ); |
||||
} |
||||
}; |
||||
|
||||
var queryParts = query.split(DELIM); |
||||
|
||||
var addressWithAdminParts = getAdminPartsBySplittingOnDelim(queryParts); |
||||
var addressWithAddressParts= getAddressParts(queryParts.join(DELIM + ' ')); |
||||
|
||||
var parsedAddress = extend(addressWithAdminParts, |
||||
addressWithAddressParts); |
||||
|
||||
var address_parts = [ 'name', |
||||
'number', |
||||
'street', |
||||
'city', |
||||
'state', |
||||
'country', |
||||
'postalcode', |
||||
'regions', |
||||
'admin_parts' |
||||
]; |
||||
|
||||
var parsed_text = {}; |
||||
|
||||
address_parts.forEach(function(part){ |
||||
if (parsedAddress[part]) { |
||||
parsed_text[part] = parsedAddress[part]; |
||||
} |
||||
}); |
||||
|
||||
// if all we found was regions, ignore it as it is not enough information to make smarter decisions
|
||||
if (Object.keys(parsed_text).length === 1 && !_.isUndefined(parsed_text.regions)) |
||||
{ |
||||
logger.info('Ignoring address parser output, regions only'); |
||||
return null; |
||||
} |
||||
|
||||
return parsed_text; |
||||
|
||||
} |
@ -0,0 +1,29 @@
|
||||
var sanitizeAll = require('../sanitiser/sanitizeAll'), |
||||
sanitizers = { |
||||
text: require('../sanitiser/_text_addressit') |
||||
}; |
||||
|
||||
var sanitize = function(req, cb) { sanitizeAll(req, sanitizers, cb); }; |
||||
var logger = require('pelias-logger').get('api:controller:search_fallback'); |
||||
var logging = require( '../helper/logging' ); |
||||
|
||||
// middleware
|
||||
module.exports.middleware = function( req, res, next ){ |
||||
// if res.data already has results then don't call the _text_autocomplete sanitiser
|
||||
// this has been put into place for when the libpostal integration way of querying
|
||||
// ES doesn't return anything and we want to fallback to the old logic
|
||||
if (res && res.hasOwnProperty('data') && res.data.length > 0) { |
||||
return next(); |
||||
} |
||||
|
||||
// log the query that caused a fallback since libpostal+new-queries didn't return anything
|
||||
if (req.path === '/v1/search') { |
||||
var queryText = logging.isDNT(req) ? '[text removed]' : req.clean.text; |
||||
logger.info(queryText); |
||||
} |
||||
|
||||
sanitize( req, function( err, clean ){ |
||||
next(); |
||||
}); |
||||
|
||||
}; |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,99 @@
|
||||
|
||||
module.exports = { |
||||
'query': { |
||||
'bool': { |
||||
'must': [ |
||||
{ |
||||
'match': { |
||||
'parent.country_a': { |
||||
'analyzer': 'standard', |
||||
'query': 'ABC' |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
'match': { |
||||
'name.default': { |
||||
'query': 'test', |
||||
'boost': 1, |
||||
'analyzer': 'peliasQueryFullToken' |
||||
} |
||||
} |
||||
} |
||||
], |
||||
'should': [{ |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'boost': 1, |
||||
'slop': 2 |
||||
} |
||||
} |
||||
},{ |
||||
'function_score': { |
||||
'query': { |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'slop': 2, |
||||
'boost': 1 |
||||
} |
||||
} |
||||
}, |
||||
'max_boost': 20, |
||||
'score_mode': 'first', |
||||
'boost_mode': 'replace', |
||||
'functions': [{ |
||||
'field_value_factor': { |
||||
'modifier': 'log1p', |
||||
'field': 'popularity', |
||||
'missing': 1 |
||||
}, |
||||
'weight': 1 |
||||
}] |
||||
} |
||||
},{ |
||||
'function_score': { |
||||
'query': { |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'slop': 2, |
||||
'boost': 1 |
||||
} |
||||
} |
||||
}, |
||||
'max_boost': 20, |
||||
'score_mode': 'first', |
||||
'boost_mode': 'replace', |
||||
'functions': [{ |
||||
'field_value_factor': { |
||||
'modifier': 'log1p', |
||||
'field': 'population', |
||||
'missing': 1 |
||||
}, |
||||
'weight': 2 |
||||
}] |
||||
} |
||||
}], |
||||
'filter': [ |
||||
{ |
||||
'terms': { |
||||
'layer': [ |
||||
'test' |
||||
] |
||||
} |
||||
} |
||||
] |
||||
} |
||||
}, |
||||
'sort': [ '_score' ], |
||||
'size': 10, |
||||
'track_scores': true |
||||
}; |
@ -0,0 +1,805 @@
|
||||
module.exports = { |
||||
'query': { |
||||
'function_score': { |
||||
'query': { |
||||
'filtered': { |
||||
'query': { |
||||
'bool': { |
||||
'should': [ |
||||
{ |
||||
'bool': { |
||||
'_name': 'fallback.venue', |
||||
'must': [ |
||||
{ |
||||
'multi_match': { |
||||
'query': 'query value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'phrase.default' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'neighbourhood value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.neighbourhood', |
||||
'parent.neighbourhood_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'borough value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.borough', |
||||
'parent.borough_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'city value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.locality', |
||||
'parent.locality_a', |
||||
'parent.localadmin', |
||||
'parent.localadmin_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'county value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.county', |
||||
'parent.county_a', |
||||
'parent.macrocounty', |
||||
'parent.macrocounty_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'state value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.region', |
||||
'parent.region_a', |
||||
'parent.macroregion', |
||||
'parent.macroregion_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'country value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.country', |
||||
'parent.country_a', |
||||
'parent.dependency', |
||||
'parent.dependency_a' |
||||
] |
||||
} |
||||
} |
||||
], |
||||
'filter': { |
||||
'term': { |
||||
'layer': 'venue' |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
'bool': { |
||||
'_name': 'fallback.address', |
||||
'must': [ |
||||
{ |
||||
'match_phrase': { |
||||
'address_parts.number': 'number value' |
||||
} |
||||
}, |
||||
{ |
||||
'match_phrase': { |
||||
'address_parts.street': 'street value' |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'neighbourhood value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.neighbourhood', |
||||
'parent.neighbourhood_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'borough value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.borough', |
||||
'parent.borough_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'city value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.locality', |
||||
'parent.locality_a', |
||||
'parent.localadmin', |
||||
'parent.localadmin_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'county value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.county', |
||||
'parent.county_a', |
||||
'parent.macrocounty', |
||||
'parent.macrocounty_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'state value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.region', |
||||
'parent.region_a', |
||||
'parent.macroregion', |
||||
'parent.macroregion_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'country value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.country', |
||||
'parent.country_a', |
||||
'parent.dependency', |
||||
'parent.dependency_a' |
||||
] |
||||
} |
||||
} |
||||
], |
||||
'should': [ |
||||
{ |
||||
'match_phrase': { |
||||
'address_parts.zip': 'postalcode value' |
||||
} |
||||
} |
||||
], |
||||
'filter': { |
||||
'term': { |
||||
'layer': 'address' |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
'bool': { |
||||
'_name': 'fallback.street', |
||||
'must': [ |
||||
{ |
||||
'match_phrase': { |
||||
'address_parts.street': 'street value' |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'neighbourhood value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.neighbourhood', |
||||
'parent.neighbourhood_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'borough value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.borough', |
||||
'parent.borough_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'city value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.locality', |
||||
'parent.locality_a', |
||||
'parent.localadmin', |
||||
'parent.localadmin_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'county value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.county', |
||||
'parent.county_a', |
||||
'parent.macrocounty', |
||||
'parent.macrocounty_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'state value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.region', |
||||
'parent.region_a', |
||||
'parent.macroregion', |
||||
'parent.macroregion_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'country value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.country', |
||||
'parent.country_a', |
||||
'parent.dependency', |
||||
'parent.dependency_a' |
||||
] |
||||
} |
||||
} |
||||
], |
||||
'should': [ |
||||
{ |
||||
'match_phrase': { |
||||
'address_parts.zip': 'postalcode value' |
||||
} |
||||
} |
||||
], |
||||
'filter': { |
||||
'term': { |
||||
'layer': 'street' |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
'bool': { |
||||
'_name': 'fallback.neighbourhood', |
||||
'must': [ |
||||
{ |
||||
'multi_match': { |
||||
'query': 'neighbourhood value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.neighbourhood', |
||||
'parent.neighbourhood_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'borough value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.borough', |
||||
'parent.borough_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'city value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.locality', |
||||
'parent.locality_a', |
||||
'parent.localadmin', |
||||
'parent.localadmin_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'county value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.county', |
||||
'parent.county_a', |
||||
'parent.macrocounty', |
||||
'parent.macrocounty_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'state value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.region', |
||||
'parent.region_a', |
||||
'parent.macroregion', |
||||
'parent.macroregion_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'country value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.country', |
||||
'parent.country_a', |
||||
'parent.dependency', |
||||
'parent.dependency_a' |
||||
] |
||||
} |
||||
} |
||||
], |
||||
'filter': { |
||||
'term': { |
||||
'layer': 'neighbourhood' |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
'bool': { |
||||
'_name': 'fallback.borough', |
||||
'must': [ |
||||
{ |
||||
'multi_match': { |
||||
'query': 'borough value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.borough', |
||||
'parent.borough_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'city value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.locality', |
||||
'parent.locality_a', |
||||
'parent.localadmin', |
||||
'parent.localadmin_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'county value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.county', |
||||
'parent.county_a', |
||||
'parent.macrocounty', |
||||
'parent.macrocounty_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'state value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.region', |
||||
'parent.region_a', |
||||
'parent.macroregion', |
||||
'parent.macroregion_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'country value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.country', |
||||
'parent.country_a', |
||||
'parent.dependency', |
||||
'parent.dependency_a' |
||||
] |
||||
} |
||||
} |
||||
], |
||||
'filter': { |
||||
'term': { |
||||
'layer': 'borough' |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
'bool': { |
||||
'_name': 'fallback.locality', |
||||
'must': [ |
||||
{ |
||||
'multi_match': { |
||||
'query': 'city value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.locality', |
||||
'parent.locality_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'county value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.county', |
||||
'parent.county_a', |
||||
'parent.macrocounty', |
||||
'parent.macrocounty_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'state value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.region', |
||||
'parent.region_a', |
||||
'parent.macroregion', |
||||
'parent.macroregion_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'country value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.country', |
||||
'parent.country_a', |
||||
'parent.dependency', |
||||
'parent.dependency_a' |
||||
] |
||||
} |
||||
} |
||||
], |
||||
'filter': { |
||||
'term': { |
||||
'layer': 'locality' |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
'bool': { |
||||
'_name': 'fallback.localadmin', |
||||
'must': [ |
||||
{ |
||||
'multi_match': { |
||||
'query': 'city value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.localadmin', |
||||
'parent.localadmin_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'county value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.county', |
||||
'parent.county_a', |
||||
'parent.macrocounty', |
||||
'parent.macrocounty_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'state value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.region', |
||||
'parent.region_a', |
||||
'parent.macroregion', |
||||
'parent.macroregion_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'country value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.country', |
||||
'parent.country_a', |
||||
'parent.dependency', |
||||
'parent.dependency_a' |
||||
] |
||||
} |
||||
} |
||||
], |
||||
'filter': { |
||||
'term': { |
||||
'layer': 'localadmin' |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
'bool': { |
||||
'_name': 'fallback.county', |
||||
'must': [ |
||||
{ |
||||
'multi_match': { |
||||
'query': 'county value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.county', |
||||
'parent.county_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'state value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.region', |
||||
'parent.region_a', |
||||
'parent.macroregion', |
||||
'parent.macroregion_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'country value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.country', |
||||
'parent.country_a', |
||||
'parent.dependency', |
||||
'parent.dependency_a' |
||||
] |
||||
} |
||||
} |
||||
], |
||||
'filter': { |
||||
'term': { |
||||
'layer': 'county' |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
'bool': { |
||||
'_name': 'fallback.macrocounty', |
||||
'must': [ |
||||
{ |
||||
'multi_match': { |
||||
'query': 'county value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.macrocounty', |
||||
'parent.macrocounty_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'state value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.region', |
||||
'parent.region_a', |
||||
'parent.macroregion', |
||||
'parent.macroregion_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'country value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.country', |
||||
'parent.country_a', |
||||
'parent.dependency', |
||||
'parent.dependency_a' |
||||
] |
||||
} |
||||
} |
||||
], |
||||
'filter': { |
||||
'term': { |
||||
'layer': 'macrocounty' |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
'bool': { |
||||
'_name': 'fallback.region', |
||||
'must': [ |
||||
{ |
||||
'multi_match': { |
||||
'query': 'state value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.region', |
||||
'parent.region_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'country value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.country', |
||||
'parent.country_a', |
||||
'parent.dependency', |
||||
'parent.dependency_a' |
||||
] |
||||
} |
||||
} |
||||
], |
||||
'filter': { |
||||
'term': { |
||||
'layer': 'region' |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
'bool': { |
||||
'_name': 'fallback.macroregion', |
||||
'must': [ |
||||
{ |
||||
'multi_match': { |
||||
'query': 'state value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.macroregion', |
||||
'parent.macroregion_a' |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
'multi_match': { |
||||
'query': 'country value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.country', |
||||
'parent.country_a', |
||||
'parent.dependency', |
||||
'parent.dependency_a' |
||||
] |
||||
} |
||||
} |
||||
], |
||||
'filter': { |
||||
'term': { |
||||
'layer': 'macroregion' |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
'bool': { |
||||
'_name': 'fallback.dependency', |
||||
'must': [ |
||||
{ |
||||
'multi_match': { |
||||
'query': 'country value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.dependency', |
||||
'parent.dependency_a' |
||||
] |
||||
} |
||||
} |
||||
], |
||||
'filter': { |
||||
'term': { |
||||
'layer': 'dependency' |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
'bool': { |
||||
'_name': 'fallback.country', |
||||
'must': [ |
||||
{ |
||||
'multi_match': { |
||||
'query': 'country value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.country', |
||||
'parent.country_a' |
||||
] |
||||
} |
||||
} |
||||
], |
||||
'filter': { |
||||
'term': { |
||||
'layer': 'country' |
||||
} |
||||
} |
||||
} |
||||
} |
||||
] |
||||
} |
||||
}, |
||||
'filter': { |
||||
'bool': { |
||||
'must': [] |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
'max_boost': 20, |
||||
'functions': [ |
||||
{ |
||||
'field_value_factor': { |
||||
'modifier': 'log1p', |
||||
'field': 'popularity', |
||||
'missing': 1 |
||||
}, |
||||
'weight': 1 |
||||
}, |
||||
{ |
||||
'field_value_factor': { |
||||
'modifier': 'log1p', |
||||
'field': 'population', |
||||
'missing': 1 |
||||
}, |
||||
'weight': 2 |
||||
} |
||||
], |
||||
'score_mode': 'avg', |
||||
'boost_mode': 'multiply' |
||||
} |
||||
}, |
||||
'size': 20, |
||||
'track_scores': true, |
||||
'sort': [ |
||||
{ |
||||
'population': { |
||||
'order': 'desc' |
||||
} |
||||
}, |
||||
{ |
||||
'popularity': { |
||||
'order': 'desc' |
||||
} |
||||
}, |
||||
'_score' |
||||
] |
||||
}; |
@ -0,0 +1,267 @@
|
||||
module.exports = { |
||||
'query': { |
||||
'function_score': { |
||||
'query': { |
||||
'filtered': { |
||||
'query': { |
||||
'bool': { |
||||
'should': [ |
||||
{ |
||||
'bool': { |
||||
'must': [ |
||||
{ |
||||
'multi_match': { |
||||
'query': 'neighbourhood value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.neighbourhood', |
||||
'parent.neighbourhood_a' |
||||
] |
||||
} |
||||
} |
||||
], |
||||
'filter': { |
||||
'term': { |
||||
'layer': 'neighbourhood' |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
'bool': { |
||||
'must': [ |
||||
{ |
||||
'multi_match': { |
||||
'query': 'neighbourhood value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.borough', |
||||
'parent.borough_a' |
||||
] |
||||
} |
||||
} |
||||
], |
||||
'filter': { |
||||
'term': { |
||||
'layer': 'borough' |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
'bool': { |
||||
'must': [ |
||||
{ |
||||
'multi_match': { |
||||
'query': 'neighbourhood value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.locality', |
||||
'parent.locality_a' |
||||
] |
||||
} |
||||
} |
||||
], |
||||
'filter': { |
||||
'term': { |
||||
'layer': 'locality' |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
'bool': { |
||||
'must': [ |
||||
{ |
||||
'multi_match': { |
||||
'query': 'neighbourhood value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.localadmin', |
||||
'parent.localadmin_a' |
||||
] |
||||
} |
||||
} |
||||
], |
||||
'filter': { |
||||
'term': { |
||||
'layer': 'localadmin' |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
'bool': { |
||||
'must': [ |
||||
{ |
||||
'multi_match': { |
||||
'query': 'neighbourhood value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.county', |
||||
'parent.county_a' |
||||
] |
||||
} |
||||
} |
||||
], |
||||
'filter': { |
||||
'term': { |
||||
'layer': 'county' |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
'bool': { |
||||
'must': [ |
||||
{ |
||||
'multi_match': { |
||||
'query': 'neighbourhood value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.macrocounty', |
||||
'parent.macrocounty_a' |
||||
] |
||||
} |
||||
} |
||||
], |
||||
'filter': { |
||||
'term': { |
||||
'layer': 'macrocounty' |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
'bool': { |
||||
'must': [ |
||||
{ |
||||
'multi_match': { |
||||
'query': 'neighbourhood value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.region', |
||||
'parent.region_a' |
||||
] |
||||
} |
||||
} |
||||
], |
||||
'filter': { |
||||
'term': { |
||||
'layer': 'region' |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
'bool': { |
||||
'must': [ |
||||
{ |
||||
'multi_match': { |
||||
'query': 'neighbourhood value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.macroregion', |
||||
'parent.macroregion_a' |
||||
] |
||||
} |
||||
} |
||||
], |
||||
'filter': { |
||||
'term': { |
||||
'layer': 'macroregion' |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
'bool': { |
||||
'must': [ |
||||
{ |
||||
'multi_match': { |
||||
'query': 'neighbourhood value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.dependency', |
||||
'parent.dependency_a' |
||||
] |
||||
} |
||||
} |
||||
], |
||||
'filter': { |
||||
'term': { |
||||
'layer': 'dependency' |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
'bool': { |
||||
'must': [ |
||||
{ |
||||
'multi_match': { |
||||
'query': 'neighbourhood value', |
||||
'type': 'phrase', |
||||
'fields': [ |
||||
'parent.country', |
||||
'parent.country_a' |
||||
] |
||||
} |
||||
} |
||||
], |
||||
'filter': { |
||||
'term': { |
||||
'layer': 'country' |
||||
} |
||||
} |
||||
} |
||||
} |
||||
] |
||||
} |
||||
}, |
||||
'filter': { |
||||
'bool': { |
||||
'must': [] |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
'max_boost': 20, |
||||
'functions': [ |
||||
{ |
||||
'field_value_factor': { |
||||
'modifier': 'log1p', |
||||
'field': 'popularity', |
||||
'missing': 1 |
||||
}, |
||||
'weight': 1 |
||||
}, |
||||
{ |
||||
'field_value_factor': { |
||||
'modifier': 'log1p', |
||||
'field': 'population', |
||||
'missing': 1 |
||||
}, |
||||
'weight': 2 |
||||
} |
||||
], |
||||
'score_mode': 'avg', |
||||
'boost_mode': 'multiply' |
||||
} |
||||
}, |
||||
'size': 20, |
||||
'track_scores': true, |
||||
'sort': [ |
||||
{ |
||||
'population': { |
||||
'order': 'desc' |
||||
} |
||||
}, |
||||
{ |
||||
'popularity': { |
||||
'order': 'desc' |
||||
} |
||||
}, |
||||
'_score' |
||||
] |
||||
}; |
@ -0,0 +1,98 @@
|
||||
|
||||
module.exports = { |
||||
'query': { |
||||
'bool': { |
||||
'must': [{ |
||||
'match': { |
||||
'name.default': { |
||||
'query': 'test', |
||||
'boost': 1, |
||||
'analyzer': 'peliasQueryFullToken' |
||||
} |
||||
} |
||||
}], |
||||
'should': [{ |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'boost': 1, |
||||
'slop': 2 |
||||
} |
||||
} |
||||
},{ |
||||
'function_score': { |
||||
'query': { |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'slop': 2, |
||||
'boost': 1 |
||||
} |
||||
} |
||||
}, |
||||
'max_boost': 20, |
||||
'score_mode': 'first', |
||||
'boost_mode': 'replace', |
||||
'functions': [{ |
||||
'field_value_factor': { |
||||
'modifier': 'log1p', |
||||
'field': 'popularity', |
||||
'missing': 1 |
||||
}, |
||||
'weight': 1 |
||||
}] |
||||
} |
||||
},{ |
||||
'function_score': { |
||||
'query': { |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'slop': 2, |
||||
'boost': 1 |
||||
} |
||||
} |
||||
}, |
||||
'max_boost': 20, |
||||
'score_mode': 'first', |
||||
'boost_mode': 'replace', |
||||
'functions': [{ |
||||
'field_value_factor': { |
||||
'modifier': 'log1p', |
||||
'field': 'population', |
||||
'missing': 1 |
||||
}, |
||||
'weight': 2 |
||||
}] |
||||
} |
||||
}], |
||||
'filter': [{ |
||||
'geo_bounding_box': { |
||||
'type': 'indexed', |
||||
'center_point': { |
||||
'top': 11.51, |
||||
'right': -61.84, |
||||
'bottom': 47.47, |
||||
'left': -103.16 |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
'terms': { |
||||
'layer': [ |
||||
'test' |
||||
] |
||||
} |
||||
}] |
||||
} |
||||
}, |
||||
'sort': [ '_score' ], |
||||
'size': 10, |
||||
'track_scores': true |
||||
}; |
@ -0,0 +1,128 @@
|
||||
|
||||
module.exports = { |
||||
'query': { |
||||
'bool': { |
||||
'must': [{ |
||||
'match': { |
||||
'name.default': { |
||||
'query': 'test', |
||||
'boost': 1, |
||||
'analyzer': 'peliasQueryFullToken' |
||||
} |
||||
} |
||||
}], |
||||
'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': 29.49136, |
||||
'lon': -82.50622 |
||||
}, |
||||
'offset': '0km', |
||||
'scale': '50km', |
||||
'decay': 0.5 |
||||
} |
||||
}, |
||||
'weight': 2 |
||||
}], |
||||
'score_mode': 'avg', |
||||
'boost_mode': 'replace' |
||||
} |
||||
},{ |
||||
'function_score': { |
||||
'query': { |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'slop': 2, |
||||
'boost': 1 |
||||
} |
||||
} |
||||
}, |
||||
'max_boost': 20, |
||||
'score_mode': 'first', |
||||
'boost_mode': 'replace', |
||||
'functions': [{ |
||||
'field_value_factor': { |
||||
'modifier': 'log1p', |
||||
'field': 'popularity', |
||||
'missing': 1 |
||||
}, |
||||
'weight': 1 |
||||
}] |
||||
} |
||||
},{ |
||||
'function_score': { |
||||
'query': { |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'slop': 2, |
||||
'boost': 1 |
||||
} |
||||
} |
||||
}, |
||||
'max_boost': 20, |
||||
'score_mode': 'first', |
||||
'boost_mode': 'replace', |
||||
'functions': [{ |
||||
'field_value_factor': { |
||||
'modifier': 'log1p', |
||||
'field': 'population', |
||||
'missing': 1 |
||||
}, |
||||
'weight': 2 |
||||
}] |
||||
} |
||||
}], |
||||
'filter': [{ |
||||
'geo_bounding_box': { |
||||
'type': 'indexed', |
||||
'center_point': { |
||||
'top': 11.51, |
||||
'right': -61.84, |
||||
'bottom': 47.47, |
||||
'left': -103.16 |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
'terms': { |
||||
'layer': [ |
||||
'test' |
||||
] |
||||
} |
||||
}] |
||||
} |
||||
}, |
||||
'sort': [ '_score' ], |
||||
'size': 10, |
||||
'track_scores': true |
||||
}; |
@ -0,0 +1,117 @@
|
||||
|
||||
module.exports = { |
||||
'query': { |
||||
'bool': { |
||||
'must': [{ |
||||
'match': { |
||||
'name.default': { |
||||
'query': 'test', |
||||
'boost': 1, |
||||
'analyzer': 'peliasQueryFullToken' |
||||
} |
||||
} |
||||
}], |
||||
'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': 0, |
||||
'lon': 0 |
||||
}, |
||||
'offset': '0km', |
||||
'scale': '50km', |
||||
'decay': 0.5 |
||||
} |
||||
}, |
||||
'weight': 2 |
||||
}], |
||||
'score_mode': 'avg', |
||||
'boost_mode': 'replace' |
||||
} |
||||
},{ |
||||
'function_score': { |
||||
'query': { |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'slop': 2, |
||||
'boost': 1 |
||||
} |
||||
} |
||||
}, |
||||
'max_boost': 20, |
||||
'score_mode': 'first', |
||||
'boost_mode': 'replace', |
||||
'functions': [{ |
||||
'field_value_factor': { |
||||
'modifier': 'log1p', |
||||
'field': 'popularity', |
||||
'missing': 1 |
||||
}, |
||||
'weight': 1 |
||||
}] |
||||
} |
||||
},{ |
||||
'function_score': { |
||||
'query': { |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'slop': 2, |
||||
'boost': 1 |
||||
} |
||||
} |
||||
}, |
||||
'max_boost': 20, |
||||
'score_mode': 'first', |
||||
'boost_mode': 'replace', |
||||
'functions': [{ |
||||
'field_value_factor': { |
||||
'modifier': 'log1p', |
||||
'field': 'population', |
||||
'missing': 1 |
||||
}, |
||||
'weight': 2 |
||||
}] |
||||
} |
||||
}], |
||||
'filter':[{ |
||||
'terms': { |
||||
'layer': [ |
||||
'test' |
||||
] |
||||
} |
||||
}] |
||||
} |
||||
}, |
||||
'sort': [ '_score' ], |
||||
'size': 10, |
||||
'track_scores': true |
||||
}; |
@ -0,0 +1,119 @@
|
||||
|
||||
module.exports = { |
||||
'query': { |
||||
'bool': { |
||||
'must': [{ |
||||
'match': { |
||||
'name.default': { |
||||
'query': 'test', |
||||
'boost': 1, |
||||
'analyzer': 'peliasQueryFullToken' |
||||
} |
||||
} |
||||
}], |
||||
'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': 29.49136, |
||||
'lon': -82.50622 |
||||
}, |
||||
'offset': '0km', |
||||
'scale': '50km', |
||||
'decay': 0.5 |
||||
} |
||||
}, |
||||
'weight': 2 |
||||
}], |
||||
'score_mode': 'avg', |
||||
'boost_mode': 'replace' |
||||
} |
||||
},{ |
||||
'function_score': { |
||||
'query': { |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'slop': 2, |
||||
'boost': 1 |
||||
} |
||||
} |
||||
}, |
||||
'max_boost': 20, |
||||
'score_mode': 'first', |
||||
'boost_mode': 'replace', |
||||
'functions': [{ |
||||
'field_value_factor': { |
||||
'modifier': 'log1p', |
||||
'field': 'popularity', |
||||
'missing': 1 |
||||
}, |
||||
'weight': 1 |
||||
}] |
||||
} |
||||
},{ |
||||
'function_score': { |
||||
'query': { |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'slop': 2, |
||||
'boost': 1 |
||||
} |
||||
} |
||||
}, |
||||
'max_boost': 20, |
||||
'score_mode': 'first', |
||||
'boost_mode': 'replace', |
||||
'functions': [{ |
||||
'field_value_factor': { |
||||
'modifier': 'log1p', |
||||
'field': 'population', |
||||
'missing': 1 |
||||
}, |
||||
'weight': 2 |
||||
}] |
||||
} |
||||
}], |
||||
'filter': [ |
||||
{ |
||||
'terms': { |
||||
'layer': [ |
||||
'test' |
||||
] |
||||
} |
||||
} |
||||
] |
||||
} |
||||
}, |
||||
'sort': [ '_score' ], |
||||
'size': 10, |
||||
'track_scores': true |
||||
}; |
@ -1,89 +1,83 @@
|
||||
|
||||
module.exports = { |
||||
'query': { |
||||
'bool': { |
||||
'must': [{ |
||||
'match': { |
||||
'name.default': { |
||||
'query': 'test', |
||||
'boost': 1, |
||||
'analyzer': 'peliasQueryFullToken' |
||||
} |
||||
} |
||||
}], |
||||
'should': [{ |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'boost': 1, |
||||
'slop': 2 |
||||
} |
||||
} |
||||
},{ |
||||
'function_score': { |
||||
'query': { |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'slop': 2, |
||||
'boost': 1 |
||||
'filtered': { |
||||
'query': { |
||||
'bool': { |
||||
'should': [ |
||||
{ |
||||
'bool': { |
||||
'_name': 'fallback.street', |
||||
'must': [ |
||||
{ |
||||
'match_phrase': { |
||||
'address_parts.street': 'street value' |
||||
} |
||||
} |
||||
], |
||||
'should': [], |
||||
'filter': { |
||||
'term': { |
||||
'layer': 'street' |
||||
} |
||||
} |
||||
} |
||||
} |
||||
] |
||||
} |
||||
}, |
||||
'filter': { |
||||
'bool': { |
||||
'must': [ |
||||
{ |
||||
'terms': { |
||||
'layer': [ |
||||
'test' |
||||
] |
||||
} |
||||
} |
||||
] |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
'max_boost': 20, |
||||
'score_mode': 'first', |
||||
'boost_mode': 'replace', |
||||
'functions': [{ |
||||
'functions': [ |
||||
{ |
||||
'field_value_factor': { |
||||
'modifier': 'log1p', |
||||
'field': 'popularity', |
||||
'missing': 1 |
||||
}, |
||||
'weight': 1 |
||||
}] |
||||
} |
||||
},{ |
||||
'function_score': { |
||||
'query': { |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'slop': 2, |
||||
'boost': 1 |
||||
} |
||||
} |
||||
}, |
||||
'max_boost': 20, |
||||
'score_mode': 'first', |
||||
'boost_mode': 'replace', |
||||
'functions': [{ |
||||
{ |
||||
'field_value_factor': { |
||||
'modifier': 'log1p', |
||||
'field': 'population', |
||||
'missing': 1 |
||||
}, |
||||
'weight': 2 |
||||
}] |
||||
} |
||||
}], |
||||
'filter': [ |
||||
{ |
||||
'terms': { |
||||
'layer': [ |
||||
'test' |
||||
] |
||||
], |
||||
'score_mode': 'avg', |
||||
'boost_mode': 'multiply' |
||||
} |
||||
}, |
||||
'size': 10, |
||||
'track_scores': true, |
||||
'sort': [ |
||||
{ |
||||
'population': { |
||||
'order': 'desc' |
||||
} |
||||
] |
||||
}, |
||||
{ |
||||
'popularity': { |
||||
'order': 'desc' |
||||
} |
||||
}, |
||||
'sort': [ '_score' ], |
||||
'size': 10, |
||||
'track_scores': true |
||||
'_score' |
||||
] |
||||
}; |
||||
|
@ -0,0 +1,89 @@
|
||||
|
||||
module.exports = { |
||||
'query': { |
||||
'bool': { |
||||
'must': [{ |
||||
'match': { |
||||
'name.default': { |
||||
'query': 'test', |
||||
'boost': 1, |
||||
'analyzer': 'peliasQueryFullToken' |
||||
} |
||||
} |
||||
}], |
||||
'should': [{ |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'boost': 1, |
||||
'slop': 2 |
||||
} |
||||
} |
||||
},{ |
||||
'function_score': { |
||||
'query': { |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'slop': 2, |
||||
'boost': 1 |
||||
} |
||||
} |
||||
}, |
||||
'max_boost': 20, |
||||
'score_mode': 'first', |
||||
'boost_mode': 'replace', |
||||
'functions': [{ |
||||
'field_value_factor': { |
||||
'modifier': 'log1p', |
||||
'field': 'popularity', |
||||
'missing': 1 |
||||
}, |
||||
'weight': 1 |
||||
}] |
||||
} |
||||
},{ |
||||
'function_score': { |
||||
'query': { |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'slop': 2, |
||||
'boost': 1 |
||||
} |
||||
} |
||||
}, |
||||
'max_boost': 20, |
||||
'score_mode': 'first', |
||||
'boost_mode': 'replace', |
||||
'functions': [{ |
||||
'field_value_factor': { |
||||
'modifier': 'log1p', |
||||
'field': 'population', |
||||
'missing': 1 |
||||
}, |
||||
'weight': 2 |
||||
}] |
||||
} |
||||
}], |
||||
'filter': [ |
||||
{ |
||||
'terms': { |
||||
'layer': [ |
||||
'test' |
||||
] |
||||
} |
||||
} |
||||
] |
||||
} |
||||
}, |
||||
'sort': [ '_score' ], |
||||
'size': 10, |
||||
'track_scores': true |
||||
}; |
@ -1,86 +1,84 @@
|
||||
module.exports = { |
||||
'query': { |
||||
'bool': { |
||||
'must': [{ |
||||
'match': { |
||||
'name.default': { |
||||
'query': 'test', |
||||
'boost': 1, |
||||
'analyzer': 'peliasQueryFullToken' |
||||
} |
||||
} |
||||
}], |
||||
'should': [{ |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'boost': 1, |
||||
'slop': 2 |
||||
} |
||||
} |
||||
}, { |
||||
'function_score': { |
||||
'query': { |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'slop': 2, |
||||
'boost': 1 |
||||
'filtered': { |
||||
'query': { |
||||
'bool': { |
||||
'should': [ |
||||
{ |
||||
'bool': { |
||||
'_name': 'fallback.street', |
||||
'must': [ |
||||
{ |
||||
'match_phrase': { |
||||
'address_parts.street': 'street value' |
||||
} |
||||
} |
||||
], |
||||
'should': [], |
||||
'filter': { |
||||
'term': { |
||||
'layer': 'street' |
||||
} |
||||
} |
||||
} |
||||
} |
||||
] |
||||
} |
||||
}, |
||||
'filter': { |
||||
'bool': { |
||||
'must': [ |
||||
{ |
||||
'terms': { |
||||
'category': [ |
||||
'retail', |
||||
'food' |
||||
] |
||||
} |
||||
} |
||||
] |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
'max_boost': 20, |
||||
'score_mode': 'first', |
||||
'boost_mode': 'replace', |
||||
'functions': [{ |
||||
'functions': [ |
||||
{ |
||||
'field_value_factor': { |
||||
'modifier': 'log1p', |
||||
'field': 'popularity', |
||||
'missing': 1 |
||||
}, |
||||
'weight': 1 |
||||
}] |
||||
} |
||||
}, { |
||||
'function_score': { |
||||
'query': { |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'slop': 2, |
||||
'boost': 1 |
||||
} |
||||
} |
||||
}, |
||||
'max_boost': 20, |
||||
'score_mode': 'first', |
||||
'boost_mode': 'replace', |
||||
'functions': [{ |
||||
{ |
||||
'field_value_factor': { |
||||
'modifier': 'log1p', |
||||
'field': 'population', |
||||
'missing': 1 |
||||
}, |
||||
'weight': 2 |
||||
}] |
||||
} |
||||
}], |
||||
'filter': [{ |
||||
'terms': { |
||||
'category': ['retail', 'food'] |
||||
} |
||||
}] |
||||
], |
||||
'score_mode': 'avg', |
||||
'boost_mode': 'multiply' |
||||
} |
||||
}, |
||||
'size': 20, |
||||
'track_scores': true, |
||||
'sort': [ |
||||
{ |
||||
'population': { |
||||
'order': 'desc' |
||||
} |
||||
}, |
||||
{ |
||||
'popularity': { |
||||
'order': 'desc' |
||||
} |
||||
}, |
||||
'_score' |
||||
] |
||||
}; |
||||
|
@ -0,0 +1,86 @@
|
||||
module.exports = { |
||||
'query': { |
||||
'bool': { |
||||
'must': [{ |
||||
'match': { |
||||
'name.default': { |
||||
'query': 'test', |
||||
'boost': 1, |
||||
'analyzer': 'peliasQueryFullToken' |
||||
} |
||||
} |
||||
}], |
||||
'should': [{ |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'boost': 1, |
||||
'slop': 2 |
||||
} |
||||
} |
||||
}, { |
||||
'function_score': { |
||||
'query': { |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'slop': 2, |
||||
'boost': 1 |
||||
} |
||||
} |
||||
}, |
||||
'max_boost': 20, |
||||
'score_mode': 'first', |
||||
'boost_mode': 'replace', |
||||
'functions': [{ |
||||
'field_value_factor': { |
||||
'modifier': 'log1p', |
||||
'field': 'popularity', |
||||
'missing': 1 |
||||
}, |
||||
'weight': 1 |
||||
}] |
||||
} |
||||
}, { |
||||
'function_score': { |
||||
'query': { |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'slop': 2, |
||||
'boost': 1 |
||||
} |
||||
} |
||||
}, |
||||
'max_boost': 20, |
||||
'score_mode': 'first', |
||||
'boost_mode': 'replace', |
||||
'functions': [{ |
||||
'field_value_factor': { |
||||
'modifier': 'log1p', |
||||
'field': 'population', |
||||
'missing': 1 |
||||
}, |
||||
'weight': 2 |
||||
}] |
||||
} |
||||
}], |
||||
'filter': [{ |
||||
'terms': { |
||||
'category': ['retail', 'food'] |
||||
} |
||||
}] |
||||
} |
||||
}, |
||||
'size': 20, |
||||
'track_scores': true, |
||||
'sort': [ |
||||
'_score' |
||||
] |
||||
}; |
@ -1,85 +1,83 @@
|
||||
|
||||
module.exports = { |
||||
'query': { |
||||
'bool': { |
||||
'must': [{ |
||||
'match': { |
||||
'name.default': { |
||||
'query': 'test', |
||||
'boost': 1, |
||||
'analyzer': 'peliasQueryFullToken' |
||||
} |
||||
} |
||||
}], |
||||
'should': [{ |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'boost': 1, |
||||
'slop': 2 |
||||
} |
||||
} |
||||
},{ |
||||
'function_score': { |
||||
'query': { |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'slop': 2, |
||||
'boost': 1 |
||||
'filtered': { |
||||
'query': { |
||||
'bool': { |
||||
'should': [ |
||||
{ |
||||
'bool': { |
||||
'_name': 'fallback.street', |
||||
'must': [ |
||||
{ |
||||
'match_phrase': { |
||||
'address_parts.street': 'street value' |
||||
} |
||||
} |
||||
], |
||||
'should': [], |
||||
'filter': { |
||||
'term': { |
||||
'layer': 'street' |
||||
} |
||||
} |
||||
} |
||||
} |
||||
] |
||||
} |
||||
}, |
||||
'filter': { |
||||
'bool': { |
||||
'must': [ |
||||
{ |
||||
'terms': { |
||||
'source': [ |
||||
'test_source' |
||||
] |
||||
} |
||||
} |
||||
] |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
'max_boost': 20, |
||||
'score_mode': 'first', |
||||
'boost_mode': 'replace', |
||||
'functions': [{ |
||||
'functions': [ |
||||
{ |
||||
'field_value_factor': { |
||||
'modifier': 'log1p', |
||||
'field': 'popularity', |
||||
'missing': 1 |
||||
}, |
||||
'weight': 1 |
||||
}] |
||||
} |
||||
},{ |
||||
'function_score': { |
||||
'query': { |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'slop': 2, |
||||
'boost': 1 |
||||
} |
||||
} |
||||
}, |
||||
'max_boost': 20, |
||||
'score_mode': 'first', |
||||
'boost_mode': 'replace', |
||||
'functions': [{ |
||||
{ |
||||
'field_value_factor': { |
||||
'modifier': 'log1p', |
||||
'field': 'population', |
||||
'missing': 1 |
||||
}, |
||||
'weight': 2 |
||||
}] |
||||
} |
||||
}], |
||||
'filter': [{ |
||||
'terms': { |
||||
'source': ['test_source'] |
||||
} |
||||
}] |
||||
], |
||||
'score_mode': 'avg', |
||||
'boost_mode': 'multiply' |
||||
} |
||||
}, |
||||
'sort': [ '_score' ], |
||||
'size': 20, |
||||
'track_scores': true |
||||
'track_scores': true, |
||||
'sort': [ |
||||
{ |
||||
'population': { |
||||
'order': 'desc' |
||||
} |
||||
}, |
||||
{ |
||||
'popularity': { |
||||
'order': 'desc' |
||||
} |
||||
}, |
||||
'_score' |
||||
] |
||||
}; |
||||
|
@ -0,0 +1,85 @@
|
||||
|
||||
module.exports = { |
||||
'query': { |
||||
'bool': { |
||||
'must': [{ |
||||
'match': { |
||||
'name.default': { |
||||
'query': 'test', |
||||
'boost': 1, |
||||
'analyzer': 'peliasQueryFullToken' |
||||
} |
||||
} |
||||
}], |
||||
'should': [{ |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'boost': 1, |
||||
'slop': 2 |
||||
} |
||||
} |
||||
},{ |
||||
'function_score': { |
||||
'query': { |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'slop': 2, |
||||
'boost': 1 |
||||
} |
||||
} |
||||
}, |
||||
'max_boost': 20, |
||||
'score_mode': 'first', |
||||
'boost_mode': 'replace', |
||||
'functions': [{ |
||||
'field_value_factor': { |
||||
'modifier': 'log1p', |
||||
'field': 'popularity', |
||||
'missing': 1 |
||||
}, |
||||
'weight': 1 |
||||
}] |
||||
} |
||||
},{ |
||||
'function_score': { |
||||
'query': { |
||||
'match': { |
||||
'phrase.default': { |
||||
'query': 'test', |
||||
'analyzer': 'peliasPhrase', |
||||
'type': 'phrase', |
||||
'slop': 2, |
||||
'boost': 1 |
||||
} |
||||
} |
||||
}, |
||||
'max_boost': 20, |
||||
'score_mode': 'first', |
||||
'boost_mode': 'replace', |
||||
'functions': [{ |
||||
'field_value_factor': { |
||||
'modifier': 'log1p', |
||||
'field': 'population', |
||||
'missing': 1 |
||||
}, |
||||
'weight': 2 |
||||
}] |
||||
} |
||||
}], |
||||
'filter': [{ |
||||
'terms': { |
||||
'source': ['test_source'] |
||||
} |
||||
}] |
||||
} |
||||
}, |
||||
'sort': [ '_score' ], |
||||
'size': 20, |
||||
'track_scores': true |
||||
}; |
@ -0,0 +1,180 @@
|
||||
var isDifferent= require('../../../helper/diffPlaces').isDifferent; |
||||
|
||||
module.exports.tests = {}; |
||||
|
||||
module.exports.tests.dedupe = function(test, common) { |
||||
|
||||
test('match same object', function(t) { |
||||
var item1 = { |
||||
'parent': { |
||||
'country': [ 'United States' ], |
||||
'county': [ 'Otsego County' ], |
||||
'region_a': [ 'NY' ], |
||||
'localadmin': [ 'Cherry Valley' ], |
||||
'county_id': [ '102082399' ], |
||||
'localadmin_id': [ '404522887' ], |
||||
'country_a': [ 'USA' ], |
||||
'region_id': [ '85688543' ], |
||||
'locality': [ 'Cherry Valley' ], |
||||
'locality_id': [ '85978799' ], |
||||
'region': [ 'New York' ], |
||||
'country_id': [ '85633793' ] |
||||
}, |
||||
'name': { |
||||
'default': '1 Main Street' |
||||
}, |
||||
'address_parts': { |
||||
'number': '1', |
||||
'street': 'Main Street' |
||||
}, |
||||
'layer': 'address' |
||||
}; |
||||
|
||||
t.false(isDifferent(item1, item1), 'should be the same'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('catch diff layers', function(t) { |
||||
var item1 = { 'layer': 'address' }; |
||||
var item2 = { 'layer': 'venue' }; |
||||
|
||||
t.true(isDifferent(item1, item2), 'should be different'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('catch diff parent', function(t) { |
||||
var item1 = { |
||||
'layer': 'same', |
||||
'parent': { |
||||
'country_id': '12345' |
||||
} |
||||
}; |
||||
var item2 = { |
||||
'layer': 'same', |
||||
'parent': { |
||||
'country_id': '54321' |
||||
} |
||||
}; |
||||
|
||||
t.true(isDifferent(item1, item2), 'should be different'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('catch diff name', function(t) { |
||||
var item1 = { |
||||
'name': { |
||||
'default': '1 Main St' |
||||
} |
||||
}; |
||||
var item2 = { |
||||
'name': { |
||||
'default': '1 Broad St' |
||||
} |
||||
}; |
||||
|
||||
t.true(isDifferent(item1, item2), 'should be different'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('match diff capitalization in name', function(t) { |
||||
var item1 = { |
||||
'name': { |
||||
'default': '1 MAIN ST' |
||||
} |
||||
}; |
||||
var item2 = { |
||||
'name': { |
||||
'default': '1 Main St' |
||||
} |
||||
}; |
||||
|
||||
t.false(isDifferent(item1, item2), 'should be the same'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('do not handle expansions', function(t) { |
||||
// we currently don't handle expansions and abbreviations and
|
||||
// this is a test waiting to be updated as soon as we fix it
|
||||
|
||||
var item1 = { |
||||
'name': { |
||||
'default': '1 Main Street' |
||||
} |
||||
}; |
||||
var item2 = { |
||||
'name': { |
||||
'default': '1 Main St' |
||||
} |
||||
}; |
||||
|
||||
t.true(isDifferent(item1, item2), 'should be different'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('missing names in other langs should not be a diff', function(t) { |
||||
var item1 = { |
||||
'name': { |
||||
'default': 'Moscow', |
||||
'rus': 'Москва' |
||||
} |
||||
}; |
||||
var item2 = { |
||||
'name': { |
||||
'default': 'Moscow' |
||||
} |
||||
}; |
||||
|
||||
t.false(isDifferent(item1, item2), 'should be the same'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('catch diff address', function(t) { |
||||
var item1 = { |
||||
'address_parts': { |
||||
'number': '1', |
||||
'street': 'Main Street', |
||||
'zip': '90210' |
||||
} |
||||
}; |
||||
var item2 = { |
||||
'address_parts': { |
||||
'number': '2', |
||||
'street': 'Main Street', |
||||
'zip': '90210' |
||||
} |
||||
}; |
||||
|
||||
t.true(isDifferent(item1, item2), 'should be different'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('catch diff address', function(t) { |
||||
var item1 = { |
||||
'address_parts': { |
||||
'number': '1', |
||||
'street': 'Main Street', |
||||
'zip': '90210' |
||||
} |
||||
}; |
||||
var item2 = { |
||||
'address_parts': { |
||||
'number': '1', |
||||
'street': 'Main Street' |
||||
} |
||||
}; |
||||
|
||||
t.false(isDifferent(item1, item2), 'should be the same'); |
||||
t.end(); |
||||
}); |
||||
}; |
||||
|
||||
module.exports.all = function (tape, common) { |
||||
|
||||
function test(name, testFunction) { |
||||
return tape('[helper] diffPlaces: ' + name, testFunction); |
||||
} |
||||
|
||||
for( var testCase in module.exports.tests ){ |
||||
module.exports.tests[testCase](test, common); |
||||
} |
||||
}; |
@ -0,0 +1,90 @@
|
||||
var accuracy = require('../../../middleware/accuracy')(); |
||||
|
||||
module.exports.tests = {}; |
||||
|
||||
module.exports.tests.accuracy = function(test, common) { |
||||
|
||||
test('empty res and req should not throw exception', function(t) { |
||||
function testIt() { |
||||
accuracy({}, {}, function() {}); |
||||
} |
||||
|
||||
t.doesNotThrow(testIt, 'an exception should not have been thrown'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('res.results without parsed_text should not throw exception', function(t) { |
||||
var res = { |
||||
data: [{ |
||||
layer: 'venue' |
||||
}] |
||||
}; |
||||
|
||||
accuracy({}, res, function() { |
||||
t.equal(res.data[0].accuracy, 'point', 'accuracy was set'); |
||||
t.end(); |
||||
}); |
||||
}); |
||||
|
||||
test('venue should have accuracy set to point', function(t) { |
||||
var res = { |
||||
data: [{ |
||||
layer: 'venue' |
||||
}] |
||||
}; |
||||
|
||||
accuracy({}, res, function() { |
||||
t.equal(res.data[0].accuracy, 'point', 'accuracy was set'); |
||||
t.end(); |
||||
}); |
||||
}); |
||||
|
||||
test('address should have accuracy set to point', function(t) { |
||||
var res = { |
||||
data: [{ |
||||
layer: 'address' |
||||
}] |
||||
}; |
||||
|
||||
accuracy({}, res, function() { |
||||
t.equal(res.data[0].accuracy, 'point', 'accuracy was set'); |
||||
t.end(); |
||||
}); |
||||
}); |
||||
|
||||
test('region should have accuracy set to centroid', function(t) { |
||||
var res = { |
||||
data: [{ |
||||
layer: 'region' |
||||
}] |
||||
}; |
||||
|
||||
accuracy({}, res, function() { |
||||
t.equal(res.data[0].accuracy, 'centroid', 'accuracy was set'); |
||||
t.end(); |
||||
}); |
||||
}); |
||||
|
||||
test('street should have accuracy set to centroid', function(t) { |
||||
var res = { |
||||
data: [{ |
||||
layer: 'street' |
||||
}] |
||||
}; |
||||
|
||||
accuracy({}, res, function() { |
||||
t.equal(res.data[0].accuracy, 'centroid', 'accuracy was set'); |
||||
t.end(); |
||||
}); |
||||
}); |
||||
}; |
||||
|
||||
module.exports.all = function (tape, common) { |
||||
function test(name, testFunction) { |
||||
return tape('[middleware] confidenceScore: ' + name, testFunction); |
||||
} |
||||
|
||||
for( var testCase in module.exports.tests ){ |
||||
module.exports.tests[testCase](test, common); |
||||
} |
||||
}; |
@ -0,0 +1,250 @@
|
||||
var confidenceScore = require('../../../middleware/confidenceScoreFallback')(); |
||||
|
||||
module.exports.tests = {}; |
||||
|
||||
module.exports.tests.confidenceScore = function(test, common) { |
||||
|
||||
test('empty res and req should not throw exception', function(t) { |
||||
function testIt() { |
||||
confidenceScore({}, {}, function() {}); |
||||
} |
||||
|
||||
t.doesNotThrow(testIt, 'an exception should not have been thrown'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('res.results without parsed_text should not throw exception', function(t) { |
||||
var req = {}; |
||||
var res = { |
||||
data: [{ |
||||
name: 'foo' |
||||
}], |
||||
meta: [10] |
||||
}; |
||||
|
||||
function testIt() { |
||||
confidenceScore(req, res, function() {}); |
||||
} |
||||
|
||||
t.doesNotThrow(testIt, 'an exception should not have been thrown'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('hit without address should not error', function(t) { |
||||
var req = { |
||||
clean: { |
||||
text: 'test name3', |
||||
parsed_text: { |
||||
postalcode: 12345 |
||||
} |
||||
} |
||||
}; |
||||
var res = { |
||||
data: [{ |
||||
name: { |
||||
default: 'foo' |
||||
} |
||||
}], |
||||
meta: { |
||||
scores: [10], |
||||
query_type: 'original' |
||||
} |
||||
}; |
||||
|
||||
function testIt() { |
||||
confidenceScore(req, res, function() {}); |
||||
} |
||||
|
||||
t.doesNotThrow(testIt, 'an exception should not have been thrown with no address'); |
||||
t.end(); |
||||
}); |
||||
|
||||
|
||||
test('res.results without parsed_text should not throw exception', function(t) { |
||||
var req = { |
||||
clean: { text: 'test name1' } |
||||
}; |
||||
var res = { |
||||
data: [{ |
||||
_score: 10, |
||||
found: true, |
||||
value: 1, |
||||
center_point: { lat: 100.1, lon: -50.5 }, |
||||
name: { default: 'test name1' }, |
||||
parent: { |
||||
country: ['country1'], |
||||
region: ['state1'], |
||||
county: ['city1'] |
||||
} |
||||
}, { |
||||
_score: 20, |
||||
value: 2, |
||||
center_point: { lat: 100.2, lon: -51.5 }, |
||||
name: { default: 'test name2' }, |
||||
parent: { |
||||
country: ['country2'], |
||||
region: ['state2'], |
||||
county: ['city2'] |
||||
} |
||||
}], |
||||
meta: { |
||||
scores: [10], |
||||
query_type: 'fallback' |
||||
} |
||||
}; |
||||
|
||||
confidenceScore(req, res, function() {}); |
||||
t.equal(res.data[0].confidence, 0.1, 'score was set'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('no fallback addresses should have max score', function(t) { |
||||
var req = { |
||||
clean: { |
||||
text: '123 Main St, City, NM', |
||||
parsed_text: { |
||||
number: 123, |
||||
street: 'Main St', |
||||
state: 'NM' |
||||
} |
||||
} |
||||
}; |
||||
var res = { |
||||
data: [{ |
||||
_score: 10, |
||||
found: true, |
||||
value: 1, |
||||
layer: 'address', |
||||
center_point: { lat: 100.1, lon: -50.5 }, |
||||
name: { default: 'test name1' }, |
||||
parent: { |
||||
country: ['country1'], |
||||
region: ['region1'], |
||||
county: ['city1'] |
||||
} |
||||
}], |
||||
meta: { |
||||
scores: [10], |
||||
query_type: 'fallback' |
||||
} |
||||
}; |
||||
|
||||
confidenceScore(req, res, function() {}); |
||||
t.equal(res.data[0].confidence, 1.0, 'max score was set'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('no fallback street query should have max score', function(t) { |
||||
var req = { |
||||
clean: { |
||||
text: 'Main St, City, NM', |
||||
parsed_text: { |
||||
street: 'Main St', |
||||
state: 'NM' |
||||
} |
||||
} |
||||
}; |
||||
var res = { |
||||
data: [{ |
||||
_score: 10, |
||||
found: true, |
||||
value: 1, |
||||
layer: 'street', |
||||
center_point: { lat: 100.1, lon: -50.5 }, |
||||
name: { default: 'test name1' }, |
||||
parent: { |
||||
country: ['country1'], |
||||
region: ['region1'], |
||||
county: ['city1'] |
||||
} |
||||
}], |
||||
meta: { |
||||
scores: [10], |
||||
query_type: 'fallback' |
||||
} |
||||
}; |
||||
|
||||
confidenceScore(req, res, function() {}); |
||||
t.equal(res.data[0].confidence, 1.0, 'max score was set'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('fallback to locality should have score deduction', function(t) { |
||||
var req = { |
||||
clean: { |
||||
text: '123 Main St, City, NM', |
||||
parsed_text: { |
||||
number: 123, |
||||
street: 'Main St', |
||||
state: 'NM' |
||||
} |
||||
} |
||||
}; |
||||
var res = { |
||||
data: [{ |
||||
_score: 10, |
||||
found: true, |
||||
value: 1, |
||||
layer: 'locality', |
||||
center_point: { lat: 100.1, lon: -50.5 }, |
||||
name: { default: 'test name1' }, |
||||
parent: { |
||||
country: ['country1'] |
||||
} |
||||
}], |
||||
meta: { |
||||
scores: [10], |
||||
query_type: 'fallback' |
||||
} |
||||
}; |
||||
|
||||
confidenceScore(req, res, function() {}); |
||||
t.equal(res.data[0].confidence, 0.6, 'score was set'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('fallback to country should have score deduction', function(t) { |
||||
var req = { |
||||
clean: { |
||||
text: '123 Main St, City, NM, USA', |
||||
parsed_text: { |
||||
number: 123, |
||||
street: 'Main St', |
||||
state: 'NM', |
||||
country: 'USA' |
||||
} |
||||
} |
||||
}; |
||||
var res = { |
||||
data: [{ |
||||
_score: 10, |
||||
found: true, |
||||
value: 1, |
||||
layer: 'country', |
||||
center_point: { lat: 100.1, lon: -50.5 }, |
||||
name: { default: 'test name1' }, |
||||
parent: { |
||||
country: ['country1'] |
||||
} |
||||
}], |
||||
meta: { |
||||
scores: [10], |
||||
query_type: 'fallback' |
||||
} |
||||
}; |
||||
|
||||
confidenceScore(req, res, function() {}); |
||||
t.equal(res.data[0].confidence, 0.1, 'score was set'); |
||||
t.end(); |
||||
}); |
||||
}; |
||||
|
||||
module.exports.all = function (tape, common) { |
||||
function test(name, testFunction) { |
||||
return tape('[middleware] confidenceScore: ' + name, testFunction); |
||||
} |
||||
|
||||
for( var testCase in module.exports.tests ){ |
||||
module.exports.tests[testCase](test, common); |
||||
} |
||||
}; |
@ -0,0 +1,431 @@
|
||||
var trimByGranularity = require('../../../middleware/trimByGranularity')(); |
||||
|
||||
module.exports.tests = {}; |
||||
|
||||
module.exports.tests.trimByGranularity = function(test, common) { |
||||
test('empty res and req should not throw exception', function(t) { |
||||
function testIt() { |
||||
trimByGranularity({}, {}, function() {}); |
||||
} |
||||
|
||||
t.doesNotThrow(testIt, 'an exception should not have been thrown'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('all records with fallback.* matched_queries name should retain only venues when they are most granular', function(t) { |
||||
var req = { clean: {} }; |
||||
|
||||
var res = { |
||||
data: [ |
||||
{ name: 'venue 1', _matched_queries: ['fallback.venue'] }, |
||||
{ name: 'venue 2', _matched_queries: ['fallback.venue'] }, |
||||
{ name: 'address 1', _matched_queries: ['fallback.address'] }, |
||||
{ name: 'street 1', _matched_queries: ['fallback.street'] }, |
||||
{ name: 'neighbourhood 1', _matched_queries: ['fallback.neighbourhood'] }, |
||||
{ name: 'locality 1', _matched_queries: ['fallback.locality'] }, |
||||
{ name: 'localadmin 1', _matched_queries: ['fallback.localadmin'] }, |
||||
{ name: 'county 1', _matched_queries: ['fallback.county'] }, |
||||
{ name: 'macrocounty 1', _matched_queries: ['fallback.macrocounty'] }, |
||||
{ name: 'region 1', _matched_queries: ['fallback.region'] }, |
||||
{ name: 'macroregion 1', _matched_queries: ['fallback.macroregion'] }, |
||||
{ name: 'dependency 1', _matched_queries: ['fallback.dependency'] }, |
||||
{ name: 'country 1', _matched_queries: ['fallback.country'] }, |
||||
{ name: 'unknown', _matched_queries: ['fallback.unknown'] } |
||||
] |
||||
}; |
||||
|
||||
var expected_data = [ |
||||
{ name: 'venue 1', _matched_queries: ['fallback.venue'] }, |
||||
{ name: 'venue 2', _matched_queries: ['fallback.venue'] }, |
||||
]; |
||||
|
||||
function testIt() { |
||||
trimByGranularity(req, res, function() { |
||||
t.deepEquals(res.data, expected_data, 'only venue records should be here'); |
||||
t.end(); |
||||
}); |
||||
} |
||||
|
||||
testIt(); |
||||
}); |
||||
|
||||
test('all records with fallback.* matched_queries name should retain only addresses when they are most granular', function(t) { |
||||
var req = { clean: {} }; |
||||
|
||||
var res = { |
||||
data: [ |
||||
{ name: 'address 1', _matched_queries: ['fallback.address'] }, |
||||
{ name: 'address 2', _matched_queries: ['fallback.address'] }, |
||||
{ name: 'street 1', _matched_queries: ['fallback.street'] }, |
||||
{ name: 'neighbourhood 1', _matched_queries: ['fallback.neighbourhood'] }, |
||||
{ name: 'locality 1', _matched_queries: ['fallback.locality'] }, |
||||
{ name: 'localadmin 1', _matched_queries: ['fallback.localadmin'] }, |
||||
{ name: 'county 1', _matched_queries: ['fallback.county'] }, |
||||
{ name: 'macrocounty 1', _matched_queries: ['fallback.macrocounty'] }, |
||||
{ name: 'region 1', _matched_queries: ['fallback.region'] }, |
||||
{ name: 'macroregion 1', _matched_queries: ['fallback.macroregion'] }, |
||||
{ name: 'dependency 1', _matched_queries: ['fallback.dependency'] }, |
||||
{ name: 'country 1', _matched_queries: ['fallback.country'] }, |
||||
{ name: 'unknown', _matched_queries: ['fallback.unknown'] } |
||||
] |
||||
}; |
||||
|
||||
var expected_data = [ |
||||
{ name: 'address 1', _matched_queries: ['fallback.address'] }, |
||||
{ name: 'address 2', _matched_queries: ['fallback.address'] }, |
||||
]; |
||||
|
||||
function testIt() { |
||||
trimByGranularity(req, res, function() { |
||||
t.deepEquals(res.data, expected_data, 'only address records should be here'); |
||||
t.end(); |
||||
}); |
||||
} |
||||
|
||||
testIt(); |
||||
}); |
||||
|
||||
test('all records with fallback.* matched_queries name should retain only streets when they are most granular', function(t) { |
||||
var req = { clean: {} }; |
||||
|
||||
var res = { |
||||
data: [ |
||||
{ name: 'street 1', _matched_queries: ['fallback.street'] }, |
||||
{ name: 'street 2', _matched_queries: ['fallback.street'] }, |
||||
{ name: 'neighbourhood 1', _matched_queries: ['fallback.neighbourhood'] }, |
||||
{ name: 'locality 1', _matched_queries: ['fallback.locality'] }, |
||||
{ name: 'localadmin 1', _matched_queries: ['fallback.localadmin'] }, |
||||
{ name: 'county 1', _matched_queries: ['fallback.county'] }, |
||||
{ name: 'macrocounty 1', _matched_queries: ['fallback.macrocounty'] }, |
||||
{ name: 'region 1', _matched_queries: ['fallback.region'] }, |
||||
{ name: 'macroregion 1', _matched_queries: ['fallback.macroregion'] }, |
||||
{ name: 'dependency 1', _matched_queries: ['fallback.dependency'] }, |
||||
{ name: 'country 1', _matched_queries: ['fallback.country'] }, |
||||
{ name: 'unknown', _matched_queries: ['fallback.unknown'] } |
||||
] |
||||
}; |
||||
|
||||
var expected_data = [ |
||||
{ name: 'street 1', _matched_queries: ['fallback.street'] }, |
||||
{ name: 'street 2', _matched_queries: ['fallback.street'] }, |
||||
]; |
||||
|
||||
function testIt() { |
||||
trimByGranularity(req, res, function() { |
||||
t.deepEquals(res.data, expected_data, 'only street records should be here'); |
||||
t.end(); |
||||
}); |
||||
} |
||||
|
||||
testIt(); |
||||
}); |
||||
|
||||
test('all records with fallback.* matched_queries name should retain only neighbourhoods when they are most granular', function(t) { |
||||
var req = { clean: {} }; |
||||
|
||||
var res = { |
||||
data: [ |
||||
{ name: 'neighbourhood 1', _matched_queries: ['fallback.neighbourhood'] }, |
||||
{ name: 'neighbourhood 2', _matched_queries: ['fallback.neighbourhood'] }, |
||||
{ name: 'locality 1', _matched_queries: ['fallback.locality'] }, |
||||
{ name: 'localadmin 1', _matched_queries: ['fallback.localadmin'] }, |
||||
{ name: 'county 1', _matched_queries: ['fallback.county'] }, |
||||
{ name: 'macrocounty 1', _matched_queries: ['fallback.macrocounty'] }, |
||||
{ name: 'region 1', _matched_queries: ['fallback.region'] }, |
||||
{ name: 'macroregion 1', _matched_queries: ['fallback.macroregion'] }, |
||||
{ name: 'dependency 1', _matched_queries: ['fallback.dependency'] }, |
||||
{ name: 'country 1', _matched_queries: ['fallback.country'] }, |
||||
{ name: 'unknown', _matched_queries: ['fallback.unknown'] } |
||||
] |
||||
}; |
||||
|
||||
var expected_data = [ |
||||
{ name: 'neighbourhood 1', _matched_queries: ['fallback.neighbourhood'] }, |
||||
{ name: 'neighbourhood 2', _matched_queries: ['fallback.neighbourhood'] }, |
||||
]; |
||||
|
||||
function testIt() { |
||||
trimByGranularity(req, res, function() { |
||||
t.deepEquals(res.data, expected_data, 'only neighbourhood records should be here'); |
||||
t.end(); |
||||
}); |
||||
} |
||||
|
||||
testIt(); |
||||
}); |
||||
|
||||
test('all records with fallback.* matched_queries name should retain only localities when they are most granular', function(t) { |
||||
var req = { clean: {} }; |
||||
|
||||
var res = { |
||||
data: [ |
||||
{ name: 'locality 1', _matched_queries: ['fallback.locality'] }, |
||||
{ name: 'locality 2', _matched_queries: ['fallback.locality'] }, |
||||
{ name: 'localadmin 1', _matched_queries: ['fallback.localadmin'] }, |
||||
{ name: 'county 1', _matched_queries: ['fallback.county'] }, |
||||
{ name: 'macrocounty 1', _matched_queries: ['fallback.macrocounty'] }, |
||||
{ name: 'region 1', _matched_queries: ['fallback.region'] }, |
||||
{ name: 'macroregion 1', _matched_queries: ['fallback.macroregion'] }, |
||||
{ name: 'dependency 1', _matched_queries: ['fallback.dependency'] }, |
||||
{ name: 'country 1', _matched_queries: ['fallback.country'] }, |
||||
{ name: 'unknown', _matched_queries: ['fallback.unknown'] } |
||||
] |
||||
}; |
||||
|
||||
var expected_data = [ |
||||
{ name: 'locality 1', _matched_queries: ['fallback.locality'] }, |
||||
{ name: 'locality 2', _matched_queries: ['fallback.locality'] }, |
||||
]; |
||||
|
||||
function testIt() { |
||||
trimByGranularity(req, res, function() { |
||||
t.deepEquals(res.data, expected_data, 'only locality records should be here'); |
||||
t.end(); |
||||
}); |
||||
} |
||||
|
||||
testIt(); |
||||
}); |
||||
|
||||
test('all records with fallback.* matched_queries name should retain only localadmins when they are most granular', function(t) { |
||||
var req = { clean: {} }; |
||||
|
||||
var res = { |
||||
data: [ |
||||
{ name: 'localadmin 1', _matched_queries: ['fallback.localadmin'] }, |
||||
{ name: 'localadmin 2', _matched_queries: ['fallback.localadmin'] }, |
||||
{ name: 'county 1', _matched_queries: ['fallback.county'] }, |
||||
{ name: 'macrocounty 1', _matched_queries: ['fallback.macrocounty'] }, |
||||
{ name: 'region 1', _matched_queries: ['fallback.region'] }, |
||||
{ name: 'macroregion 1', _matched_queries: ['fallback.macroregion'] }, |
||||
{ name: 'dependency 1', _matched_queries: ['fallback.dependency'] }, |
||||
{ name: 'country 1', _matched_queries: ['fallback.country'] }, |
||||
{ name: 'unknown', _matched_queries: ['fallback.unknown'] } |
||||
] |
||||
}; |
||||
|
||||
var expected_data = [ |
||||
{ name: 'localadmin 1', _matched_queries: ['fallback.localadmin'] }, |
||||
{ name: 'localadmin 2', _matched_queries: ['fallback.localadmin'] }, |
||||
]; |
||||
|
||||
function testIt() { |
||||
trimByGranularity(req, res, function() { |
||||
t.deepEquals(res.data, expected_data, 'only localadmin records should be here'); |
||||
t.end(); |
||||
}); |
||||
} |
||||
|
||||
testIt(); |
||||
}); |
||||
|
||||
test('all records with fallback.* matched_queries name should retain only counties when they are most granular', function(t) { |
||||
var req = { clean: {} }; |
||||
|
||||
var res = { |
||||
data: [ |
||||
{ name: 'county 1', _matched_queries: ['fallback.county'] }, |
||||
{ name: 'county 2', _matched_queries: ['fallback.county'] }, |
||||
{ name: 'macrocounty 1', _matched_queries: ['fallback.macrocounty'] }, |
||||
{ name: 'region 1', _matched_queries: ['fallback.region'] }, |
||||
{ name: 'macroregion 1', _matched_queries: ['fallback.macroregion'] }, |
||||
{ name: 'dependency 1', _matched_queries: ['fallback.dependency'] }, |
||||
{ name: 'country 1', _matched_queries: ['fallback.country'] }, |
||||
{ name: 'unknown', _matched_queries: ['fallback.unknown'] } |
||||
] |
||||
}; |
||||
|
||||
var expected_data = [ |
||||
{ name: 'county 1', _matched_queries: ['fallback.county'] }, |
||||
{ name: 'county 2', _matched_queries: ['fallback.county'] }, |
||||
]; |
||||
|
||||
function testIt() { |
||||
trimByGranularity(req, res, function() { |
||||
t.deepEquals(res.data, expected_data, 'only county records should be here'); |
||||
t.end(); |
||||
}); |
||||
} |
||||
|
||||
testIt(); |
||||
}); |
||||
|
||||
test('all records with fallback.* matched_queries name should retain only macrocounties when they are most granular', function(t) { |
||||
var req = { clean: {} }; |
||||
|
||||
var res = { |
||||
data: [ |
||||
{ name: 'macrocounty 1', _matched_queries: ['fallback.macrocounty'] }, |
||||
{ name: 'macrocounty 2', _matched_queries: ['fallback.macrocounty'] }, |
||||
{ name: 'region 1', _matched_queries: ['fallback.region'] }, |
||||
{ name: 'macroregion 1', _matched_queries: ['fallback.macroregion'] }, |
||||
{ name: 'dependency 1', _matched_queries: ['fallback.dependency'] }, |
||||
{ name: 'country 1', _matched_queries: ['fallback.country'] }, |
||||
{ name: 'unknown', _matched_queries: ['fallback.unknown'] } |
||||
] |
||||
}; |
||||
|
||||
var expected_data = [ |
||||
{ name: 'macrocounty 1', _matched_queries: ['fallback.macrocounty'] }, |
||||
{ name: 'macrocounty 2', _matched_queries: ['fallback.macrocounty'] }, |
||||
]; |
||||
|
||||
function testIt() { |
||||
trimByGranularity(req, res, function() { |
||||
t.deepEquals(res.data, expected_data, 'only macrocounty records should be here'); |
||||
t.end(); |
||||
}); |
||||
} |
||||
|
||||
testIt(); |
||||
}); |
||||
|
||||
test('all records with fallback.* matched_queries name should retain only regions when they are most granular', function(t) { |
||||
var req = { clean: {} }; |
||||
|
||||
var res = { |
||||
data: [ |
||||
{ name: 'region 1', _matched_queries: ['fallback.region'] }, |
||||
{ name: 'region 2', _matched_queries: ['fallback.region'] }, |
||||
{ name: 'macroregion 1', _matched_queries: ['fallback.macroregion'] }, |
||||
{ name: 'dependency 1', _matched_queries: ['fallback.dependency'] }, |
||||
{ name: 'country 1', _matched_queries: ['fallback.country'] }, |
||||
{ name: 'unknown', _matched_queries: ['fallback.unknown'] } |
||||
] |
||||
}; |
||||
|
||||
var expected_data = [ |
||||
{ name: 'region 1', _matched_queries: ['fallback.region'] }, |
||||
{ name: 'region 2', _matched_queries: ['fallback.region'] }, |
||||
]; |
||||
|
||||
function testIt() { |
||||
trimByGranularity(req, res, function() { |
||||
t.deepEquals(res.data, expected_data, 'only region records should be here'); |
||||
t.end(); |
||||
}); |
||||
} |
||||
|
||||
testIt(); |
||||
}); |
||||
|
||||
test('all records with fallback.* matched_queries name should retain only macroregions when they are most granular', function(t) { |
||||
var req = { clean: {} }; |
||||
|
||||
var res = { |
||||
data: [ |
||||
{ name: 'macroregion 1', _matched_queries: ['fallback.macroregion'] }, |
||||
{ name: 'macroregion 2', _matched_queries: ['fallback.macroregion'] }, |
||||
{ name: 'dependency 1', _matched_queries: ['fallback.dependency'] }, |
||||
{ name: 'country 1', _matched_queries: ['fallback.country'] }, |
||||
{ name: 'unknown', _matched_queries: ['fallback.unknown'] } |
||||
] |
||||
}; |
||||
|
||||
var expected_data = [ |
||||
{ name: 'macroregion 1', _matched_queries: ['fallback.macroregion'] }, |
||||
{ name: 'macroregion 2', _matched_queries: ['fallback.macroregion'] }, |
||||
]; |
||||
|
||||
function testIt() { |
||||
trimByGranularity(req, res, function() { |
||||
t.deepEquals(res.data, expected_data, 'only macroregion records should be here'); |
||||
t.end(); |
||||
}); |
||||
} |
||||
|
||||
testIt(); |
||||
}); |
||||
|
||||
test('all records with fallback.* matched_queries name should retain only dependencies when they are most granular', function(t) { |
||||
var req = { clean: {} }; |
||||
|
||||
var res = { |
||||
data: [ |
||||
{ name: 'dependency 1', _matched_queries: ['fallback.dependency'] }, |
||||
{ name: 'dependency 2', _matched_queries: ['fallback.dependency'] }, |
||||
{ name: 'country 1', _matched_queries: ['fallback.country'] }, |
||||
{ name: 'unknown', _matched_queries: ['fallback.unknown'] } |
||||
] |
||||
}; |
||||
|
||||
var expected_data = [ |
||||
{ name: 'dependency 1', _matched_queries: ['fallback.dependency'] }, |
||||
{ name: 'dependency 2', _matched_queries: ['fallback.dependency'] }, |
||||
]; |
||||
|
||||
function testIt() { |
||||
trimByGranularity(req, res, function() { |
||||
t.deepEquals(res.data, expected_data, 'only dependency records should be here'); |
||||
t.end(); |
||||
}); |
||||
} |
||||
|
||||
testIt(); |
||||
}); |
||||
|
||||
test('all records with fallback.* matched_queries name should retain only countries when they are most granular', function(t) { |
||||
var req = { clean: {} }; |
||||
|
||||
var res = { |
||||
data: [ |
||||
{ name: 'country 1', _matched_queries: ['fallback.country'] }, |
||||
{ name: 'country 2', _matched_queries: ['fallback.country'] }, |
||||
{ name: 'unknown', _matched_queries: ['fallback.unknown'] } |
||||
] |
||||
}; |
||||
|
||||
var expected_data = [ |
||||
{ name: 'country 1', _matched_queries: ['fallback.country'] }, |
||||
{ name: 'country 2', _matched_queries: ['fallback.country'] }, |
||||
]; |
||||
|
||||
function testIt() { |
||||
trimByGranularity(req, res, function() { |
||||
t.deepEquals(res.data, expected_data, 'only country records should be here'); |
||||
t.end(); |
||||
}); |
||||
} |
||||
|
||||
testIt(); |
||||
}); |
||||
|
||||
test('presence of any non-fallback.* named queries should not trim', function(t) { |
||||
var req = { clean: {} }; |
||||
|
||||
var res = { |
||||
data: [ |
||||
{ name: 'region', _matched_queries: ['fallback.region'] }, |
||||
{ name: 'country', _matched_queries: ['fallback.country'] }, |
||||
{ name: 'result with non-named query' } |
||||
] |
||||
}; |
||||
|
||||
var expected_data = [ |
||||
{ name: 'region', _matched_queries: ['fallback.region'] }, |
||||
{ name: 'country', _matched_queries: ['fallback.country'] }, |
||||
{ name: 'result with non-named query' } |
||||
]; |
||||
|
||||
function testIt() { |
||||
trimByGranularity(req, res, function() { |
||||
t.deepEquals(res.data, expected_data, 'all should results should have been retained'); |
||||
t.end(); |
||||
}); |
||||
} |
||||
|
||||
testIt(); |
||||
|
||||
}); |
||||
|
||||
}; |
||||
|
||||
module.exports.all = function (tape, common) { |
||||
function test(name, testFunction) { |
||||
return tape('[middleware] trimByGranularity: ' + name, testFunction); |
||||
} |
||||
|
||||
for( var testCase in module.exports.tests ){ |
||||
module.exports.tests[testCase](test, common); |
||||
} |
||||
}; |
@ -0,0 +1,206 @@
|
||||
var generate = require('../../../query/search_original'); |
||||
|
||||
module.exports.tests = {}; |
||||
|
||||
module.exports.tests.interface = function(test, common) { |
||||
test('valid interface', function(t) { |
||||
t.equal(typeof generate, 'function', 'valid function'); |
||||
t.end(); |
||||
}); |
||||
}; |
||||
|
||||
module.exports.tests.query = function(test, common) { |
||||
test('valid search + focus + bbox', function(t) { |
||||
var query = generate({ |
||||
text: 'test', querySize: 10, |
||||
'focus.point.lat': 29.49136, 'focus.point.lon': -82.50622, |
||||
'boundary.rect.min_lat': 47.47, |
||||
'boundary.rect.max_lon': -61.84, |
||||
'boundary.rect.max_lat': 11.51, |
||||
'boundary.rect.min_lon': -103.16, |
||||
layers: ['test'] |
||||
}); |
||||
|
||||
var compiled = JSON.parse( JSON.stringify( query ) ); |
||||
var expected = require('../fixture/search_linguistic_focus_bbox_original'); |
||||
|
||||
t.deepEqual(compiled.type, 'original', 'query type set'); |
||||
t.deepEqual(compiled.body, expected, 'search_linguistic_focus_bbox'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('valid search + bbox', function(t) { |
||||
var query = generate({ |
||||
text: 'test', querySize: 10, |
||||
'boundary.rect.min_lat': 47.47, |
||||
'boundary.rect.max_lon': -61.84, |
||||
'boundary.rect.max_lat': 11.51, |
||||
'boundary.rect.min_lon': -103.16, |
||||
layers: ['test'] |
||||
}); |
||||
|
||||
var compiled = JSON.parse( JSON.stringify( query ) ); |
||||
var expected = require('../fixture/search_linguistic_bbox_original'); |
||||
|
||||
t.deepEqual(compiled.type, 'original', 'query type set'); |
||||
t.deepEqual(compiled.body, expected, 'search_linguistic_bbox'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('valid lingustic-only search', function(t) { |
||||
var query = generate({ |
||||
text: 'test', querySize: 10, |
||||
layers: ['test'] |
||||
}); |
||||
|
||||
var compiled = JSON.parse( JSON.stringify( query ) ); |
||||
var expected = require('../fixture/search_linguistic_only_original'); |
||||
|
||||
t.deepEqual(compiled.type, 'original', 'query type set'); |
||||
t.deepEqual(compiled.body, expected, 'search_linguistic_only'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('search search + focus', function(t) { |
||||
var query = generate({ |
||||
text: 'test', querySize: 10, |
||||
'focus.point.lat': 29.49136, 'focus.point.lon': -82.50622, |
||||
layers: ['test'] |
||||
}); |
||||
|
||||
var compiled = JSON.parse( JSON.stringify( query ) ); |
||||
var expected = require('../fixture/search_linguistic_focus_original'); |
||||
|
||||
t.deepEqual(compiled.type, 'original', 'query type set'); |
||||
t.deepEqual(compiled.body, expected, 'search_linguistic_focus'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('search search + focus on null island', function(t) { |
||||
var query = generate({ |
||||
text: 'test', querySize: 10, |
||||
'focus.point.lat': 0, 'focus.point.lon': 0, |
||||
layers: ['test'] |
||||
}); |
||||
|
||||
var compiled = JSON.parse( JSON.stringify( query ) ); |
||||
var expected = require('../fixture/search_linguistic_focus_null_island_original'); |
||||
|
||||
t.deepEqual(compiled.type, 'original', 'query type set'); |
||||
t.deepEqual(compiled.body, expected, 'search_linguistic_focus_null_island'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('valid query with a full valid address', function(t) { |
||||
var query = generate({ text: '123 main st new york ny 10010 US', |
||||
layers: [ 'address', 'venue', 'country', 'region', 'county', 'neighbourhood', 'locality', 'localadmin' ], |
||||
querySize: 10, |
||||
parsed_text: { |
||||
number: '123', |
||||
street: 'main st', |
||||
state: 'NY', |
||||
country: 'USA', |
||||
postalcode: '10010', |
||||
regions: [ 'new york' ] |
||||
} |
||||
}); |
||||
|
||||
var compiled = JSON.parse( JSON.stringify( query ) ); |
||||
var expected = require('../fixture/search_full_address_original'); |
||||
|
||||
t.deepEqual(compiled.type, 'original', 'query type set'); |
||||
t.deepEqual(compiled.body, expected, 'search_full_address'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('valid query with partial address', function(t) { |
||||
var query = generate({ text: 'soho grand, new york', |
||||
layers: [ 'address', 'venue', 'country', 'region', 'county', 'neighbourhood', 'locality', 'localadmin' ], |
||||
querySize: 10, |
||||
parsed_text: { name: 'soho grand', |
||||
state: 'NY', |
||||
regions: [ 'soho grand' ], |
||||
admin_parts: 'new york' |
||||
} |
||||
}); |
||||
|
||||
var compiled = JSON.parse( JSON.stringify( query ) ); |
||||
var expected = require('../fixture/search_partial_address_original'); |
||||
|
||||
t.deepEqual(compiled.type, 'original', 'query type set'); |
||||
t.deepEqual(compiled.body, expected, 'search_partial_address'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('valid query with regions in address', function(t) { |
||||
var query = generate({ text: '1 water st manhattan ny', |
||||
layers: [ 'address', 'venue', 'country', 'region', 'county', 'neighbourhood', 'locality', 'localadmin' ], |
||||
querySize: 10, |
||||
parsed_text: { number: '1', |
||||
street: 'water st', |
||||
state: 'NY', |
||||
regions: [ 'manhattan' ] |
||||
} |
||||
}); |
||||
|
||||
var compiled = JSON.parse( JSON.stringify( query ) ); |
||||
var expected = require('../fixture/search_regions_address_original'); |
||||
|
||||
t.deepEqual(compiled.type, 'original', 'query type set'); |
||||
t.deepEqual(compiled.body, expected, 'search_regions_address'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('valid boundary.country search', function(t) { |
||||
var query = generate({ |
||||
text: 'test', querySize: 10, |
||||
layers: ['test'], |
||||
'boundary.country': 'ABC' |
||||
}); |
||||
|
||||
var compiled = JSON.parse( JSON.stringify( query ) ); |
||||
var expected = require('../fixture/search_boundary_country_original'); |
||||
|
||||
t.deepEqual(compiled.type, 'original', 'query type set'); |
||||
t.deepEqual(compiled.body, expected, 'search: valid boundary.country query'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('valid sources filter', function(t) { |
||||
var query = generate({ |
||||
'text': 'test', |
||||
'sources': ['test_source'] |
||||
}); |
||||
|
||||
var compiled = JSON.parse( JSON.stringify( query ) ); |
||||
var expected = require('../fixture/search_with_source_filtering_original'); |
||||
|
||||
t.deepEqual(compiled.type, 'original', 'query type set'); |
||||
t.deepEqual(compiled.body, expected, 'search: valid search query with source filtering'); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('categories filter', function(t) { |
||||
var query = generate({ |
||||
'text': 'test', |
||||
'categories': ['retail','food'] |
||||
}); |
||||
|
||||
var compiled = JSON.parse( JSON.stringify( query ) ); |
||||
var expected = require('../fixture/search_with_category_filtering_original'); |
||||
|
||||
t.deepEqual(compiled.type, 'original', 'query type set'); |
||||
t.deepEqual(compiled.body, expected, 'valid search query with category filtering'); |
||||
t.end(); |
||||
}); |
||||
}; |
||||
|
||||
module.exports.all = function (tape, common) { |
||||
function test(name, testFunction) { |
||||
return tape('search query ' + name, testFunction); |
||||
} |
||||
|
||||
for( var testCase in module.exports.tests ){ |
||||
module.exports.tests[testCase](test, common); |
||||
} |
||||
}; |
@ -0,0 +1,165 @@
|
||||
var VariableStore = require('pelias-query').Vars; |
||||
var text_parser = require('../../../query/text_parser'); |
||||
|
||||
module.exports.tests = {}; |
||||
|
||||
module.exports.tests.interface = function(test, common) { |
||||
test('valid interface', function(t) { |
||||
t.equal(typeof text_parser, 'function', 'valid function'); |
||||
t.end(); |
||||
}); |
||||
}; |
||||
|
||||
module.exports.tests.query = function(test, common) { |
||||
test('parsed_text without properties should leave vs properties unset', function(t) { |
||||
var parsed_text = {}; |
||||
var vs = new VariableStore(); |
||||
|
||||
text_parser(parsed_text, vs); |
||||
|
||||
t.false(vs.isset('input:query')); |
||||
t.false(vs.isset('input:category')); |
||||
t.false(vs.isset('input:housenumber')); |
||||
t.false(vs.isset('input:street')); |
||||
t.false(vs.isset('input:neighbourhood')); |
||||
t.false(vs.isset('input:borough')); |
||||
t.false(vs.isset('input:postcode')); |
||||
t.false(vs.isset('input:locality')); |
||||
t.false(vs.isset('input:county')); |
||||
t.false(vs.isset('input:region')); |
||||
t.false(vs.isset('input:country')); |
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('parsed_text without properties should leave vs properties unset', function(t) { |
||||
var parsed_text = { |
||||
query: 'query value', |
||||
category: 'category value', |
||||
number: 'number value', |
||||
street: 'street value', |
||||
neighbourhood: 'neighbourhood value', |
||||
borough: 'borough value', |
||||
postalcode: 'postalcode value', |
||||
city: 'city value', |
||||
county: 'county value', |
||||
state: 'state value', |
||||
country: 'country value' |
||||
}; |
||||
var vs = new VariableStore(); |
||||
|
||||
text_parser(parsed_text, vs); |
||||
|
||||
t.equals(vs.var('input:query').toString(), 'query value'); |
||||
t.equals(vs.var('input:category').toString(), 'category value'); |
||||
t.equals(vs.var('input:housenumber').toString(), 'number value'); |
||||
t.equals(vs.var('input:street').toString(), 'street value'); |
||||
t.equals(vs.var('input:neighbourhood').toString(), 'neighbourhood value'); |
||||
t.equals(vs.var('input:borough').toString(), 'borough value'); |
||||
t.equals(vs.var('input:postcode').toString(), 'postalcode value'); |
||||
t.equals(vs.var('input:locality').toString(), 'city value'); |
||||
t.equals(vs.var('input:county').toString(), 'county value'); |
||||
t.equals(vs.var('input:region').toString(), 'state value'); |
||||
t.equals(vs.var('input:country').toString(), 'country value'); |
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
}; |
||||
|
||||
module.exports.tests.housenumber_special_cases = function(test, common) { |
||||
test('numeric query with street but no number should reassign query to housenumber', function(t) { |
||||
var parsed_text = { |
||||
query: '17', |
||||
// no house number set
|
||||
street: 'street value' |
||||
}; |
||||
var vs = new VariableStore(); |
||||
|
||||
text_parser(parsed_text, vs); |
||||
|
||||
t.false(vs.isset('input:query')); |
||||
t.equals(vs.var('input:housenumber').toString(), '17'); |
||||
t.equals(vs.var('input:street').toString(), 'street value'); |
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('numeric query with street but without number should not change anything', function(t) { |
||||
var parsed_text = { |
||||
query: '17', |
||||
number: 'housenumber value', |
||||
street: 'street value' |
||||
// no number or street
|
||||
}; |
||||
var vs = new VariableStore(); |
||||
|
||||
text_parser(parsed_text, vs); |
||||
|
||||
t.equals(vs.var('input:query').toString(), '17'); |
||||
t.equals(vs.var('input:housenumber').toString(), 'housenumber value'); |
||||
t.equals(vs.var('input:street').toString(), 'street value'); |
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('numeric query with number but without street should not change anything', function(t) { |
||||
var parsed_text = { |
||||
query: '17', |
||||
number: 'number value' |
||||
// no number or street
|
||||
}; |
||||
var vs = new VariableStore(); |
||||
|
||||
text_parser(parsed_text, vs); |
||||
|
||||
t.equals(vs.var('input:query').toString(), '17'); |
||||
t.equals(vs.var('input:housenumber').toString(), 'number value'); |
||||
t.false(vs.isset('input:street')); |
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('numeric query without street or number should not change anything', function(t) { |
||||
var parsed_text = { |
||||
query: '17' |
||||
// no number or street
|
||||
}; |
||||
var vs = new VariableStore(); |
||||
|
||||
text_parser(parsed_text, vs); |
||||
|
||||
t.equals(vs.var('input:query').toString(), '17'); |
||||
t.false(vs.isset('input:housenumber')); |
||||
t.false(vs.isset('input:street')); |
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('non-numeric query with street but no number should not change anything', function(t) { |
||||
var parsed_text = { |
||||
query: '13 this is 15 not a number 17', |
||||
street: 'street value' |
||||
}; |
||||
var vs = new VariableStore(); |
||||
|
||||
text_parser(parsed_text, vs); |
||||
|
||||
t.equals(vs.var('input:query').toString(), '13 this is 15 not a number 17'); |
||||
t.false(vs.isset('input:housenumber')); |
||||
t.equals(vs.var('input:street').toString(), 'street value'); |
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
}; |
||||
|
||||
module.exports.all = function (tape, common) { |
||||
function test(name, testFunction) { |
||||
return tape('text_parser ' + name, testFunction); |
||||
} |
||||
|
||||
for( var testCase in module.exports.tests ){ |
||||
module.exports.tests[testCase](test, common); |
||||
} |
||||
}; |
@ -0,0 +1,339 @@
|
||||
var sanitiser = require('../../../sanitiser/_text_addressit'); |
||||
var type_mapping = require('../../../helper/type_mapping'); |
||||
|
||||
module.exports.tests = {}; |
||||
|
||||
module.exports.tests.text_parser = function(test, common) { |
||||
test('short input text has admin layers set ', function(t) { |
||||
var raw = { |
||||
text: 'emp' //start of empire state building
|
||||
}; |
||||
var clean = { |
||||
}; |
||||
|
||||
var messages = sanitiser(raw, clean); |
||||
|
||||
t.deepEquals(messages.errors, [], 'no errors'); |
||||
t.deepEquals(messages.warnings, [], 'no warnings'); |
||||
|
||||
t.end(); |
||||
}); |
||||
|
||||
var usQueries = [ |
||||
{ name: 'soho', admin_parts: 'new york', state: 'NY' }, |
||||
{ name: '123 main', admin_parts: 'new york', state: 'NY' } |
||||
]; |
||||
|
||||
usQueries.forEach(function (query) { |
||||
test('naive parsing ' + query, function(t) { |
||||
var raw = { |
||||
text: query.name + ', ' + query.admin_parts |
||||
}; |
||||
var clean = {}; |
||||
|
||||
var expected_clean = { |
||||
text: query.name + ', ' + query.admin_parts, |
||||
parsed_text: { |
||||
name: query.name, |
||||
regions: [ query.name ], |
||||
admin_parts: query.admin_parts, |
||||
state: query.state |
||||
} |
||||
}; |
||||
|
||||
var messages = sanitiser(raw, clean); |
||||
|
||||
t.deepEqual(messages, { errors: [], warnings: [] } ); |
||||
t.deepEqual(clean, expected_clean); |
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('naive parsing ' + query + ' without spaces', function(t) { |
||||
var raw = { |
||||
text: query.name + ',' + query.admin_parts |
||||
}; |
||||
var clean = {}; |
||||
|
||||
var expected_clean = { |
||||
text: query.name + ',' + query.admin_parts, |
||||
parsed_text: { |
||||
name: query.name, |
||||
regions: [ query.name ], |
||||
admin_parts: query.admin_parts, |
||||
state: query.state |
||||
} |
||||
}; |
||||
|
||||
var messages = sanitiser(raw, clean); |
||||
|
||||
t.deepEqual(messages, { errors: [], warnings: [] } ); |
||||
t.deepEqual(clean, expected_clean); |
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
}); |
||||
|
||||
var nonUSQueries = [ |
||||
{ name: 'chelsea', admin_parts: 'london' }, |
||||
]; |
||||
|
||||
nonUSQueries.forEach(function (query) { |
||||
test('naive parsing ' + query, function(t) { |
||||
var raw = { |
||||
text: query.name + ', ' + query.admin_parts |
||||
}; |
||||
var clean = {}; |
||||
|
||||
var expected_clean = { |
||||
text: query.name + ', ' + query.admin_parts, |
||||
parsed_text: { |
||||
name: query.name, |
||||
regions: [ query.name, query.admin_parts ], |
||||
admin_parts: query.admin_parts |
||||
} |
||||
}; |
||||
|
||||
var messages = sanitiser(raw, clean); |
||||
|
||||
t.deepEqual(messages, { errors: [], warnings: [] } ); |
||||
t.deepEqual(clean, expected_clean); |
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('naive parsing ' + query + ' without spaces', function(t) { |
||||
var raw = { |
||||
text: query.name + ',' + query.admin_parts |
||||
}; |
||||
var clean = {}; |
||||
|
||||
var expected_clean = { |
||||
text: query.name + ',' + query.admin_parts, |
||||
parsed_text: { |
||||
name: query.name, |
||||
regions: [ query.name, query.admin_parts ], |
||||
admin_parts: query.admin_parts |
||||
} |
||||
}; |
||||
|
||||
var messages = sanitiser(raw, clean); |
||||
|
||||
t.deepEqual(messages, { errors: [], warnings: [] } ); |
||||
t.deepEqual(clean, expected_clean); |
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
}); |
||||
|
||||
test('query with one token', function (t) { |
||||
var raw = { |
||||
text: 'yugolsavia' |
||||
}; |
||||
var clean = {}; |
||||
clean.parsed_text = 'this should be removed'; |
||||
|
||||
var expected_clean = { |
||||
text: 'yugolsavia' |
||||
}; |
||||
|
||||
var messages = sanitiser(raw, clean); |
||||
|
||||
t.deepEqual(messages, { errors: [], warnings: [] } ); |
||||
t.deepEqual(clean, expected_clean); |
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('query with two tokens, no numbers', function (t) { |
||||
var raw = { |
||||
text: 'small town' |
||||
}; |
||||
var clean = {}; |
||||
clean.parsed_text = 'this should be removed'; |
||||
|
||||
var expected_clean = { |
||||
text: 'small town' |
||||
}; |
||||
|
||||
var messages = sanitiser(raw, clean); |
||||
|
||||
t.deepEqual(messages, { errors: [], warnings: [] } ); |
||||
t.deepEqual(clean, expected_clean); |
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('query with two tokens, number first', function (t) { |
||||
var raw = { |
||||
text: '123 main' |
||||
}; |
||||
var clean = {}; |
||||
clean.parsed_text = 'this should be removed'; |
||||
|
||||
var expected_clean = { |
||||
text: '123 main' |
||||
}; |
||||
|
||||
var messages = sanitiser(raw, clean); |
||||
|
||||
t.deepEqual(messages, { errors: [], warnings: [] } ); |
||||
t.deepEqual(clean, expected_clean); |
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('query with two tokens, number second', function (t) { |
||||
var raw = { |
||||
text: 'main 123' |
||||
}; |
||||
var clean = {}; |
||||
clean.parsed_text = 'this should be removed'; |
||||
|
||||
var expected_clean = { |
||||
text: 'main 123' |
||||
}; |
||||
|
||||
var messages = sanitiser(raw, clean); |
||||
|
||||
t.deepEqual(messages, { errors: [], warnings: [] } ); |
||||
t.deepEqual(clean, expected_clean); |
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('query with many tokens', function(t) { |
||||
var raw = { |
||||
text: 'main particle new york' |
||||
}; |
||||
var clean = {}; |
||||
clean.parsed_text = 'this should be removed'; |
||||
|
||||
var expected_clean = { |
||||
text: 'main particle new york', |
||||
parsed_text: { |
||||
regions: [ 'main particle' ], |
||||
state: 'NY' |
||||
} |
||||
}; |
||||
|
||||
var messages = sanitiser(raw, clean); |
||||
|
||||
t.deepEqual(messages, { errors: [], warnings: [] } ); |
||||
t.deepEqual(clean, expected_clean); |
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('valid address, house number', function(t) { |
||||
var raw = { |
||||
text: '123 main st new york ny' |
||||
}; |
||||
var clean = {}; |
||||
|
||||
var expected_clean = { |
||||
text: '123 main st new york ny', |
||||
parsed_text: { |
||||
number: '123', |
||||
street: 'main st', |
||||
state: 'NY', |
||||
regions: [ 'new york' ] |
||||
} |
||||
}; |
||||
|
||||
var messages = sanitiser(raw, clean); |
||||
|
||||
t.deepEqual(messages, { errors: [], warnings: [] } ); |
||||
t.deepEqual(clean, expected_clean); |
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
test('valid address, zipcode', function(t) { |
||||
var raw = { |
||||
text: '123 main st new york ny 10010' |
||||
}; |
||||
var clean = {}; |
||||
|
||||
var expected_clean = { |
||||
text: '123 main st new york ny 10010', |
||||
parsed_text: { |
||||
number: '123', |
||||
street: 'main st', |
||||
state: 'NY', |
||||
postalcode: '10010', |
||||
regions: [ 'new york' ] |
||||
} |
||||
}; |
||||
|
||||
var messages = sanitiser(raw, clean); |
||||
|
||||
t.deepEqual(messages, { errors: [], warnings: [] } ); |
||||
t.deepEqual(clean, expected_clean); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('valid address with leading 0s in zipcode', function(t) { |
||||
var raw = { |
||||
text: '339 W Main St, Cheshire, 06410' |
||||
}; |
||||
var clean = {}; |
||||
|
||||
var expected_clean = { |
||||
text: '339 W Main St, Cheshire, 06410', |
||||
parsed_text: { |
||||
name: '339 W Main St', |
||||
number: '339', |
||||
street: 'W Main St', |
||||
postalcode: '06410', |
||||
regions: [ 'Cheshire' ], |
||||
admin_parts: 'Cheshire, 06410' |
||||
} |
||||
}; |
||||
|
||||
var messages = sanitiser(raw, clean); |
||||
|
||||
t.deepEqual(messages, { errors: [], warnings: [] } ); |
||||
t.deepEqual(clean, expected_clean); |
||||
t.end(); |
||||
}); |
||||
|
||||
test('valid address without spaces after commas', function(t) { |
||||
var raw = { |
||||
text: '339 W Main St,Lancaster,PA' |
||||
}; |
||||
var clean = {}; |
||||
|
||||
var expected_clean = { |
||||
text: '339 W Main St,Lancaster,PA', |
||||
parsed_text: { |
||||
name: '339 W Main St', |
||||
number: '339', |
||||
street: 'W Main St', |
||||
state: 'PA', |
||||
regions: [ 'Lancaster' ], |
||||
admin_parts: 'Lancaster, PA' |
||||
} |
||||
}; |
||||
|
||||
var messages = sanitiser(raw, clean); |
||||
|
||||
t.deepEqual(messages, { errors: [], warnings: [] } ); |
||||
t.deepEqual(clean, expected_clean); |
||||
t.end(); |
||||
|
||||
}); |
||||
|
||||
}; |
||||
|
||||
module.exports.all = function (tape, common) { |
||||
function test(name, testFunction) { |
||||
return tape('SANITISER _text: ' + name, testFunction); |
||||
} |
||||
|
||||
for( var testCase in module.exports.tests ){ |
||||
module.exports.tests[testCase](test, common); |
||||
} |
||||
}; |
@ -0,0 +1,161 @@
|
||||
var sanitizeAll = require('../../../sanitiser/sanitizeAll'); |
||||
|
||||
module.exports.tests = {}; |
||||
|
||||
module.exports.tests.all = function(test, common) { |
||||
test('req.clean/errors/warnings should be initialized when they are not', function(t) { |
||||
var req = {}; |
||||
var sanitizers = [ |
||||
function() { |
||||
req.clean.a = 'first sanitizer'; |
||||
return { |
||||
errors: ['error 1', 'error 2'], |
||||
warnings: ['warning 1', 'warning 2'] |
||||
}; |
||||
}, |
||||
function() { |
||||
req.clean.b = 'second sanitizer'; |
||||
return { |
||||
errors: ['error 3'], |
||||
warnings: ['warning 3'] |
||||
}; |
||||
} |
||||
]; |
||||
|
||||
var expected_req = { |
||||
clean: { |
||||
a: 'first sanitizer', |
||||
b: 'second sanitizer' |
||||
}, |
||||
errors: ['error 1', 'error 2', 'error 3'], |
||||
warnings: ['warning 1', 'warning 2', 'warning 3'] |
||||
}; |
||||
|
||||
sanitizeAll(req, sanitizers, function(){ |
||||
t.deepEquals(req, expected_req); |
||||
t.end(); |
||||
}); |
||||
|
||||
}); |
||||
|
||||
test('req.clean/errors/warnings should not be initialized when they already have been', function(t) { |
||||
var req = { |
||||
clean: { |
||||
alreadyInitialized: true |
||||
}, |
||||
errors: ['pre-existing error'], |
||||
warnings: ['pre-existing warning'] |
||||
}; |
||||
|
||||
var sanitizers = [ |
||||
function() { |
||||
req.clean.a = 'first sanitizer'; |
||||
return { |
||||
errors: ['error 1', 'error 2'], |
||||
warnings: ['warning 1', 'warning 2'] |
||||
}; |
||||
}, |
||||
function() { |
||||
req.clean.b = 'second sanitizer'; |
||||
return { |
||||
errors: ['error 3'], |
||||
warnings: ['warning 3'] |
||||
}; |
||||
} |
||||
]; |
||||
|
||||
var expected_req = { |
||||
clean: { |
||||
alreadyInitialized: true, |
||||
a: 'first sanitizer', |
||||
b: 'second sanitizer' |
||||
}, |
||||
errors: ['pre-existing error', 'error 1', 'error 2', 'error 3'], |
||||
warnings: ['pre-existing warning', 'warning 1', 'warning 2', 'warning 3'] |
||||
}; |
||||
|
||||
sanitizeAll(req, sanitizers, function(){ |
||||
t.deepEquals(req, expected_req); |
||||
t.end(); |
||||
}); |
||||
|
||||
}); |
||||
|
||||
test('req.query should be passed to individual sanitizers when available', function(t) { |
||||
var req = { |
||||
query: { |
||||
value: 'query value' |
||||
} |
||||
}; |
||||
var sanitizers = [ |
||||
function(params) { |
||||
req.clean.query = params; |
||||
return { |
||||
errors: [], |
||||
warnings: [] |
||||
}; |
||||
} |
||||
]; |
||||
|
||||
var expected_req = { |
||||
query: { |
||||
value: 'query value' |
||||
}, |
||||
clean: { |
||||
query: { |
||||
value: 'query value' |
||||
} |
||||
}, |
||||
errors: [], |
||||
warnings: [] |
||||
}; |
||||
|
||||
sanitizeAll(req, sanitizers, function(){ |
||||
t.deepEquals(req, expected_req); |
||||
t.end(); |
||||
}); |
||||
|
||||
}); |
||||
|
||||
test('an empty object should be passed to individual sanitizers when req.query is unavailable', function(t) { |
||||
var req = {}; |
||||
var sanitizers = [ |
||||
function(params) { |
||||
if (Object.keys(params).length === 0) { |
||||
req.clean.empty_object_was_passed = true; |
||||
} |
||||
|
||||
return { |
||||
errors: [], |
||||
warnings: [] |
||||
}; |
||||
} |
||||
]; |
||||
|
||||
var expected_req = { |
||||
clean: { |
||||
empty_object_was_passed: true |
||||
}, |
||||
errors: [], |
||||
warnings: [] |
||||
}; |
||||
|
||||
sanitizeAll(req, sanitizers, function(){ |
||||
t.deepEquals(req, expected_req); |
||||
t.end(); |
||||
}); |
||||
|
||||
}); |
||||
|
||||
}; |
||||
|
||||
module.exports.all = function (tape, common) { |
||||
|
||||
function test(name, testFunction) { |
||||
return tape('SANITIZE sanitizeAll ' + name, testFunction); |
||||
} |
||||
|
||||
for( var testCase in module.exports.tests ){ |
||||
module.exports.tests[testCase](test, common); |
||||
} |
||||
}; |
@ -0,0 +1,121 @@
|
||||
var proxyquire = require('proxyquire').noCallThru(); |
||||
|
||||
module.exports.tests = {}; |
||||
|
||||
module.exports.tests.sanitize = function(test, common) { |
||||
test('verify that all sanitisers were called as expected when `res` is undefined', function(t) { |
||||
var called_sanitisers = []; |
||||
|
||||
// rather than re-verify the functionality of all the sanitisers, this test just verifies that they
|
||||
// were all called correctly
|
||||
var search = proxyquire('../../../sanitiser/search_fallback', { |
||||
'../sanitiser/_text_addressit': function() { |
||||
called_sanitisers.push('_text_addressit'); |
||||
return { errors: [], warnings: [] }; |
||||
} |
||||
}); |
||||
|
||||
var expected_sanitisers = [ |
||||
'_text_addressit' |
||||
]; |
||||
|
||||
var req = {}; |
||||
|
||||
search.middleware(req, undefined, function(){ |
||||
t.deepEquals(called_sanitisers, expected_sanitisers); |
||||
t.end(); |
||||
}); |
||||
|
||||
}); |
||||
|
||||
test('verify that all sanitisers were called as expected when `res` has no `data` property', function(t) { |
||||
var called_sanitisers = []; |
||||
|
||||
// rather than re-verify the functionality of all the sanitisers, this test just verifies that they
|
||||
// were all called correctly
|
||||
var search = proxyquire('../../../sanitiser/search_fallback', { |
||||
'../sanitiser/_text_addressit': function() { |
||||
called_sanitisers.push('_text_addressit'); |
||||
return { errors: [], warnings: [] }; |
||||
} |
||||
}); |
||||
|
||||
var expected_sanitisers = [ |
||||
'_text_addressit' |
||||
]; |
||||
|
||||
var req = {}; |
||||
var res = {}; |
||||
|
||||
search.middleware(req, res, function(){ |
||||
t.deepEquals(called_sanitisers, expected_sanitisers); |
||||
t.end(); |
||||
}); |
||||
|
||||
}); |
||||
|
||||
test('verify that all sanitisers were called as expected when res.data is empty', function(t) { |
||||
var called_sanitisers = []; |
||||
|
||||
// rather than re-verify the functionality of all the sanitisers, this test just verifies that they
|
||||
// were all called correctly
|
||||
var search = proxyquire('../../../sanitiser/search_fallback', { |
||||
'../sanitiser/_text_addressit': function() { |
||||
called_sanitisers.push('_text_addressit'); |
||||
return { errors: [], warnings: [] }; |
||||
} |
||||
}); |
||||
|
||||
var expected_sanitisers = [ |
||||
'_text_addressit' |
||||
]; |
||||
|
||||
var req = {}; |
||||
var res = { |
||||
data: [] |
||||
}; |
||||
|
||||
search.middleware(req, res, function(){ |
||||
t.deepEquals(called_sanitisers, expected_sanitisers); |
||||
t.end(); |
||||
}); |
||||
|
||||
}); |
||||
|
||||
test('non-empty res.data should not call the _text_autocomplete sanitiser', function(t) { |
||||
var called_sanitisers = []; |
||||
|
||||
// rather than re-verify the functionality of all the sanitisers, this test just verifies that they
|
||||
// were all called correctly
|
||||
var search = proxyquire('../../../sanitiser/search_fallback', { |
||||
'../sanitiser/_text_autocomplete': function() { |
||||
throw new Error('_text_autocomplete sanitiser should not have been called'); |
||||
} |
||||
}); |
||||
|
||||
var expected_sanitisers = []; |
||||
|
||||
var req = {}; |
||||
var res = { |
||||
data: [{}] |
||||
}; |
||||
|
||||
search.middleware(req, res, function(){ |
||||
t.deepEquals(called_sanitisers, expected_sanitisers); |
||||
t.end(); |
||||
}); |
||||
|
||||
}); |
||||
|
||||
}; |
||||
|
||||
module.exports.all = function (tape, common) { |
||||
|
||||
function test(name, testFunction) { |
||||
return tape('SANITIZE /search_fallback ' + name, testFunction); |
||||
} |
||||
|
||||
for( var testCase in module.exports.tests ){ |
||||
module.exports.tests[testCase](test, common); |
||||
} |
||||
}; |
Loading…
Reference in new issue