SQL: Improve performances of LTRIM/RTRIM (#57603)

Change custom stripping leading and trailing whitespaces implementation
to substantially improves performance:
```
Benchmark                         Mode  Cnt      Score     Error  Units
StringTrim.testWithStringBuilder  avgt   25  82547.575 ±  66.244  ns/op (existing impl)
StringTrim.testWithSubstring      avgt   25   1398.762 ± 101.152  ns/op (new impl)
StringTrim.testWithJavaStrip      avgt   25   1186.120 ±  10.374  ns/op (for reference)
```
Java's string stripLeading()/stripTrailing() not available to all supported JDKs.

Enhanced LENGTH unit tests and compine a couple of LTRIM/RTRIM integ
tests.

Relates to: #57594
(partially cherry picked from commit ee7868d68733f195dc46926a7eab3d9dd7033ef4)

Co-authored-by: Bogdan Pintea <bogdan.pintea@elastic.co>
This commit is contained in:
Marios Trivyzas 2020-06-04 13:43:49 +02:00 committed by GitHub
parent 2c2d903277
commit 5f8442d1f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 21 additions and 27 deletions

View File

@ -70,11 +70,8 @@ SELECT LEFT('Elasticsearch', LENGTH('abcdefghijklmnop')) leftchars;
ltrimFilter ltrimFilter
SELECT LTRIM(first_name) lt FROM "test_emp" WHERE LTRIM(first_name) = 'Bob'; SELECT LTRIM(first_name) lt FROM "test_emp" WHERE LTRIM(first_name) = 'Bob';
ltrimInline1 ltrimInline
SELECT LTRIM(' Elastic ') trimmed; SELECT LTRIM(' Elastic ') lt1, LTRIM(' ') lt2;
ltrimInline2
SELECT LTRIM(' ') trimmed;
locateInline1 locateInline1
SELECT LOCATE('a', 'Elasticsearch', 8) location; SELECT LOCATE('a', 'Elasticsearch', 8) location;
@ -127,11 +124,8 @@ SELECT LTRIM("first_name") lt FROM "test_emp" WHERE LTRIM("first_name") LIKE '%a
rtrimFilter rtrimFilter
SELECT RTRIM(first_name) rt FROM "test_emp" WHERE RTRIM(first_name) = 'Johnny'; SELECT RTRIM(first_name) rt FROM "test_emp" WHERE RTRIM(first_name) = 'Johnny';
rtrimInline1 rtrimInline
SELECT RTRIM(' Elastic ') trimmed; SELECT RTRIM(' Elastic ') rt1, RTRIM(' ') rt2;
rtrimInline2
SELECT RTRIM(' ') trimmed;
spaceFilter spaceFilter
SELECT SPACE(languages) spaces, languages FROM "test_emp" WHERE SPACE(languages) = ' '; SELECT SPACE(languages) spaces, languages FROM "test_emp" WHERE SPACE(languages) = ' ';

View File

@ -23,15 +23,15 @@ final class StringFunctionUtils {
if (!hasLength(s)) { if (!hasLength(s)) {
return s; return s;
} }
if (start < 0) { if (start < 0) {
start = 0; start = 0;
} }
if (start + 1 > s.length() || length < 0) { if (start + 1 > s.length() || length < 0) {
return ""; return "";
} }
return (start + length > s.length()) ? s.substring(start) : s.substring(start, start + length); return (start + length > s.length()) ? s.substring(start) : s.substring(start, start + length);
} }
@ -47,11 +47,11 @@ final class StringFunctionUtils {
return s; return s;
} }
StringBuilder sb = new StringBuilder(s); int i = s.length() - 1;
while (sb.length() > 0 && Character.isWhitespace(sb.charAt(sb.length() - 1))) { while (i >= 0 && Character.isWhitespace(s.charAt(i))) {
sb.deleteCharAt(sb.length() - 1); i--;
} }
return sb.toString(); return s.substring(0, i + 1);
} }
/** /**
@ -66,10 +66,10 @@ final class StringFunctionUtils {
return s; return s;
} }
StringBuilder sb = new StringBuilder(s); int i = 0;
while (sb.length() > 0 && Character.isWhitespace(sb.charAt(0))) { while (i < s.length() && Character.isWhitespace(s.charAt(i))) {
sb.deleteCharAt(0); i++;
} }
return sb.toString(); return s.substring(i);
} }
} }

View File

@ -51,8 +51,8 @@ public class StringProcessor implements Processor {
LCASE((String s) -> s.toLowerCase(Locale.ROOT)), LCASE((String s) -> s.toLowerCase(Locale.ROOT)),
UCASE((String s) -> s.toUpperCase(Locale.ROOT)), UCASE((String s) -> s.toUpperCase(Locale.ROOT)),
LENGTH((String s) -> StringFunctionUtils.trimTrailingWhitespaces(s).length()), LENGTH((String s) -> StringFunctionUtils.trimTrailingWhitespaces(s).length()),
RTRIM((String s) -> StringFunctionUtils.trimTrailingWhitespaces(s)), RTRIM(StringFunctionUtils::trimTrailingWhitespaces),
LTRIM((String s) -> StringFunctionUtils.trimLeadingWhitespaces(s)), LTRIM(StringFunctionUtils::trimLeadingWhitespaces),
TRIM(String::trim), TRIM(String::trim),
SPACE((Number n) -> { SPACE((Number n) -> {
int i = n.intValue(); int i = n.intValue();

View File

@ -134,10 +134,10 @@ public class StringFunctionProcessorTests extends AbstractWireSerializingTestCas
StringProcessor proc = new StringProcessor(StringOperation.LENGTH); StringProcessor proc = new StringProcessor(StringOperation.LENGTH);
assertNull(proc.process(null)); assertNull(proc.process(null));
assertEquals(7, proc.process("foo bar")); assertEquals(7, proc.process("foo bar"));
assertEquals(0, proc.process("")); assertEquals(0, proc.process(withRandomWhitespaces(" \t \r\n \n ", true, true)));
assertEquals(0, proc.process(" ")); assertEquals(0, proc.process(withRandomWhitespaces(" ", true, true)));
assertEquals(7, proc.process("foo bar ")); assertEquals(7, proc.process(withRandomWhitespaces("foo bar", false, true)));
assertEquals(10, proc.process(" foo bar ")); assertEquals(10, proc.process(withRandomWhitespaces(" foo bar ", false, true)));
assertEquals(1, proc.process('f')); assertEquals(1, proc.process('f'));
stringCharInputValidation(proc); stringCharInputValidation(proc);