diff --git a/middleware/assignLabels.js b/middleware/assignLabels.js index 630974f2f..f4e46bdcb 100644 --- a/middleware/assignLabels.js +++ b/middleware/assignLabels.js @@ -1,6 +1,6 @@ const _ = require('lodash'); -const defaultLabelGenerator = require('pelias-labels'); +const defaultLabelGenerator = require('pelias-labels').partsGenerator; function setup(labelGenerator) { function middleware(req, res, next) { @@ -10,6 +10,36 @@ function setup(labelGenerator) { return middleware; } +function getLabelFromLayer(labelParts, layer) { + const part = labelParts.find(p => p.layer === layer); + return _.get(part, 'label'); +} + +function filterUnambiguousParts(second) { + return (labelParts) => { + if (labelParts.role === 'required') { + return false; + } + const label = getLabelFromLayer(second.labelParts, labelParts.layer); + return label && label !== labelParts.label; + }; +} + +function getBestLayers(results) { + const bestLayers = new Set(); + const first = results[0]; + // Ensure deduplication based on optional elements even when the first two elements are equals. + for (let i = 1; i < results.length; i++) { + const second = results[i]; + first.labelParts.filter(filterUnambiguousParts(second)).map((p) => bestLayers.add(p.layer)); + if (bestLayers.size > 0) { + // For now, we break as soon as we find a discriminant. + break; + } + } + return bestLayers; +} + function assignLabel(req, res, next, labelGenerator) { // do nothing if there's nothing to process @@ -17,10 +47,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, _.get(req, 'clean.lang.iso6393')); + const { labelParts, separator } = labelGenerator(result, _.get(req, 'clean.lang.iso6393')); + result.label = labelParts.filter(e => e.role === 'required').map(e => e.label).join(separator); + dedupLabel[result.label] = dedupLabel[result.label] || []; + dedupLabel[result.label].push({ result, labelParts, 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, labelParts, separator }) => { + result.label = labelParts.filter(e => e.role === 'required' || bestLayers.has(e.layer)).map(e => e.label).join(separator); + }); + }); + next(); } diff --git a/package.json b/package.json index d2787371f..b76db45c1 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "morgan": "^1.8.2", "pelias-compare": "^0.1.16", "pelias-config": "^5.0.1", - "pelias-labels": "^1.19.0", + "pelias-labels": "pelias/labels#joxit/feat/with-optional", "pelias-logger": "^1.2.0", "pelias-microservice-wrapper": "^1.10.0", "pelias-model": "^9.0.0", diff --git a/test/unit/middleware/assignLabels.js b/test/unit/middleware/assignLabels.js index ebd7c22a7..22ae572d8 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 { labelParts: [{ label: 'label 1', role: 'required' }], separator: ', '}; } if (result.id === 2) { - return 'label 2'; + return { labelParts: [{ 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 { labelParts: [{ label: 'label 1', role: 'required' }], separator: ', '}; } - } + }) })(); var input = {