diff --git a/helper/geojsonify_place_details.js b/helper/geojsonify_place_details.js index 44e827d5..d9a000ee 100644 --- a/helper/geojsonify_place_details.js +++ b/helper/geojsonify_place_details.js @@ -7,6 +7,7 @@ var DETAILS_PROPS = [ { name: 'housenumber', type: 'string' }, { name: 'street', type: 'string' }, { name: 'postalcode', type: 'string' }, + { name: 'postalcode_gid', type: 'string' }, { name: 'confidence', type: 'default' }, { name: 'match_type', type: 'string' }, { name: 'distance', type: 'default' }, diff --git a/helper/placeTypes.js b/helper/placeTypes.js index c9550ce7..defc9274 100644 --- a/helper/placeTypes.js +++ b/helper/placeTypes.js @@ -8,5 +8,6 @@ module.exports = [ 'localadmin', 'locality', 'borough', - 'neighbourhood' + 'neighbourhood', + 'postalcode' ]; diff --git a/helper/type_mapping.js b/helper/type_mapping.js index c43a96bb..7b9de5a0 100644 --- a/helper/type_mapping.js +++ b/helper/type_mapping.js @@ -51,7 +51,7 @@ var LAYERS_BY_SOURCE = { 'locality','borough', 'neighbourhood', 'venue' ], whosonfirst: [ 'continent', 'country', 'dependency', 'macroregion', 'region', 'locality', 'localadmin', 'macrocounty', 'county', 'macrohood', 'borough', - 'neighbourhood', 'microhood', 'disputed', 'venue'] + 'neighbourhood', 'microhood', 'disputed', 'venue', 'postalcode'] }; /* @@ -62,7 +62,7 @@ var LAYERS_BY_SOURCE = { var LAYER_ALIASES = { 'coarse': [ 'continent', 'country', 'dependency', 'macroregion', 'region', 'locality', 'localadmin', 'macrocounty', 'county', 'macrohood', 'borough', - 'neighbourhood', 'microhood', 'disputed'] + 'neighbourhood', 'microhood', 'disputed', 'postalcode' ] }; // create a list of all layers by combining each entry from LAYERS_BY_SOURCE diff --git a/middleware/trimByGranularity.js b/middleware/trimByGranularity.js index da4ef4f9..06bf9141 100644 --- a/middleware/trimByGranularity.js +++ b/middleware/trimByGranularity.js @@ -19,6 +19,7 @@ var layers = [ 'street', 'neighbourhood', 'borough', + 'postalcode', 'locality', 'localadmin', 'county', diff --git a/package.json b/package.json index 64ded821..12c6bbc7 100644 --- a/package.json +++ b/package.json @@ -55,8 +55,8 @@ "pelias-config": "2.7.1", "pelias-labels": "1.5.1", "pelias-logger": "0.1.0", - "pelias-model": "4.4.0", - "pelias-query": "8.12.0", + "pelias-model": "git://github.com/pelias/model.git#add-postalcode", + "pelias-query": "git://github.com/pelias/query.git#add-postalcodes", "pelias-text-analyzer": "1.7.0", "retry": "^0.10.1", "stats-lite": "2.0.3", diff --git a/query/search.js b/query/search.js index 48b47f31..91c22299 100644 --- a/query/search.js +++ b/query/search.js @@ -144,7 +144,10 @@ function generateQuery( clean ){ } function getQuery(vs) { - if (hasStreet(vs) || isCityStateOnlyWithOptionalCountry(vs) || isCityCountryOnly(vs)) { + if (hasStreet(vs) || + isCityStateOnlyWithOptionalCountry(vs) || + isCityCountryOnly(vs) || + isPostalCodeOnly(vs)) { return { type: 'fallback', body: fallbackQuery.render(vs) @@ -188,4 +191,18 @@ function isCityCountryOnly(vs) { } +function isPostalCodeOnly(vs) { + var isSet = (layer) => { + return 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); + +} + module.exports = generateQuery; diff --git a/test/unit/fixture/search_fallback.js b/test/unit/fixture/search_fallback.js index 857e47e9..3835cadb 100644 --- a/test/unit/fixture/search_fallback.js +++ b/test/unit/fixture/search_fallback.js @@ -193,6 +193,75 @@ module.exports = { } } }, + { + 'bool': { + '_name': 'fallback.postalcode', + 'must': [ + { + 'multi_match': { + 'query': 'postalcode value', + 'type': 'phrase', + 'fields': [ + 'parent.postalcode' + ] + } + }, + { + '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': 'postalcode' + } + } + } + }, { 'bool': { '_name': 'fallback.street', diff --git a/test/unit/fixture/search_fallback_postalcode_only.js b/test/unit/fixture/search_fallback_postalcode_only.js new file mode 100644 index 00000000..4519e166 --- /dev/null +++ b/test/unit/fixture/search_fallback_postalcode_only.js @@ -0,0 +1,68 @@ +module.exports = { + 'query': { + 'function_score': { + 'query': { + 'filtered': { + 'query': { + 'bool': { + 'should': [ + { + 'bool': { + '_name': 'fallback.postalcode', + 'must': [ + { + 'multi_match': { + 'query': '90210', + 'type': 'phrase', + 'fields': [ + 'parent.postalcode' + ] + } + } + ], + 'filter': { + 'term': { + 'layer': 'postalcode' + } + } + } + } + ] + } + }, + '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': [ + '_score' + ] +}; diff --git a/test/unit/helper/type_mapping.js b/test/unit/helper/type_mapping.js index a9ec4721..d67218c5 100644 --- a/test/unit/helper/type_mapping.js +++ b/test/unit/helper/type_mapping.js @@ -14,7 +14,7 @@ module.exports.tests.interfaces = function(test, common) { t.deepEquals(type_mapping.layer_mapping.coarse, [ 'continent', 'country', 'dependency', 'macroregion', 'region', 'locality', 'localadmin', 'macrocounty', 'county', 'macrohood', - 'borough', 'neighbourhood', 'microhood', 'disputed' ]); + 'borough', 'neighbourhood', 'microhood', 'disputed', 'postalcode' ]); t.end(); }); diff --git a/test/unit/query/search.js b/test/unit/query/search.js index 1f312d0d..aa582082 100644 --- a/test/unit/query/search.js +++ b/test/unit/query/search.js @@ -603,6 +603,25 @@ module.exports.tests.city_country = function(test, common) { }); + test('valid postalcode only search', function(t) { + var clean = { + parsed_text: { + postalcode: '90210' + }, + text: '90210' + }; + + var query = generate(clean); + + var compiled = JSON.parse( JSON.stringify( query ) ); + var expected = require('../fixture/search_fallback_postalcode_only'); + + t.deepEqual(compiled.type, 'fallback', 'query type set'); + t.deepEqual(compiled.body, expected, 'search_fallback_postalcode_only'); + t.end(); + }); + + }; module.exports.all = function (tape, common) { diff --git a/test/unit/sanitizer/_layers.js b/test/unit/sanitizer/_layers.js index 5792e947..5a0c0693 100644 --- a/test/unit/sanitizer/_layers.js +++ b/test/unit/sanitizer/_layers.js @@ -43,7 +43,7 @@ module.exports.tests.sanitize_layers = function(test, common) { var admin_layers = [ 'continent', 'country', 'dependency', 'macroregion', 'region', 'locality', 'localadmin', 'macrocounty', 'county', - 'macrohood', 'borough', 'neighbourhood', 'microhood', 'disputed' ]; + 'macrohood', 'borough', 'neighbourhood', 'microhood', 'disputed', 'postalcode' ]; t.deepEqual(clean.layers, admin_layers, 'coarse layers set'); t.end(); @@ -78,7 +78,7 @@ module.exports.tests.sanitize_layers = function(test, common) { var expected_layers = [ 'continent', 'country', 'dependency', 'macroregion', 'region', 'locality', 'localadmin', 'macrocounty', 'county', - 'macrohood', 'borough', 'neighbourhood', 'microhood', 'disputed' ]; + 'macrohood', 'borough', 'neighbourhood', 'microhood', 'disputed', 'postalcode' ]; t.deepEqual(clean.layers, expected_layers, 'coarse + regular layers set'); t.end(); @@ -115,7 +115,7 @@ module.exports.tests.sanitize_layers = function(test, common) { var coarse_layers = [ 'continent', 'country', 'dependency', 'macroregion', 'region', 'locality', 'localadmin', 'macrocounty', 'county', 'macrohood', 'borough', 'neighbourhood', 'microhood', - 'disputed' ]; + 'disputed', 'postalcode' ]; var venue_layers = [ 'venue' ]; var expected_layers = venue_layers.concat(coarse_layers);