diff --git a/CHANGELOG.md b/CHANGELOG.md index e094321d52..2beb25d95e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,9 @@ Current ### Changed: +- [Remove restriction for single physical dimension to multiple lookup dimensions](https://github.com/yahoo/fili/pull/112) + * Modified physical dimension name to logical dimension name mapping into a `Map>` instead of `Map` in `PhysicalTable.java` + - [SegmentMetadataLoader include provided request headers](https://github.com/yahoo/fili/pull/106) * `SegmentMetadataLoader` sends requests with the provided request headers in `AsyncDruidWebservice` now * Refactored `AsyncDruidWebserviceSpec` test and added test for checking `getJsonData` includes request headers as well diff --git a/fili-core/src/main/java/com/yahoo/bard/webservice/table/PhysicalTable.java b/fili-core/src/main/java/com/yahoo/bard/webservice/table/PhysicalTable.java index 5001aaeada..9d888239e5 100644 --- a/fili-core/src/main/java/com/yahoo/bard/webservice/table/PhysicalTable.java +++ b/fili-core/src/main/java/com/yahoo/bard/webservice/table/PhysicalTable.java @@ -2,14 +2,12 @@ // Licensed under the terms of the Apache license. Please see LICENSE.md file distributed with this work for terms. package com.yahoo.bard.webservice.table; -import com.yahoo.bard.webservice.data.dimension.Dimension; import com.yahoo.bard.webservice.data.dimension.DimensionColumn; import com.yahoo.bard.webservice.data.dimension.DimensionDictionary; import com.yahoo.bard.webservice.data.metric.MetricColumn; import com.yahoo.bard.webservice.data.time.ZonedTimeGrain; import com.yahoo.bard.webservice.metadata.SegmentMetadata; import com.yahoo.bard.webservice.util.IntervalUtils; -import com.yahoo.bard.webservice.util.StreamUtils; import com.yahoo.bard.webservice.util.Utils; import org.joda.time.DateTime; @@ -23,8 +21,10 @@ import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; import javax.validation.constraints.NotNull; @@ -38,7 +38,7 @@ public class PhysicalTable extends Table { private Map> workingIntervals; private final Object mutex = new Object(); private final Map logicalToPhysicalColumnNames; - private final Map physicalToLogicalColumnNames; + private final Map> physicalToLogicalColumnNames; /** * Create a physical table. @@ -58,10 +58,12 @@ public PhysicalTable( this.workingIntervals = Collections.synchronizedMap(new HashMap<>()); this.logicalToPhysicalColumnNames = Collections.unmodifiableMap(logicalToPhysicalColumnNames); this.physicalToLogicalColumnNames = Collections.unmodifiableMap( - this.logicalToPhysicalColumnNames - .entrySet() - .stream() - .collect(StreamUtils.toLinkedMap(Map.Entry::getValue, Map.Entry::getKey)) + this.logicalToPhysicalColumnNames.entrySet().stream().collect( + Collectors.groupingBy( + Map.Entry::getValue, + Collectors.mapping(Map.Entry::getKey, Collectors.toSet()) + ) + ) ); } @@ -137,14 +139,19 @@ public synchronized void resetColumns(SegmentMetadata segmentMetadata, Dimension workingIntervals.clear(); for (Map.Entry> nameIntervals : dimensionIntervals.entrySet()) { String physicalName = nameIntervals.getKey(); - String apiName = getLogicalColumnName(physicalName); - Dimension dimension = dimensionDictionary.findByApiName(apiName); - // Schema evolution may lead to unknown dimensions, skip these - if (dimension == null) { - continue; - } - DimensionColumn dimensionColumn = DimensionColumn.addNewDimensionColumn(this, dimension); - workingIntervals.put(dimensionColumn, nameIntervals.getValue()); + + getLogicalColumnNames(physicalName).stream() + .map(dimensionDictionary::findByApiName) + .filter(Objects::nonNull) + .forEach( + dimension -> { + DimensionColumn dimensionColumn = DimensionColumn.addNewDimensionColumn( + this, + dimension + ); + workingIntervals.put(dimensionColumn, nameIntervals.getValue()); + } + ); } for (Map.Entry> nameIntervals : metricIntervals.entrySet()) { MetricColumn metricColumn = MetricColumn.addNewMetricColumn(this, nameIntervals.getKey()); @@ -237,8 +244,8 @@ public String getPhysicalColumnName(String logicalName) { * @param physicalName Physical name to lookup in physical table * @return Translated physicalName if applicable */ - private String getLogicalColumnName(String physicalName) { - return physicalToLogicalColumnNames.getOrDefault(physicalName, physicalName); + private Set getLogicalColumnNames(String physicalName) { + return physicalToLogicalColumnNames.getOrDefault(physicalName, Collections.singleton(physicalName)); } /** diff --git a/fili-core/src/test/groovy/com/yahoo/bard/webservice/table/PhysicalTableSpec.groovy b/fili-core/src/test/groovy/com/yahoo/bard/webservice/table/PhysicalTableSpec.groovy index 644ae9fd54..5d407a2c40 100644 --- a/fili-core/src/test/groovy/com/yahoo/bard/webservice/table/PhysicalTableSpec.groovy +++ b/fili-core/src/test/groovy/com/yahoo/bard/webservice/table/PhysicalTableSpec.groovy @@ -150,4 +150,14 @@ class PhysicalTableSpec extends Specification { expect: physicalTable.getDimensions() == [dimension] as Set } + + def "test physical to logical mapping is constructed correctly"() { + setup: + PhysicalTable oneDimPhysicalTable = new PhysicalTable("test table", DAY.buildZonedTimeGrain(UTC), ['dimension':'druidDim']) + PhysicalTable twoDimPhysicalTable = new PhysicalTable("test table", DAY.buildZonedTimeGrain(UTC), ['dimension1':'druidDim', 'dimension2':'druidDim']) + + expect: + oneDimPhysicalTable.getLogicalColumnNames('druidDim') == ['dimension'] as Set + twoDimPhysicalTable.getLogicalColumnNames('druidDim') == ['dimension1', 'dimension2'] as Set + } }