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 = { |
module.exports = { |
||||||
'query': { |
'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': { |
'function_score': { |
||||||
'query': { |
'query': { |
||||||
'match': { |
'filtered': { |
||||||
'phrase.default': { |
'query': { |
||||||
'query': 'test', |
'bool': { |
||||||
'analyzer': 'peliasPhrase', |
'should': [ |
||||||
'type': 'phrase', |
{ |
||||||
'slop': 2, |
'bool': { |
||||||
'boost': 1 |
'_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, |
'max_boost': 20, |
||||||
'score_mode': 'first', |
'functions': [ |
||||||
'boost_mode': 'replace', |
{ |
||||||
'functions': [{ |
|
||||||
'field_value_factor': { |
'field_value_factor': { |
||||||
'modifier': 'log1p', |
'modifier': 'log1p', |
||||||
'field': 'popularity', |
'field': 'popularity', |
||||||
'missing': 1 |
'missing': 1 |
||||||
}, |
}, |
||||||
'weight': 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': { |
'field_value_factor': { |
||||||
'modifier': 'log1p', |
'modifier': 'log1p', |
||||||
'field': 'population', |
'field': 'population', |
||||||
'missing': 1 |
'missing': 1 |
||||||
}, |
}, |
||||||
'weight': 2 |
'weight': 2 |
||||||
}] |
|
||||||
} |
} |
||||||
}], |
], |
||||||
'filter': [ |
'score_mode': 'avg', |
||||||
{ |
'boost_mode': 'multiply' |
||||||
'terms': { |
|
||||||
'layer': [ |
|
||||||
'test' |
|
||||||
] |
|
||||||
} |
} |
||||||
|
}, |
||||||
|
'size': 10, |
||||||
|
'track_scores': true, |
||||||
|
'sort': [ |
||||||
|
{ |
||||||
|
'population': { |
||||||
|
'order': 'desc' |
||||||
} |
} |
||||||
] |
}, |
||||||
|
{ |
||||||
|
'popularity': { |
||||||
|
'order': 'desc' |
||||||
} |
} |
||||||
}, |
}, |
||||||
'sort': [ '_score' ], |
'_score' |
||||||
'size': 10, |
] |
||||||
'track_scores': true |
|
||||||
}; |
}; |
||||||
|
@ -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 = { |
module.exports = { |
||||||
'query': { |
'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': { |
'function_score': { |
||||||
'query': { |
'query': { |
||||||
'match': { |
'filtered': { |
||||||
'phrase.default': { |
'query': { |
||||||
'query': 'test', |
'bool': { |
||||||
'analyzer': 'peliasPhrase', |
'should': [ |
||||||
'type': 'phrase', |
{ |
||||||
'slop': 2, |
'bool': { |
||||||
'boost': 1 |
'_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, |
'max_boost': 20, |
||||||
'score_mode': 'first', |
'functions': [ |
||||||
'boost_mode': 'replace', |
{ |
||||||
'functions': [{ |
|
||||||
'field_value_factor': { |
'field_value_factor': { |
||||||
'modifier': 'log1p', |
'modifier': 'log1p', |
||||||
'field': 'popularity', |
'field': 'popularity', |
||||||
'missing': 1 |
'missing': 1 |
||||||
}, |
}, |
||||||
'weight': 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': { |
'field_value_factor': { |
||||||
'modifier': 'log1p', |
'modifier': 'log1p', |
||||||
'field': 'population', |
'field': 'population', |
||||||
'missing': 1 |
'missing': 1 |
||||||
}, |
}, |
||||||
'weight': 2 |
'weight': 2 |
||||||
}] |
|
||||||
} |
|
||||||
}], |
|
||||||
'filter': [{ |
|
||||||
'terms': { |
|
||||||
'category': ['retail', 'food'] |
|
||||||
} |
} |
||||||
}] |
], |
||||||
|
'score_mode': 'avg', |
||||||
|
'boost_mode': 'multiply' |
||||||
} |
} |
||||||
}, |
}, |
||||||
'size': 20, |
'size': 20, |
||||||
'track_scores': true, |
'track_scores': true, |
||||||
'sort': [ |
'sort': [ |
||||||
|
{ |
||||||
|
'population': { |
||||||
|
'order': 'desc' |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
'popularity': { |
||||||
|
'order': 'desc' |
||||||
|
} |
||||||
|
}, |
||||||
'_score' |
'_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 = { |
module.exports = { |
||||||
'query': { |
'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': { |
'function_score': { |
||||||
'query': { |
'query': { |
||||||
'match': { |
'filtered': { |
||||||
'phrase.default': { |
'query': { |
||||||
'query': 'test', |
'bool': { |
||||||
'analyzer': 'peliasPhrase', |
'should': [ |
||||||
'type': 'phrase', |
{ |
||||||
'slop': 2, |
'bool': { |
||||||
'boost': 1 |
'_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, |
'max_boost': 20, |
||||||
'score_mode': 'first', |
'functions': [ |
||||||
'boost_mode': 'replace', |
{ |
||||||
'functions': [{ |
|
||||||
'field_value_factor': { |
'field_value_factor': { |
||||||
'modifier': 'log1p', |
'modifier': 'log1p', |
||||||
'field': 'popularity', |
'field': 'popularity', |
||||||
'missing': 1 |
'missing': 1 |
||||||
}, |
}, |
||||||
'weight': 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': { |
'field_value_factor': { |
||||||
'modifier': 'log1p', |
'modifier': 'log1p', |
||||||
'field': 'population', |
'field': 'population', |
||||||
'missing': 1 |
'missing': 1 |
||||||
}, |
}, |
||||||
'weight': 2 |
'weight': 2 |
||||||
}] |
|
||||||
} |
|
||||||
}], |
|
||||||
'filter': [{ |
|
||||||
'terms': { |
|
||||||
'source': ['test_source'] |
|
||||||
} |
} |
||||||
}] |
], |
||||||
|
'score_mode': 'avg', |
||||||
|
'boost_mode': 'multiply' |
||||||
} |
} |
||||||
}, |
}, |
||||||
'sort': [ '_score' ], |
|
||||||
'size': 20, |
'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