add version comparator for StringComparator (#6745)

* add version comparator for StringComparator

* add more test case and docs
This commit is contained in:
dongyifeng 2019-01-09 09:17:03 +08:00 committed by Clint Wylie
parent c4716d1639
commit def823124c
8 changed files with 85 additions and 2 deletions

View File

@ -276,7 +276,7 @@ greater than, less than, greater than or equal to, less than or equal to, and "b
|upper|String|The upper bound for the filter|no|
|lowerStrict|Boolean|Perform strict comparison on the lower bound (">" instead of ">=")|no, default: false|
|upperStrict|Boolean|Perform strict comparison on the upper bound ("<" instead of "<=")|no, default: false|
|ordering|String|Specifies the sorting order to use when comparing values against the bound. Can be one of the following values: "lexicographic", "alphanumeric", "numeric", "strlen". See [Sorting Orders](./sorting-orders.html) for more details.|no, default: "lexicographic"|
|ordering|String|Specifies the sorting order to use when comparing values against the bound. Can be one of the following values: "lexicographic", "alphanumeric", "numeric", "strlen", "version". See [Sorting Orders](./sorting-orders.html) for more details.|no, default: "lexicographic"|
|extractionFn|[Extraction function](#filtering-with-extraction-functions)| Extraction function to apply to the dimension|no|
Bound filters support the use of extraction functions, see [Filtering with Extraction Functions](#filtering-with-extraction-functions) for details.

View File

@ -47,3 +47,8 @@ When comparing two unparseable values (e.g., "hello" and "world"), this ordering
## Strlen
Sorts values by the their string lengths. When there is a tie, this comparator falls back to using the String compareTo method.
## Version
Sorts values as versions, e.g.: "10.0 sorts after 9.0", "1.0.0-SNAPSHOT sorts after 1.0.0".
See https://maven.apache.org/ref/3.6.0/maven-artifact/apidocs/org/apache/maven/artifact/versioning/ComparableVersion.html for more details on how this ordering sorts values.

View File

@ -749,6 +749,11 @@
<artifactId>caffeine</artifactId>
<version>${caffeine.version}</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact</artifactId>
<version>3.6.0</version>
</dependency>
<dependency>
<groupId>org.apache.calcite</groupId>

View File

@ -116,6 +116,11 @@
<artifactId>checker</artifactId>
<version>${checkerframework.version}</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact</artifactId>
</dependency>
<!-- Tests -->
<dependency>

View File

@ -36,7 +36,8 @@ public class StringComparatorModule extends SimpleModule
new NamedType(StringComparators.LexicographicComparator.class, StringComparators.LEXICOGRAPHIC_NAME),
new NamedType(StringComparators.AlphanumericComparator.class, StringComparators.ALPHANUMERIC_NAME),
new NamedType(StringComparators.StrlenComparator.class, StringComparators.STRLEN_NAME),
new NamedType(StringComparators.NumericComparator.class, StringComparators.NUMERIC_NAME)
new NamedType(StringComparators.NumericComparator.class, StringComparators.NUMERIC_NAME),
new NamedType(StringComparators.VersionComparator.class, StringComparators.VERSION_NAME)
);
}

View File

@ -39,6 +39,8 @@ public abstract class StringComparator implements Comparator<String>
return StringComparators.STRLEN;
case StringComparators.NUMERIC_NAME:
return StringComparators.NUMERIC;
case StringComparators.VERSION_NAME:
return StringComparators.VERSION;
default:
throw new IAE("Unknown string comparator[%s]", type);
}

View File

@ -24,6 +24,7 @@ import com.google.common.primitives.Ints;
import com.google.common.primitives.UnsignedBytes;
import org.apache.druid.common.guava.GuavaUtils;
import org.apache.druid.java.util.common.StringUtils;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import java.math.BigDecimal;
import java.util.Comparator;
@ -34,16 +35,19 @@ public class StringComparators
public static final String ALPHANUMERIC_NAME = "alphanumeric";
public static final String NUMERIC_NAME = "numeric";
public static final String STRLEN_NAME = "strlen";
public static final String VERSION_NAME = "version";
public static final StringComparator LEXICOGRAPHIC = new LexicographicComparator();
public static final StringComparator ALPHANUMERIC = new AlphanumericComparator();
public static final StringComparator NUMERIC = new NumericComparator();
public static final StringComparator STRLEN = new StrlenComparator();
public static final StringComparator VERSION = new VersionComparator();
public static final int LEXICOGRAPHIC_CACHE_ID = 0x01;
public static final int ALPHANUMERIC_CACHE_ID = 0x02;
public static final int NUMERIC_CACHE_ID = 0x03;
public static final int STRLEN_CACHE_ID = 0x04;
public static final int VERSION_CACHE_ID = 0x05;
public static class LexicographicComparator extends StringComparator
{
@ -416,4 +420,51 @@ public class StringComparators
return new byte[]{(byte) NUMERIC_CACHE_ID};
}
}
public static class VersionComparator extends StringComparator
{
@Override
public int compare(String o1, String o2)
{
//noinspection StringEquality
if (o1 == o2) {
return 0;
}
if (o1 == null) {
return -1;
}
if (o2 == null) {
return 1;
}
DefaultArtifactVersion version1 = new DefaultArtifactVersion(o1);
DefaultArtifactVersion version2 = new DefaultArtifactVersion(o2);
return version1.compareTo(version2);
}
@Override
public String toString()
{
return StringComparators.VERSION_NAME;
}
@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
return true;
}
@Override
public byte[] getCacheKey()
{
return new byte[]{(byte) VERSION_CACHE_ID};
}
}
}

View File

@ -142,6 +142,20 @@ public class StringComparatorsTest
Assert.assertTrue(StringComparators.NUMERIC.compare("CAN'T PARSE THIS", "CAN'T TOUCH THIS") < 0);
}
@Test
public void testVersionComparator()
{
commonTest(StringComparators.VERSION);
Assert.assertTrue(StringComparators.VERSION.compare("02", "002") == 0);
Assert.assertTrue(StringComparators.VERSION.compare("1.0", "2.0") < 0);
Assert.assertTrue(StringComparators.VERSION.compare("9.1", "10.0") < 0);
Assert.assertTrue(StringComparators.VERSION.compare("1.1.1", "2.0") < 0);
Assert.assertTrue(StringComparators.VERSION.compare("1.0-SNAPSHOT", "1.0") < 0);
Assert.assertTrue(StringComparators.VERSION.compare("2.0.1-xyz-1", "2.0.1-1-xyz") < 0);
Assert.assertTrue(StringComparators.VERSION.compare("1.0-SNAPSHOT", "1.0-Final") < 0);
}
@Test
public void testLexicographicComparatorSerdeTest() throws IOException
{