blob: 763a924f8c20a626bf3ceafa7c4617053a9779f2 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.druid.segment.indexing;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import org.apache.druid.data.input.InputRow;
import org.apache.druid.data.input.impl.DimensionsSpec;
import org.apache.druid.data.input.impl.InputRowParser;
import org.apache.druid.data.input.impl.MapInputRowParser;
import org.apache.druid.data.input.impl.TimeAndDimsParseSpec;
import org.apache.druid.data.input.impl.TimestampSpec;
import org.apache.druid.java.util.common.DateTimes;
import org.apache.druid.query.expression.TestExprMacroTable;
import org.apache.druid.query.filter.AndDimFilter;
import org.apache.druid.query.filter.SelectorDimFilter;
import org.apache.druid.segment.TestHelper;
import org.apache.druid.segment.transform.ExpressionTransform;
import org.apache.druid.segment.transform.TransformSpec;
import org.apache.druid.testing.InitializedNullHandlingTest;
import org.junit.Assert;
import org.junit.Test;
import java.util.Map;
public class TransformSpecTest extends InitializedNullHandlingTest
{
private static final MapInputRowParser PARSER = new MapInputRowParser(
new TimeAndDimsParseSpec(
new TimestampSpec("t", "auto", DateTimes.of("2000-01-01")),
new DimensionsSpec(
DimensionsSpec.getDefaultSchemas(ImmutableList.of("f", "x", "y")),
null,
null
)
)
);
private static final Map<String, Object> ROW1 = ImmutableMap.<String, Object>builder()
.put("x", "foo")
.put("y", "bar")
.put("a", 2.0)
.put("b", 3L)
.build();
private static final Map<String, Object> ROW2 = ImmutableMap.<String, Object>builder()
.put("x", "foo")
.put("y", "baz")
.put("a", 2.0)
.put("b", 4L)
.build();
@Test
public void testTransforms()
{
final TransformSpec transformSpec = new TransformSpec(
null,
ImmutableList.of(
new ExpressionTransform("f", "concat(x,y)", TestExprMacroTable.INSTANCE),
new ExpressionTransform("g", "a + b", TestExprMacroTable.INSTANCE),
new ExpressionTransform("h", "concat(f,g)", TestExprMacroTable.INSTANCE)
)
);
final InputRowParser<Map<String, Object>> parser = transformSpec.decorate(PARSER);
final InputRow row = parser.parseBatch(ROW1).get(0);
Assert.assertNotNull(row);
Assert.assertEquals(DateTimes.of("2000-01-01").getMillis(), row.getTimestampFromEpoch());
Assert.assertEquals(DateTimes.of("2000-01-01"), row.getTimestamp());
Assert.assertEquals(ImmutableList.of("f", "x", "y"), row.getDimensions());
Assert.assertEquals(ImmutableList.of("foo"), row.getDimension("x"));
Assert.assertEquals(3.0, row.getMetric("b").doubleValue(), 0);
Assert.assertEquals("foobar", row.getRaw("f"));
Assert.assertEquals(ImmutableList.of("foobar"), row.getDimension("f"));
Assert.assertEquals(ImmutableList.of("5.0"), row.getDimension("g"));
Assert.assertEquals(ImmutableList.of(), row.getDimension("h"));
Assert.assertEquals(5L, row.getMetric("g").longValue());
}
@Test
public void testTransformOverwriteField()
{
// Transforms are allowed to overwrite fields, and to refer to the fields they overwrite; double-check this.
final TransformSpec transformSpec = new TransformSpec(
null,
ImmutableList.of(
new ExpressionTransform("x", "concat(x,y)", TestExprMacroTable.INSTANCE)
)
);
final InputRowParser<Map<String, Object>> parser = transformSpec.decorate(PARSER);
final InputRow row = parser.parseBatch(ROW1).get(0);
Assert.assertNotNull(row);
Assert.assertEquals(DateTimes.of("2000-01-01").getMillis(), row.getTimestampFromEpoch());
Assert.assertEquals(DateTimes.of("2000-01-01"), row.getTimestamp());
Assert.assertEquals(ImmutableList.of("f", "x", "y"), row.getDimensions());
Assert.assertEquals(ImmutableList.of("foobar"), row.getDimension("x"));
Assert.assertEquals(3.0, row.getMetric("b").doubleValue(), 0);
Assert.assertNull(row.getRaw("f"));
}
@Test
public void testFilterOnTransforms()
{
// Filters are allowed to refer to transformed fields; double-check this.
final TransformSpec transformSpec = new TransformSpec(
new AndDimFilter(
ImmutableList.of(
new SelectorDimFilter("x", "foo", null),
new SelectorDimFilter("f", "foobar", null),
new SelectorDimFilter("g", "5.0", null)
)
),
ImmutableList.of(
new ExpressionTransform("f", "concat(x,y)", TestExprMacroTable.INSTANCE),
new ExpressionTransform("g", "a + b", TestExprMacroTable.INSTANCE)
)
);
final InputRowParser<Map<String, Object>> parser = transformSpec.decorate(PARSER);
Assert.assertNotNull(parser.parseBatch(ROW1).get(0));
Assert.assertNull(parser.parseBatch(ROW2).get(0));
}
@Test
public void testTransformTimeFromOtherFields()
{
final TransformSpec transformSpec = new TransformSpec(
null,
ImmutableList.of(
new ExpressionTransform("__time", "(a + b) * 3600000", TestExprMacroTable.INSTANCE)
)
);
final InputRowParser<Map<String, Object>> parser = transformSpec.decorate(PARSER);
final InputRow row = parser.parseBatch(ROW1).get(0);
Assert.assertNotNull(row);
Assert.assertEquals(DateTimes.of("1970-01-01T05:00:00Z"), row.getTimestamp());
Assert.assertEquals(DateTimes.of("1970-01-01T05:00:00Z").getMillis(), row.getTimestampFromEpoch());
}
@Test
public void testTransformTimeFromTime()
{
final TransformSpec transformSpec = new TransformSpec(
null,
ImmutableList.of(
new ExpressionTransform("__time", "__time + 3600000", TestExprMacroTable.INSTANCE)
)
);
final InputRowParser<Map<String, Object>> parser = transformSpec.decorate(PARSER);
final InputRow row = parser.parseBatch(ROW1).get(0);
Assert.assertNotNull(row);
Assert.assertEquals(DateTimes.of("2000-01-01T01:00:00Z"), row.getTimestamp());
Assert.assertEquals(DateTimes.of("2000-01-01T01:00:00Z").getMillis(), row.getTimestampFromEpoch());
}
@Test
public void testSerde() throws Exception
{
final TransformSpec transformSpec = new TransformSpec(
new AndDimFilter(
ImmutableList.of(
new SelectorDimFilter("x", "foo", null),
new SelectorDimFilter("f", "foobar", null),
new SelectorDimFilter("g", "5.0", null)
)
),
ImmutableList.of(
new ExpressionTransform("f", "concat(x,y)", TestExprMacroTable.INSTANCE),
new ExpressionTransform("g", "a + b", TestExprMacroTable.INSTANCE)
)
);
final ObjectMapper jsonMapper = TestHelper.makeJsonMapper();
Assert.assertEquals(
transformSpec,
jsonMapper.readValue(jsonMapper.writeValueAsString(transformSpec), TransformSpec.class)
);
}
}