mirror of https://github.com/pelias/api.git
9 changed files with 396 additions and 6 deletions
@ -0,0 +1,59 @@ |
|||||||
|
const _ = require('lodash'); |
||||||
|
const iso3166 = require('iso3166-1'); |
||||||
|
const util = require('../util/arrayHelper'); |
||||||
|
|
||||||
|
/* |
||||||
|
this function returns an object that denotes an intersection of form: |
||||||
|
{ |
||||||
|
street1: value1, |
||||||
|
street2: value2 |
||||||
|
} |
||||||
|
*/ |
||||||
|
function parseIntersections(text) { |
||||||
|
var str1 = '', str2 = ''; |
||||||
|
if(text.trim().length > 1) { |
||||||
|
var words = text.toLowerCase().split(' '); |
||||||
|
// remove all the whitespaces
|
||||||
|
words = util.removeWhitespaceElements(words); |
||||||
|
words = util.EWStreetsSanitizer(words); |
||||||
|
words = util.addOrdinality(words); |
||||||
|
// only treat input as intersection if contains '&' or 'and'
|
||||||
|
const delimiter = _.includes(text, '&') ? '&' : 'and'; |
||||||
|
const delimiterIndex = words.indexOf(delimiter); |
||||||
|
|
||||||
|
str1 = util.wordsToSentence(words, 0, delimiterIndex); |
||||||
|
str2 = util.wordsToSentence(words, delimiterIndex+1, words.length); |
||||||
|
} else { |
||||||
|
throw 'Missing streets in the intersection'; |
||||||
|
} |
||||||
|
return { street1: str1, street2: str2 }; |
||||||
|
} |
||||||
|
|
||||||
|
function setup(should_execute) { |
||||||
|
function controller( req, res, next ){ |
||||||
|
// bail early if req/res don't pass conditions for execution
|
||||||
|
if (!should_execute(req, res)) { |
||||||
|
return next(); |
||||||
|
} |
||||||
|
|
||||||
|
// parse text with query parser
|
||||||
|
//const parsed_text = text_analyzer.parse(req.clean.text);
|
||||||
|
const parsed_text = parseIntersections(req.clean.text); |
||||||
|
|
||||||
|
if (parsed_text !== undefined) { |
||||||
|
// if a known ISO2 country was parsed, convert it to ISO3
|
||||||
|
if (_.has(parsed_text, 'country') && iso3166.is2(_.toUpper(parsed_text.country))) { |
||||||
|
parsed_text.country = iso3166.to3(_.toUpper(parsed_text.country)); |
||||||
|
} |
||||||
|
|
||||||
|
req.clean.parsed_text = parsed_text; |
||||||
|
} |
||||||
|
|
||||||
|
return next(); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
return controller; |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = setup; |
@ -0,0 +1,5 @@ |
|||||||
|
const _ = require('lodash'); |
||||||
|
|
||||||
|
module.exports = (request, response) => { |
||||||
|
return _.includes(request.query.text, '&') || _.includes(request.query.text, ' and '); |
||||||
|
}; |
@ -0,0 +1,220 @@ |
|||||||
|
/* eslint-disable */ |
||||||
|
|
||||||
|
//
|
||||||
|
// 'use strict';
|
||||||
|
//
|
||||||
|
// const peliasQuery = require('pelias-query');
|
||||||
|
// const defaults = require('./search_defaults');
|
||||||
|
// const textParser = require('./text_parser');
|
||||||
|
// const check = require('check-types');
|
||||||
|
// const logger = require('pelias-logger').get('api');
|
||||||
|
//
|
||||||
|
// //------------------------------
|
||||||
|
// // general-purpose search query
|
||||||
|
// //------------------------------
|
||||||
|
// var fallbackQuery = new peliasQuery.layout.FallbackQuery();
|
||||||
|
//
|
||||||
|
// // scoring boost
|
||||||
|
// fallbackQuery.score( peliasQuery.view.focus_only_function( peliasQuery.view.phrase ) );
|
||||||
|
// fallbackQuery.score( peliasQuery.view.popularity_only_function );
|
||||||
|
// fallbackQuery.score( peliasQuery.view.population_only_function );
|
||||||
|
// // --------------------------------
|
||||||
|
//
|
||||||
|
// // non-scoring hard filters
|
||||||
|
// fallbackQuery.filter( peliasQuery.view.boundary_country );
|
||||||
|
// fallbackQuery.filter( peliasQuery.view.boundary_circle );
|
||||||
|
// fallbackQuery.filter( peliasQuery.view.boundary_rect );
|
||||||
|
// fallbackQuery.filter( peliasQuery.view.sources );
|
||||||
|
// fallbackQuery.filter( peliasQuery.view.layers );
|
||||||
|
// fallbackQuery.filter( peliasQuery.view.categories );
|
||||||
|
// // --------------------------------
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// map request variables to query variables for all inputs
|
||||||
|
// provided by this HTTP request.
|
||||||
|
// **/
|
||||||
|
// function generateQuery( clean ){
|
||||||
|
//
|
||||||
|
// console.log("I am in intersections query");
|
||||||
|
//
|
||||||
|
// const vs = new peliasQuery.Vars( defaults );
|
||||||
|
//
|
||||||
|
// let logStr = '[query:search] [parser:intersections_parser] ';
|
||||||
|
//
|
||||||
|
// // input text
|
||||||
|
// vs.var( 'input:name', clean.text );
|
||||||
|
//
|
||||||
|
// // sources
|
||||||
|
// if( check.array(clean.sources) && clean.sources.length ) {
|
||||||
|
// vs.var( 'sources', clean.sources);
|
||||||
|
// logStr += '[param:sources] ';
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // layers
|
||||||
|
// if( check.array(clean.layers) && clean.layers.length ) {
|
||||||
|
// vs.var('layers', clean.layers);
|
||||||
|
// logStr += '[param:layers] ';
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // categories
|
||||||
|
// if (clean.categories) {
|
||||||
|
// vs.var('input:categories', clean.categories);
|
||||||
|
// logStr += '[param:categories] ';
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // size
|
||||||
|
// if( clean.querySize ) {
|
||||||
|
// vs.var( 'size', clean.querySize );
|
||||||
|
// logStr += '[param: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']
|
||||||
|
// });
|
||||||
|
// logStr += '[param:focus_point] ';
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 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']
|
||||||
|
// });
|
||||||
|
// logStr += '[param:boundary_rect] ';
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 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'
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// logStr += '[param:boundary_circle] ';
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // boundary country
|
||||||
|
// if( check.string(clean['boundary.country']) ){
|
||||||
|
// vs.set({
|
||||||
|
// 'boundary:country': clean['boundary.country']
|
||||||
|
// });
|
||||||
|
// logStr += '[param:boundary_country] ';
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // run the address parser
|
||||||
|
// if( clean.parsed_text ){
|
||||||
|
// textParser( clean.parsed_text, vs );
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// var q = getQuery(vs);
|
||||||
|
//
|
||||||
|
// //console.log(JSON.stringify(q, null, 2));
|
||||||
|
//
|
||||||
|
// if (q !== undefined) {
|
||||||
|
// logger.info(logStr);
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// logger.info('[parser:intersections] query type not supported');
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return q;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// function getQuery(vs) {
|
||||||
|
//
|
||||||
|
// logger.info(`[query:search] [search_input_type:${determineQueryType(vs)}]`);
|
||||||
|
//
|
||||||
|
// if (hasStreet(vs) || isPostalCodeOnly(vs)) {
|
||||||
|
// return {
|
||||||
|
// type: 'fallback',
|
||||||
|
// body: fallbackQuery.render(vs)
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // returning undefined is a signal to a later step that the addressit-parsed
|
||||||
|
// // query should be queried for
|
||||||
|
// return undefined;
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// function determineQueryType(vs) {
|
||||||
|
// if (vs.isset('input:housenumber') && vs.isset('input:street')) {
|
||||||
|
// return 'address';
|
||||||
|
// }
|
||||||
|
// else if (vs.isset('input:street')) {
|
||||||
|
// return 'street';
|
||||||
|
// }
|
||||||
|
// else if (vs.isset('input:street1') || vs.isset('input:street2')) {
|
||||||
|
// return 'intersection';
|
||||||
|
// }
|
||||||
|
// else if (vs.isset('input:query')) {
|
||||||
|
// return 'venue';
|
||||||
|
// }
|
||||||
|
// else if (['neighbourhood', 'borough', 'postcode', 'county', 'region','country'].some(
|
||||||
|
// layer => vs.isset(`input:${layer}`)
|
||||||
|
// )) {
|
||||||
|
// return 'admin';
|
||||||
|
// }
|
||||||
|
// return 'other';
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// function hasStreet(vs) {
|
||||||
|
// return vs.isset('input:street') || vs.isset('input:street1') || vs.isset('input:street2');
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// function isPostalCodeOnly(vs) {
|
||||||
|
// var isSet = layer => vs.isset(`input:${layer}`);
|
||||||
|
//
|
||||||
|
// var allowedFields = ['postcode'];
|
||||||
|
// var disallowedFields = ['query', 'category', 'housenumber', 'street',
|
||||||
|
// 'neighbourhood', 'borough', 'county', 'region', 'country'];
|
||||||
|
//
|
||||||
|
// return allowedFields.every(isSet) &&
|
||||||
|
// !disallowedFields.some(isSet);
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
|
||||||
|
function generateQuery(clean) { |
||||||
|
return { |
||||||
|
type: 'fallback', |
||||||
|
body: { |
||||||
|
'size': 2, |
||||||
|
'query': { |
||||||
|
'or': [{ |
||||||
|
'bool' : { |
||||||
|
'must': [ |
||||||
|
{ 'match': { 'layer' : 'intersection'} }, |
||||||
|
{ 'match': { 'address_parts.street1' : clean.parsed_text.street1} }, |
||||||
|
{ 'match': { 'address_parts.street2' : clean.parsed_text.street2} } |
||||||
|
] |
||||||
|
} }, { |
||||||
|
'bool' : { |
||||||
|
'must': [ |
||||||
|
{ 'match': { 'layer' : 'intersection'} }, |
||||||
|
{ 'match': { 'address_parts.street1' : clean.parsed_text.street2} }, |
||||||
|
{ 'match': { 'address_parts.street2' : clean.parsed_text.street1} } |
||||||
|
] |
||||||
|
} } |
||||||
|
] |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = generateQuery; |
@ -0,0 +1,75 @@ |
|||||||
|
module.exports.removeWhitespaceElements = function (arr) { |
||||||
|
for(let i = 0; i < arr.length; i++) { |
||||||
|
if(arr[i] === '') { |
||||||
|
arr.splice(i, 1); |
||||||
|
i--; |
||||||
|
} |
||||||
|
} |
||||||
|
return arr; |
||||||
|
}; |
||||||
|
|
||||||
|
// intended for intersections only
|
||||||
|
// this function turns '77' into '77th', '3' into '3rd', etc
|
||||||
|
module.exports.addOrdinality = function (arr) { |
||||||
|
arr.forEach( function (elmnt, index) { |
||||||
|
// is it only numbers
|
||||||
|
let isNum = /^\d+$/.test(elmnt); |
||||||
|
if(isNum) { |
||||||
|
switch(elmnt[elmnt.length-1]){ |
||||||
|
case '1': |
||||||
|
elmnt += 'st'; |
||||||
|
arr[index] = elmnt; |
||||||
|
break; |
||||||
|
case '2': |
||||||
|
elmnt += 'nd'; |
||||||
|
arr[index] = elmnt; |
||||||
|
break; |
||||||
|
case '3': |
||||||
|
elmnt += 'rd'; |
||||||
|
arr[index] = elmnt; |
||||||
|
break; |
||||||
|
default : |
||||||
|
elmnt += 'th'; |
||||||
|
arr[index] = elmnt; |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
return arr; |
||||||
|
}; |
||||||
|
|
||||||
|
// intended to do the conversions like:
|
||||||
|
// 'w28' -> 'West 28'
|
||||||
|
// 'e17' -> 'East 17'
|
||||||
|
module.exports.EWStreetsSanitizer = function(arr){ |
||||||
|
const mapping = { |
||||||
|
e : 'East', |
||||||
|
w : 'West' |
||||||
|
}; |
||||||
|
|
||||||
|
for (let i = 0; i < arr.length; i++) { |
||||||
|
if (arr[i].length > 1) { |
||||||
|
if((arr[i][0].toLowerCase() === 'e' || arr[i][0].toLowerCase() === 'w') && /^\d$/.test(arr[i][1])) { |
||||||
|
let streetNum = arr[i].substring(1); |
||||||
|
arr[i] = mapping[arr[i][0]]; |
||||||
|
if(i+1 === arr.length) { |
||||||
|
arr.push(streetNum); |
||||||
|
} else { |
||||||
|
arr.splice(i+1,0,streetNum); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return arr; |
||||||
|
}; |
||||||
|
|
||||||
|
module.exports.wordsToSentence = function (arr, start, end) { |
||||||
|
var sentence = ''; |
||||||
|
for (let i = start; i < end; i++) { |
||||||
|
sentence += arr[i]; |
||||||
|
if (i < (end - 1)) { |
||||||
|
sentence += ' '; |
||||||
|
} |
||||||
|
} |
||||||
|
return sentence; |
||||||
|
}; |
Loading…
Reference in new issue