Merge pull request #2771 from gianm/extractionfn-stuff

Various ExtractionFn null handling fixes.
This commit is contained in:
Fangjin Yang 2016-04-01 16:35:46 -07:00
commit 18b9ea62cf
11 changed files with 66 additions and 38 deletions

View File

@ -59,7 +59,7 @@ public interface ExtractionFn
public byte[] getCacheKey();
/**
* The "extraction" function. This should map a value into some other String value.
* The "extraction" function. This should map an Object into some String value.
* <p>
* In order to maintain the "null and empty string are equivalent" semantics that Druid provides, the
* empty string is considered invalid output for this method and should instead return null. This is
@ -72,8 +72,28 @@ public interface ExtractionFn
*/
public String apply(Object value);
/**
* The "extraction" function. This should map a String value into some other String value.
* <p>
* Like {@link #apply(Object)}, the empty string is considered invalid output for this method and it should
* instead return null.
*
* @param value the original value of the dimension
*
* @return a value that should be used instead of the original
*/
public String apply(String value);
/**
* The "extraction" function. This should map a long value into some String value.
* <p>
* Like {@link #apply(Object)}, the empty string is considered invalid output for this method and it should
* instead return null.
*
* @param value the original value of the dimension
*
* @return a value that should be used instead of the original
*/
public String apply(long value);
/**

View File

@ -109,7 +109,7 @@ public class JavaScriptExtractionFn implements ExtractionFn
@Override
public String apply(String value)
{
return this.apply((Object) value);
return this.apply((Object) Strings.emptyToNull(value));
}
@Override

View File

@ -31,7 +31,7 @@ import java.nio.ByteBuffer;
import java.util.Locale;
@JsonTypeName("lower")
public class LowerExtractionFn implements ExtractionFn
public class LowerExtractionFn extends DimExtractionFn
{
private final Locale locale;
@ -60,12 +60,6 @@ public class LowerExtractionFn implements ExtractionFn
return key.toLowerCase(locale);
}
@Override
public String apply(long value)
{
return apply(String.valueOf(value));
}
@Override
public boolean preservesOrdering()
{
@ -88,10 +82,4 @@ public class LowerExtractionFn implements ExtractionFn
.put(localeBytes)
.array();
}
@Override
public String apply(Object value)
{
return apply(String.valueOf(value));
}
}

View File

@ -22,6 +22,7 @@ package io.druid.query.extraction;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.metamx.common.StringUtils;
import java.nio.ByteBuffer;
@ -59,9 +60,8 @@ public class MatchingDimExtractionFn extends DimExtractionFn
@Override
public String apply(String dimValue)
{
dimValue = (dimValue == null) ? "" : dimValue;
Matcher matcher = pattern.matcher(dimValue);
return matcher.find() ? dimValue : null;
Matcher matcher = pattern.matcher(Strings.nullToEmpty(dimValue));
return matcher.find() ? Strings.emptyToNull(dimValue) : null;
}
@JsonProperty("expr")

View File

@ -86,11 +86,8 @@ public class RegexDimExtractionFn extends DimExtractionFn
@Override
public String apply(String dimValue)
{
if (dimValue == null) {
return null;
}
String retVal;
Matcher matcher = pattern.matcher(dimValue);
final String retVal;
final Matcher matcher = pattern.matcher(Strings.nullToEmpty(dimValue));
if (matcher.find()) {
retVal = matcher.group(1);
} else {

View File

@ -22,6 +22,7 @@ package io.druid.query.extraction;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import io.druid.query.search.search.SearchQuerySpec;
import java.nio.ByteBuffer;
@ -61,7 +62,7 @@ public class SearchQuerySpecDimExtractionFn extends DimExtractionFn
@Override
public String apply(String dimValue)
{
return searchQuerySpec.accept(dimValue) ? dimValue : null;
return searchQuerySpec.accept(dimValue) ? Strings.emptyToNull(dimValue) : null;
}
@Override

View File

@ -31,7 +31,7 @@ import java.nio.ByteBuffer;
import java.util.Locale;
@JsonTypeName("upper")
public class UpperExtractionFn implements ExtractionFn
public class UpperExtractionFn extends DimExtractionFn
{
private final Locale locale;
@ -59,12 +59,6 @@ public class UpperExtractionFn implements ExtractionFn
return key.toUpperCase(locale);
}
@Override
public String apply(long value)
{
return apply(String.valueOf(value));
}
@Override
public boolean preservesOrdering()
{
@ -87,10 +81,4 @@ public class UpperExtractionFn implements ExtractionFn
.put(localeBytes)
.array();
}
@Override
public String apply(Object value)
{
return apply(String.valueOf(value));
}
}

View File

@ -35,6 +35,8 @@ public class LowerExtractionFnTest
Assert.assertEquals("lower 1 string", extractionFn.apply("lOwER 1 String"));
Assert.assertEquals(null, extractionFn.apply(""));
Assert.assertEquals(null, extractionFn.apply(null));
Assert.assertEquals(null, extractionFn.apply((Object)null));
Assert.assertEquals("1", extractionFn.apply(1));
}
@Test

View File

@ -67,6 +67,17 @@ public class MatchingDimExtractionFnTest
}
}
@Test
public void testNullExtraction()
{
String regex = "^$";
ExtractionFn extractionFn = new MatchingDimExtractionFn(regex);
Assert.assertNull(extractionFn.apply((Object) null));
Assert.assertNull(extractionFn.apply((String) null));
Assert.assertNull(extractionFn.apply((String) ""));
}
@Test
public void testSerde() throws Exception
{

View File

@ -102,7 +102,6 @@ public class RegexDimExtractionFnTest
Assert.assertEquals(expected, extracted);
}
@Test
public void testNullAndEmpty()
{
@ -116,6 +115,26 @@ public class RegexDimExtractionFnTest
Assert.assertEquals(null, extractionFn.apply("/a/b"));
}
@Test
public void testMissingValueReplacementFromNullAndEmpty()
{
String regex = "(bob)";
ExtractionFn extractionFn = new RegexDimExtractionFn(regex, true, "NO MATCH");
Assert.assertEquals("NO MATCH", extractionFn.apply(""));
Assert.assertEquals("NO MATCH", extractionFn.apply(null));
}
@Test
public void testMissingValueReplacementToEmpty()
{
String regex = "(bob)";
ExtractionFn extractionFn = new RegexDimExtractionFn(regex, true, "");
Assert.assertEquals(null, extractionFn.apply(null));
Assert.assertEquals(null, extractionFn.apply(""));
Assert.assertEquals(null, extractionFn.apply("abc"));
Assert.assertEquals(null, extractionFn.apply("123"));
}
@Test
public void testMissingValueReplacement()
{

View File

@ -35,6 +35,8 @@ public class UpperExtractionFnTest
Assert.assertEquals("UPPER", extractionFn.apply("uPpeR"));
Assert.assertEquals(null, extractionFn.apply(""));
Assert.assertEquals(null, extractionFn.apply(null));
Assert.assertEquals(null, extractionFn.apply((Object)null));
Assert.assertEquals("1", extractionFn.apply(1));
}
@Test