From 79280ef4bb7d8a53f6d77bad42d2cd80f53a93f5 Mon Sep 17 00:00:00 2001 From: Joxit Date: Fri, 5 Feb 2021 11:47:12 +0100 Subject: [PATCH] feat(assignLabels): improve duplicate label handling --- middleware/assignLabels.js | 43 ++++++++++++++++++++++++++-- package.json | 2 +- test/unit/middleware/assignLabels.js | 14 +++++---- 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/middleware/assignLabels.js b/middleware/assignLabels.js index 9ea6d74f2..e5418cc2c 100644 --- a/middleware/assignLabels.js +++ b/middleware/assignLabels.js @@ -1,4 +1,5 @@ -const defaultLabelGenerator = require('pelias-labels'); +const defaultLabelGenerator = require('pelias-labels').partsGenerator; +const _ = require('lodash'); function setup(labelGenerator) { function middleware(req, res, next) { @@ -8,6 +9,25 @@ function setup(labelGenerator) { return middleware; } +function getLabelFromLayer(parts, layer) { + const part = parts.find(p => p.layer === layer); + return _.get(part, 'label'); +} + +function filterUnambiguousParts(part, second) { + if (part.role === 'required') { + return false; + } + const label = getLabelFromLayer(second.parts, part.layer); + return label && label !== part.label; +} + +function getBestLayers(results) { + const first = results[0]; + const second = results[1]; + return first.parts.filter(p => filterUnambiguousParts(p, second)).map(p => p.layer); +} + function assignLabel(req, res, next, labelGenerator) { // do nothing if there's nothing to process @@ -15,10 +35,29 @@ function assignLabel(req, res, next, labelGenerator) { return next(); } + // This object will help for label deduplication + const dedupLabel = {}; + + // First we assign for all result the default label with all required layers res.data.forEach(function (result) { - result.label = labelGenerator(result); + const { parts, separator } = labelGenerator(result); + result.label = parts.filter(e => e.role === 'required').map(e => e.label).join(separator); + dedupLabel[result.label] = dedupLabel[result.label] || []; + dedupLabel[result.label].push({ result, parts, separator }); }); + // We check all values with more than one entry + Object.values(dedupLabel) + .filter(results => results.length > 1) + .forEach(results => { + // This array will contain all optional layers that should be displayed + const bestLayers = getBestLayers(results); + // We reassign the label with the new value + results.forEach(({ result, parts, separator }) => { + result.label = parts.filter(e => e.role === 'required' || bestLayers.indexOf(e.layer) >= 0).map(e => e.label).join(separator); + }); + }); + next(); } diff --git a/package.json b/package.json index 62ccc8c2c..eac8a4da7 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "morgan": "^1.8.2", "pelias-compare": "^0.1.16", "pelias-config": "^4.0.0", - "pelias-labels": "^1.16.0", + "pelias-labels": "pelias/labels#joxit/feat/with-optional", "pelias-logger": "^1.2.0", "pelias-microservice-wrapper": "^1.7.0", "pelias-model": "^7.0.0", diff --git a/test/unit/middleware/assignLabels.js b/test/unit/middleware/assignLabels.js index ebd7c22a7..1612a078f 100644 --- a/test/unit/middleware/assignLabels.js +++ b/test/unit/middleware/assignLabels.js @@ -1,5 +1,9 @@ var proxyquire = require('proxyquire').noCallThru(); +function partsGenerator(cb) { + return { partsGenerator: cb }; +} + module.exports.tests = {}; module.exports.tests.serialization = function(test, common) { @@ -30,10 +34,10 @@ module.exports.tests.serialization = function(test, common) { test('labels should be assigned to all results', function(t) { var labelGenerator = function(result) { if (result.id === 1) { - return 'label 1'; + return { parts: [{ label: 'label 1', role: 'required' }], separator: ', '}; } if (result.id === 2) { - return 'label 2'; + return { parts: [{ label: 'label 2', role: 'required' }], separator: ', '}; } }; @@ -73,11 +77,11 @@ module.exports.tests.serialization = function(test, common) { test('no explicit labelGenerator supplied should use pelias-labels module', function(t) { var assignLabels = proxyquire('../../../middleware/assignLabels', { - 'pelias-labels': function(result) { + 'pelias-labels': partsGenerator(function(result) { if (result.id === 1) { - return 'label 1'; + return { parts: [{ label: 'label 1', role: 'required' }], separator: ', '}; } - } + }) })(); var input = {