Skip to content

Commit cbcacce

Browse files
committed
Fix alias type points to nested field
Signed-off-by: Heng Qian <qianheng@amazon.com>
1 parent 23407cb commit cbcacce

File tree

5 files changed

+94
-14
lines changed

5 files changed

+94
-14
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
setup:
2+
- do:
3+
indices.create:
4+
index: test
5+
body:
6+
settings:
7+
number_of_shards: 1
8+
number_of_replicas: 0
9+
mappings:
10+
properties:
11+
log:
12+
properties:
13+
url:
14+
properties:
15+
message:
16+
type: text
17+
fields:
18+
keyword:
19+
type: keyword
20+
ignore_above: 256
21+
time:
22+
type: long
23+
message_alias:
24+
type: alias
25+
path: log.url.message
26+
time_alias:
27+
type: alias
28+
path: log.url.time
29+
30+
- do:
31+
query.settings:
32+
body:
33+
transient:
34+
plugins.calcite.enabled : true
35+
plugins.calcite.fallback.allowed : false
36+
37+
---
38+
teardown:
39+
- do:
40+
query.settings:
41+
body:
42+
transient:
43+
plugins.calcite.enabled : false
44+
plugins.calcite.fallback.allowed : true
45+
46+
---
47+
"Path of alias type points to nested field":
48+
- skip:
49+
features:
50+
- headers
51+
- do:
52+
bulk:
53+
index: test
54+
refresh: true
55+
body:
56+
- '{"index": {}}'
57+
- '{"log": {"url": {"message": "/e2e/h/zap", "time": 1} } }'
58+
59+
- do:
60+
headers:
61+
Content-Type: 'application/json'
62+
ppl:
63+
body:
64+
query: 'source=test | where message_alias = "/e2e/h/zap" | fields message_alias, time_alias'
65+
- match: {"total": 1}
66+
- match: {"schema": [{"name": "message_alias", "type": "string"}, {"name": "time_alias", "type": "bigint"}]}
67+
- match: {"datarows": [["/e2e/h/zap", 1]]}

opensearch/src/main/java/org/opensearch/sql/opensearch/data/type/OpenSearchDataType.java

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -133,15 +133,19 @@ public static Map<String, OpenSearchDataType> parseMapping(Map<String, Object> i
133133
});
134134

135135
// Begin to parse alias type fields
136-
aliasMapping.forEach(
137-
(k, v) -> {
138-
if (result.containsKey(v)) {
139-
result.put(k, new OpenSearchAliasType(v, result.get(v)));
140-
} else {
141-
throw new IllegalStateException(
142-
String.format("Cannot find the path [%s] for alias type field [%s]", v, k));
143-
}
144-
});
136+
if (!aliasMapping.isEmpty()) {
137+
// The path of alias type may point to a nested field, so we need to flatten the result.
138+
Map<String, OpenSearchDataType> flattenResult = traverseAndFlatten(result);
139+
aliasMapping.forEach(
140+
(k, v) -> {
141+
if (flattenResult.containsKey(v)) {
142+
result.put(k, new OpenSearchAliasType(v, flattenResult.get(v)));
143+
} else {
144+
throw new IllegalStateException(
145+
String.format("Cannot find the path [%s] for alias type field [%s]", v, k));
146+
}
147+
});
148+
}
145149

146150
return result;
147151
}

opensearch/src/main/java/org/opensearch/sql/opensearch/request/PredicateAnalyzer.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,17 +1006,21 @@ ExprType getExprType() {
10061006
}
10071007

10081008
boolean isTextType() {
1009-
return type != null && type instanceof OpenSearchTextType;
1009+
return type != null && type.getOriginalExprType() instanceof OpenSearchTextType;
10101010
}
10111011

10121012
String toKeywordSubField() {
1013+
ExprType type = this.type.getOriginalExprType();
10131014
if (type instanceof OpenSearchTextType) {
10141015
OpenSearchTextType textType = (OpenSearchTextType) type;
1016+
// For OpenSearch Alias type which maps to the field of text type,
1017+
// we have to use its original path
1018+
String path = this.type.getOriginalPath().orElse(this.name);
10151019
// Find the first subfield with type keyword, return null if non-exist.
10161020
return textType.getFields().entrySet().stream()
10171021
.filter(e -> e.getValue().getMappingType() == MappingType.Keyword)
10181022
.findFirst()
1019-
.map(e -> name + "." + e.getKey())
1023+
.map(e -> path + "." + e.getKey())
10201024
.orElse(null);
10211025
}
10221026
return null;

opensearch/src/main/java/org/opensearch/sql/opensearch/storage/scan/CalciteLogicalIndexScan.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,17 @@ public CalciteLogicalIndexScan pushDownProject(List<Integer> selectedColumns) {
121121
}
122122
RelDataType newSchema = builder.build();
123123
CalciteLogicalIndexScan newScan = this.copyWithNewSchema(newSchema);
124+
Map<String, String> aliasMapping = this.osIndex.getAliasMapping();
125+
// For alias types, we need to push down its original path instead of the alias name.
126+
List<String> projectedFields =
127+
newSchema.getFieldNames().stream()
128+
.map(fieldName -> aliasMapping.getOrDefault(fieldName, fieldName))
129+
.toList();
124130
newScan.pushDownContext.add(
125131
PushDownAction.of(
126132
PushDownType.PROJECT,
127133
newSchema.getFieldNames(),
128-
requestBuilder ->
129-
requestBuilder.pushDownProjectStream(newSchema.getFieldNames().stream())));
134+
requestBuilder -> requestBuilder.pushDownProjectStream(projectedFields.stream())));
130135
return newScan;
131136
}
132137

opensearch/src/main/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/LuceneQuery.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ public QueryBuilder build(FunctionExpression func) {
109109
Expression expr = func.getArguments().get(1);
110110
ExprValue literalValue =
111111
expr instanceof LiteralExpression ? expr.valueOf() : cast((FunctionExpression) expr, ref);
112-
return doBuild(ref.getAttr(), ref.type(), literalValue);
112+
return doBuild(ref.getRawPath(), ref.type(), literalValue);
113113
}
114114

115115
private ExprValue cast(FunctionExpression castFunction, ReferenceExpression ref) {

0 commit comments

Comments
 (0)