Skip to content

Commit

Permalink
ESQL: Implement 'right' function (#98974)
Browse files Browse the repository at this point in the history
Add the 'right' function, which extracts a substring beginning from its
right end (opposite function of 'left').
---------

Co-authored-by: Alexander Spies <alexander.spies@elastic.co>
  • Loading branch information
dreamquster and alex-spies committed Sep 8, 2023
1 parent 7dcfdd6 commit 0438166
Show file tree
Hide file tree
Showing 18 changed files with 658 additions and 60 deletions.
5 changes: 5 additions & 0 deletions docs/changelog/98974.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 98974
summary: "ESQL: RIGHT function"
area: ES|QL
type: feature
issues: []
10 changes: 6 additions & 4 deletions docs/reference/esql/esql-functions.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ these functions:
* <<esql-is_infinite>>
* <<esql-is_nan>>
* <<esql-least>>
* <<esql-left>>
* <<esql-length>>
* <<esql-log10>>
* <<esql-ltrim>>
* <<esql-rtrim>>
* <<esql-mv_avg>>
* <<esql-mv_concat>>
* <<esql-mv_count>>
Expand All @@ -47,13 +47,14 @@ these functions:
* <<esql-now>>
* <<esql-pi>>
* <<esql-pow>>
* <<esql-right>>
* <<esql-round>>
* <<esql-rtrim>>
* <<esql-sin>>
* <<esql-sinh>>
* <<esql-split>>
* <<esql-starts_with>>
* <<esql-substring>>
* <<esql-left>>
* <<esql-tan>>
* <<esql-tanh>>
* <<esql-tau>>
Expand Down Expand Up @@ -94,10 +95,10 @@ include::functions/is_finite.asciidoc[]
include::functions/is_infinite.asciidoc[]
include::functions/is_nan.asciidoc[]
include::functions/least.asciidoc[]
include::functions/left.asciidoc[]
include::functions/length.asciidoc[]
include::functions/log10.asciidoc[]
include::functions/ltrim.asciidoc[]
include::functions/rtrim.asciidoc[]
include::functions/mv_avg.asciidoc[]
include::functions/mv_concat.asciidoc[]
include::functions/mv_count.asciidoc[]
Expand All @@ -109,14 +110,15 @@ include::functions/mv_sum.asciidoc[]
include::functions/now.asciidoc[]
include::functions/pi.asciidoc[]
include::functions/pow.asciidoc[]
include::functions/right.asciidoc[]
include::functions/round.asciidoc[]
include::functions/rtrim.asciidoc[]
include::functions/sin.asciidoc[]
include::functions/sinh.asciidoc[]
include::functions/split.asciidoc[]
include::functions/sqrt.asciidoc[]
include::functions/starts_with.asciidoc[]
include::functions/substring.asciidoc[]
include::functions/left.asciidoc[]
include::functions/tan.asciidoc[]
include::functions/tanh.asciidoc[]
include::functions/tau.asciidoc[]
Expand Down
9 changes: 7 additions & 2 deletions docs/reference/esql/functions/left.asciidoc
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
[[esql-left]]
=== `LEFT`
[.text-center]
image::esql/functions/signature/left.svg[Embedded,opts=inline]

Return the substring that extract 'length' chars
from string starting from 0.
Return the substring that extracts 'length' chars from the 'string' starting from the left.

[source.merge.styled,esql]
----
Expand All @@ -12,3 +13,7 @@ include::{esql-specs}/string.csv-spec[tag=left]
|===
include::{esql-specs}/string.csv-spec[tag=left-result]
|===

Supported types:

include::types/left.asciidoc[]
19 changes: 19 additions & 0 deletions docs/reference/esql/functions/right.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[[esql-right]]
=== `RIGHT`
[.text-center]
image::esql/functions/signature/right.svg[Embedded,opts=inline]

Return the substring that extracts 'length' chars from the 'string' starting from the right.

[source.merge.styled,esql]
----
include::{esql-specs}/string.csv-spec[tag=right]
----
[%header.monospaced.styled,format=dsv,separator=|]
|===
include::{esql-specs}/string.csv-spec[tag=right-result]
|===

Supported types:

include::types/right.asciidoc[]
2 changes: 1 addition & 1 deletion docs/reference/esql/functions/signature/left.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/reference/esql/functions/signature/right.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion docs/reference/esql/functions/types/left.asciidoc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[%header.monospaced.styled,format=dsv,separator=|]
|===
arg1 | arg2 | result
string | length | result
keyword | integer | keyword
|===
5 changes: 5 additions & 0 deletions docs/reference/esql/functions/types/right.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[%header.monospaced.styled,format=dsv,separator=|]
|===
string | length | result
keyword | integer | keyword
|===
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ is_finite |is_finite(arg1)
is_infinite |is_infinite(arg1)
is_nan |is_nan(arg1)
least |least(first, rest...)
left |left(arg1, arg2)
left |left(string, length)
length |length(arg1)
log10 |log10(n)
ltrim |ltrim(arg1)
Expand All @@ -56,6 +56,7 @@ now |now()
percentile |percentile(arg1, arg2)
pi |pi()
pow |pow(base, exponent)
right |right(string, length)
round |round(arg1, arg2)
rtrim |rtrim(arg1)
sin |sin(n)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -733,3 +733,23 @@ Bamford |Bam
Bernatsky |Ber
// end::left-result[]
;

right
// tag::right[]
FROM employees
| KEEP last_name
| EVAL right = RIGHT(last_name, 3)
| SORT last_name ASC
| LIMIT 5
// end::right[]
;

// tag::right-result[]
last_name:keyword | right:keyword
Awdeh |deh
Azuma |uma
Baek |aek
Bamford |ord
Bernatsky |sky
// end::right-result[]
;
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,35 @@
// 2.0.
package org.elasticsearch.xpack.esql.expression.function.scalar.string;

import java.lang.IllegalArgumentException;
import java.lang.Override;
import java.lang.String;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.UnicodeUtil;
import org.elasticsearch.compute.data.Block;
import org.elasticsearch.compute.data.BytesRefBlock;
import org.elasticsearch.compute.data.BytesRefVector;
import org.elasticsearch.compute.data.IntBlock;
import org.elasticsearch.compute.data.IntVector;
import org.elasticsearch.compute.data.Page;
import org.elasticsearch.compute.operator.EvalOperator;
import org.elasticsearch.xpack.esql.expression.function.Warnings;
import org.elasticsearch.xpack.ql.tree.Source;

/**
* {@link EvalOperator.ExpressionEvaluator} implementation for {@link Left}.
* This class is generated. Do not edit it.
*/
public final class LeftEvaluator implements EvalOperator.ExpressionEvaluator {
private final Warnings warnings;

private final BytesRef out;

private final UnicodeUtil.UTF8CodePoint cp;

private final EvalOperator.ExpressionEvaluator str;

private final EvalOperator.ExpressionEvaluator length;

public LeftEvaluator(Source source, BytesRef out, EvalOperator.ExpressionEvaluator str,
EvalOperator.ExpressionEvaluator length) {
this.warnings = new Warnings(source);
public LeftEvaluator(BytesRef out, UnicodeUtil.UTF8CodePoint cp,
EvalOperator.ExpressionEvaluator str, EvalOperator.ExpressionEvaluator length) {
this.out = out;
this.cp = cp;
this.str = str;
this.length = length;
}
Expand All @@ -59,7 +57,7 @@ public Block eval(Page page) {
if (lengthVector == null) {
return eval(page.getPositionCount(), strBlock, lengthBlock);
}
return eval(page.getPositionCount(), strVector, lengthVector);
return eval(page.getPositionCount(), strVector, lengthVector).asBlock();
}

public BytesRefBlock eval(int positionCount, BytesRefBlock strBlock, IntBlock lengthBlock) {
Expand All @@ -74,32 +72,22 @@ public BytesRefBlock eval(int positionCount, BytesRefBlock strBlock, IntBlock le
result.appendNull();
continue position;
}
try {
result.appendBytesRef(Left.process(out, strBlock.getBytesRef(strBlock.getFirstValueIndex(p), strScratch), lengthBlock.getInt(lengthBlock.getFirstValueIndex(p))));
} catch (IllegalArgumentException e) {
warnings.registerException(e);
result.appendNull();
}
result.appendBytesRef(Left.process(out, cp, strBlock.getBytesRef(strBlock.getFirstValueIndex(p), strScratch), lengthBlock.getInt(lengthBlock.getFirstValueIndex(p))));
}
return result.build();
}

public BytesRefBlock eval(int positionCount, BytesRefVector strVector, IntVector lengthVector) {
BytesRefBlock.Builder result = BytesRefBlock.newBlockBuilder(positionCount);
public BytesRefVector eval(int positionCount, BytesRefVector strVector, IntVector lengthVector) {
BytesRefVector.Builder result = BytesRefVector.newVectorBuilder(positionCount);
BytesRef strScratch = new BytesRef();
position: for (int p = 0; p < positionCount; p++) {
try {
result.appendBytesRef(Left.process(out, strVector.getBytesRef(p, strScratch), lengthVector.getInt(p)));
} catch (IllegalArgumentException e) {
warnings.registerException(e);
result.appendNull();
}
result.appendBytesRef(Left.process(out, cp, strVector.getBytesRef(p, strScratch), lengthVector.getInt(p)));
}
return result.build();
}

@Override
public String toString() {
return "LeftEvaluator[" + "out=" + out + ", str=" + str + ", length=" + length + "]";
return "LeftEvaluator[" + "str=" + str + ", length=" + length + "]";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License
// 2.0; you may not use this file except in compliance with the Elastic License
// 2.0.
package org.elasticsearch.xpack.esql.expression.function.scalar.string;

import java.lang.Override;
import java.lang.String;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.UnicodeUtil;
import org.elasticsearch.compute.data.Block;
import org.elasticsearch.compute.data.BytesRefBlock;
import org.elasticsearch.compute.data.BytesRefVector;
import org.elasticsearch.compute.data.IntBlock;
import org.elasticsearch.compute.data.IntVector;
import org.elasticsearch.compute.data.Page;
import org.elasticsearch.compute.operator.EvalOperator;

/**
* {@link EvalOperator.ExpressionEvaluator} implementation for {@link Right}.
* This class is generated. Do not edit it.
*/
public final class RightEvaluator implements EvalOperator.ExpressionEvaluator {
private final BytesRef out;

private final UnicodeUtil.UTF8CodePoint cp;

private final EvalOperator.ExpressionEvaluator str;

private final EvalOperator.ExpressionEvaluator length;

public RightEvaluator(BytesRef out, UnicodeUtil.UTF8CodePoint cp,
EvalOperator.ExpressionEvaluator str, EvalOperator.ExpressionEvaluator length) {
this.out = out;
this.cp = cp;
this.str = str;
this.length = length;
}

@Override
public Block eval(Page page) {
Block strUncastBlock = str.eval(page);
if (strUncastBlock.areAllValuesNull()) {
return Block.constantNullBlock(page.getPositionCount());
}
BytesRefBlock strBlock = (BytesRefBlock) strUncastBlock;
Block lengthUncastBlock = length.eval(page);
if (lengthUncastBlock.areAllValuesNull()) {
return Block.constantNullBlock(page.getPositionCount());
}
IntBlock lengthBlock = (IntBlock) lengthUncastBlock;
BytesRefVector strVector = strBlock.asVector();
if (strVector == null) {
return eval(page.getPositionCount(), strBlock, lengthBlock);
}
IntVector lengthVector = lengthBlock.asVector();
if (lengthVector == null) {
return eval(page.getPositionCount(), strBlock, lengthBlock);
}
return eval(page.getPositionCount(), strVector, lengthVector).asBlock();
}

public BytesRefBlock eval(int positionCount, BytesRefBlock strBlock, IntBlock lengthBlock) {
BytesRefBlock.Builder result = BytesRefBlock.newBlockBuilder(positionCount);
BytesRef strScratch = new BytesRef();
position: for (int p = 0; p < positionCount; p++) {
if (strBlock.isNull(p) || strBlock.getValueCount(p) != 1) {
result.appendNull();
continue position;
}
if (lengthBlock.isNull(p) || lengthBlock.getValueCount(p) != 1) {
result.appendNull();
continue position;
}
result.appendBytesRef(Right.process(out, cp, strBlock.getBytesRef(strBlock.getFirstValueIndex(p), strScratch), lengthBlock.getInt(lengthBlock.getFirstValueIndex(p))));
}
return result.build();
}

public BytesRefVector eval(int positionCount, BytesRefVector strVector, IntVector lengthVector) {
BytesRefVector.Builder result = BytesRefVector.newVectorBuilder(positionCount);
BytesRef strScratch = new BytesRef();
position: for (int p = 0; p < positionCount; p++) {
result.appendBytesRef(Right.process(out, cp, strVector.getBytesRef(p, strScratch), lengthVector.getInt(p)));
}
return result.build();
}

@Override
public String toString() {
return "RightEvaluator[" + "str=" + str + ", length=" + length + "]";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
import org.elasticsearch.xpack.esql.expression.function.scalar.string.Left;
import org.elasticsearch.xpack.esql.expression.function.scalar.string.Length;
import org.elasticsearch.xpack.esql.expression.function.scalar.string.RTrim;
import org.elasticsearch.xpack.esql.expression.function.scalar.string.Right;
import org.elasticsearch.xpack.esql.expression.function.scalar.string.Split;
import org.elasticsearch.xpack.esql.expression.function.scalar.string.StartsWith;
import org.elasticsearch.xpack.esql.expression.function.scalar.string.Substring;
Expand Down Expand Up @@ -143,6 +144,7 @@ private FunctionDefinition[][] functions() {
def(RTrim.class, RTrim::new, "rtrim"),
def(Trim.class, Trim::new, "trim"),
def(Left.class, Left::new, "left"),
def(Right.class, Right::new, "right"),
def(StartsWith.class, StartsWith::new, "starts_with") },
// date
new FunctionDefinition[] {
Expand Down

0 comments on commit 0438166

Please sign in to comment.