From 32684e00134549c321b5adf352d6c9da65b0d5ab Mon Sep 17 00:00:00 2001 From: Julian Simioni Date: Tue, 11 Sep 2018 16:47:04 -0400 Subject: [PATCH] feat(query): Add support for custom boosts to search endpoint This adds support for custom boosts to the addressit-style search queries. The newer libpostal based queries do not include this functionality since they can only query for addresses. --- query/search_original.js | 7 ++ .../fixture/search_with_custom_boosts.json | 107 ++++++++++++++++++ test/unit/query/search_with_custom_boosts.js | 55 +++++++++ test/unit/run.js | 1 + 4 files changed, 170 insertions(+) create mode 100644 test/unit/fixture/search_with_custom_boosts.json create mode 100644 test/unit/query/search_with_custom_boosts.js diff --git a/query/search_original.js b/query/search_original.js index 381e7b86..a627a8d9 100644 --- a/query/search_original.js +++ b/query/search_original.js @@ -3,9 +3,13 @@ const defaults = require('./search_defaults'); const textParser = require('./text_parser_addressit'); const check = require('check-types'); const logger = require('pelias-logger').get('api'); +const config = require('pelias-config').generate().api; var placeTypes = require('../helper/placeTypes'); +var views = { + custom_boosts: require('./view/boost_sources_and_layers'), +}; // 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 @@ -39,6 +43,9 @@ query.score( peliasQuery.view.admin('country_a') ); query.score( peliasQuery.view.admin('region_a') ); query.score( peliasQuery.view.admin_multi_match(adminFields, 'peliasAdmin') ); +const boostConfig = config.customBoosts || {}; +query.score( views.custom_boosts(config.customBoosts) ); + // non-scoring hard filters query.filter( peliasQuery.view.boundary_circle ); query.filter( peliasQuery.view.boundary_rect ); diff --git a/test/unit/fixture/search_with_custom_boosts.json b/test/unit/fixture/search_with_custom_boosts.json new file mode 100644 index 00000000..06e2ca3b --- /dev/null +++ b/test/unit/fixture/search_with_custom_boosts.json @@ -0,0 +1,107 @@ +{ + "type": "search_original", + "body": { + "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 + }] + } + }, { + "bool": { + "should": [ + { + "constant_score": { + "boost": 5, + "query": { + "term": { + "source": "openstreetmap" + } + } + } + }, + { + "constant_score": { + "boost": 3, + "query": { + "term": { + "layer": "transit" + } + } + } + } + ] + } + }] + } + }, + "sort": [ "_score" ], + "size": 10, + "track_scores": true + } +} diff --git a/test/unit/query/search_with_custom_boosts.js b/test/unit/query/search_with_custom_boosts.js new file mode 100644 index 00000000..af751444 --- /dev/null +++ b/test/unit/query/search_with_custom_boosts.js @@ -0,0 +1,55 @@ +const proxyquire = require('proxyquire'); + +module.exports.tests = {}; + +module.exports.tests.query = function(test, common) { + test('valid search with custom boosts', function(t) { + const clean = { + tokens: ['foo'], + tokens_complete: ['foo'], + tokens_incomplete: [], + text: 'test', + querySize: 10 + }; + + const config_with_boosts = { + generate: function() { + return { + api: { + customBoosts: { + source: { + openstreetmap: 5 + }, + layer: { + transit: 3 + } + } + } + }; + } + }; + + var expected_query = require('../fixture/search_with_custom_boosts.json'); + + const search_query_module = proxyquire('../../../query/search_original', { + 'pelias-config': config_with_boosts + }); + + const actual_query = JSON.parse( JSON.stringify( search_query_module(clean) ) ); + console.log(JSON.stringify(actual_query.body.query.bool, null, 2)); + + t.deepEqual(actual_query, expected_query, 'query as expected'); + t.pass(); + t.end(); + }); +}; + +module.exports.all = function (tape, common) { + function test(name, testFunction) { + return tape('search with custom boosts query ' + name, testFunction); + } + + for( var testCase in module.exports.tests ){ + module.exports.tests[testCase](test, common); + } +}; diff --git a/test/unit/run.js b/test/unit/run.js index 7b089819..394c02ec 100644 --- a/test/unit/run.js +++ b/test/unit/run.js @@ -68,6 +68,7 @@ var tests = [ require('./query/reverse'), require('./query/reverse_defaults'), require('./query/search'), + require('./query/search_with_custom_boosts'), require('./query/search_defaults'), require('./query/search_original'), require('./query/structured_geocoding'),