Skip to content

Commit 2810046

Browse files
committed
[opt](maxcompute)Optimize maxcompute performance for select in scenarios with small limits.
1 parent 90f1eb8 commit 2810046

8 files changed

Lines changed: 1260 additions & 12 deletions

File tree

fe/be-java-extensions/max-compute-connector/src/main/java/org/apache/doris/maxcompute/MaxComputeJniScanner.java

Lines changed: 638 additions & 7 deletions
Large diffs are not rendered by default.
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.apache.doris.maxcompute;
19+
20+
import org.apache.doris.common.jni.vec.ColumnType;
21+
import org.apache.doris.common.jni.vec.ColumnValue;
22+
23+
import org.junit.Assert;
24+
import org.junit.Test;
25+
26+
import java.lang.reflect.Constructor;
27+
import java.time.LocalDate;
28+
import java.time.LocalDateTime;
29+
import java.time.ZoneId;
30+
import java.util.ArrayList;
31+
import java.util.Arrays;
32+
import java.util.List;
33+
34+
public class MaxComputeJniScannerTest {
35+
private static final ZoneId SHANGHAI = ZoneId.of("Asia/Shanghai");
36+
37+
@Test
38+
public void testResultSetColumnValueParsesStringDateTime() throws Exception {
39+
ColumnValue value = newResultSetColumnValue("2026-04-12 15:16:17.123", "datetimev2(3)");
40+
41+
Assert.assertEquals(LocalDateTime.of(2026, 4, 12, 15, 16, 17, 123_000_000), value.getDateTime());
42+
}
43+
44+
@Test
45+
public void testResultSetColumnValueParsesOffsetDateTimeString() throws Exception {
46+
ColumnValue value = newResultSetColumnValue("2026-04-12T15:16:17Z", "datetimev2(3)");
47+
48+
Assert.assertEquals(LocalDateTime.of(2026, 4, 12, 23, 16, 17), value.getDateTime());
49+
}
50+
51+
@Test
52+
public void testResultSetColumnValueParsesStringDate() throws Exception {
53+
ColumnValue value = newResultSetColumnValue("2026-04-12", "datev2");
54+
55+
Assert.assertEquals(LocalDate.of(2026, 4, 12), value.getDate());
56+
}
57+
58+
@Test
59+
public void testResultSetColumnValueUnpacksArrayString() throws Exception {
60+
ColumnValue value = newResultSetColumnValue("[value1, value2, NULL]", "array<string>");
61+
List<ColumnValue> elements = new ArrayList<>();
62+
63+
value.unpackArray(elements);
64+
65+
Assert.assertEquals(3, elements.size());
66+
Assert.assertEquals("value1", elements.get(0).getString());
67+
Assert.assertEquals("value2", elements.get(1).getString());
68+
Assert.assertTrue(elements.get(2).isNull());
69+
}
70+
71+
@Test
72+
public void testResultSetColumnValueUnpacksMapString() throws Exception {
73+
ColumnValue value = newResultSetColumnValue("{key1:value1, key2:NULL}", "map<string,string>");
74+
List<ColumnValue> keys = new ArrayList<>();
75+
List<ColumnValue> values = new ArrayList<>();
76+
77+
value.unpackMap(keys, values);
78+
79+
Assert.assertEquals(2, keys.size());
80+
Assert.assertEquals("key1", keys.get(0).getString());
81+
Assert.assertEquals("value1", values.get(0).getString());
82+
Assert.assertEquals("key2", keys.get(1).getString());
83+
Assert.assertTrue(values.get(1).isNull());
84+
}
85+
86+
@Test
87+
public void testResultSetColumnValueUnpacksStructString() throws Exception {
88+
ColumnValue value = newResultSetColumnValue("{field1:abc, field2:123}", "struct<field1:string,field2:int>");
89+
List<ColumnValue> fields = new ArrayList<>();
90+
91+
value.unpackStruct(Arrays.asList(0, 1), fields);
92+
93+
Assert.assertEquals(2, fields.size());
94+
Assert.assertEquals("abc", fields.get(0).getString());
95+
Assert.assertEquals(123, fields.get(1).getInt());
96+
}
97+
98+
@Test
99+
public void testResultSetColumnValueUnpacksNestedComplexString() throws Exception {
100+
ColumnValue value = newResultSetColumnValue("{key:[{s_int:-123}]}", "map<string,array<struct<s_int:int>>>");
101+
List<ColumnValue> keys = new ArrayList<>();
102+
List<ColumnValue> values = new ArrayList<>();
103+
104+
value.unpackMap(keys, values);
105+
106+
Assert.assertEquals(1, keys.size());
107+
Assert.assertEquals("key", keys.get(0).getString());
108+
109+
List<ColumnValue> arrayElements = new ArrayList<>();
110+
values.get(0).unpackArray(arrayElements);
111+
Assert.assertEquals(1, arrayElements.size());
112+
113+
List<ColumnValue> structFields = new ArrayList<>();
114+
arrayElements.get(0).unpackStruct(Arrays.asList(0), structFields);
115+
Assert.assertEquals(-123, structFields.get(0).getInt());
116+
}
117+
118+
private ColumnValue newResultSetColumnValue(Object value, String type) throws Exception {
119+
Class<?> clazz = Class.forName("org.apache.doris.maxcompute.MaxComputeJniScanner$ResultSetColumnValue");
120+
Constructor<?> constructor = clazz.getDeclaredConstructor(Object.class, ColumnType.class, ZoneId.class);
121+
constructor.setAccessible(true);
122+
return (ColumnValue) constructor.newInstance(value, ColumnType.parseType("c1", type), SHANGHAI);
123+
}
124+
}

fe/fe-common/src/main/java/org/apache/doris/common/maxcompute/MCProperties.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@ public class MCProperties {
6868
"mc.datetime_predicate_push_down";
6969
public static final String DEFAULT_DATETIME_PREDICATE_PUSH_DOWN = "true";
7070

71+
public static final String ENABLE_MCQA_QUERY = "mc.enable_mcqa_query";
72+
public static final String DEFAULT_ENABLE_MCQA_QUERY = "false";
73+
public static final String MCQA_QUOTA = "mc.mcqa_quota";
74+
public static final String MCQA_QUERY_LIMIT_THRESHOLD = "mc.mcqa_query_limit_threshold";
75+
public static final String DEFAULT_MCQA_QUERY_LIMIT_THRESHOLD = "4096";
76+
7177
// The account systems for Alibaba Cloud China and International are different. If the primary account is an
7278
// International user, specify ACCOUNT_FORMAT as ACCOUNT_FORMAT_ID. Otherwise, specify ACCOUNT_FORMAT_NAME.
7379
public static final String ACCOUNT_FORMAT = "mc.account_format";

fe/fe-core/src/main/java/org/apache/doris/datasource/maxcompute/MaxComputeExternalCatalog.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ public class MaxComputeExternalCatalog extends ExternalCatalog {
6969
private int connectTimeout;
7070
private int readTimeout;
7171
private int retryTimes;
72+
private long mcqaQueryLimitThreshold;
7273

7374
public boolean dateTimePredicatePushDown;
7475

@@ -191,6 +192,8 @@ protected void initLocalObjectsImpl() {
191192
props.getOrDefault(MCProperties.READ_TIMEOUT, MCProperties.DEFAULT_READ_TIMEOUT));
192193
retryTimes = Integer.parseInt(
193194
props.getOrDefault(MCProperties.RETRY_COUNT, MCProperties.DEFAULT_RETRY_COUNT));
195+
mcqaQueryLimitThreshold = Long.parseLong(props.getOrDefault(
196+
MCProperties.MCQA_QUERY_LIMIT_THRESHOLD, MCProperties.DEFAULT_MCQA_QUERY_LIMIT_THRESHOLD));
194197

195198
RestOptions restOptions = RestOptions.newBuilder()
196199
.withConnectTimeout(connectTimeout)
@@ -324,6 +327,11 @@ public boolean getDateTimePredicatePushDown() {
324327
return dateTimePredicatePushDown;
325328
}
326329

330+
public long getMcqaQueryLimitThreshold() {
331+
makeSureInitialized();
332+
return mcqaQueryLimitThreshold;
333+
}
334+
327335
public ZoneId getProjectDateTimeZone() {
328336
makeSureInitialized();
329337

@@ -429,6 +437,8 @@ public void checkProperties() throws DdlException {
429437
props.getOrDefault(MCProperties.READ_TIMEOUT, MCProperties.DEFAULT_READ_TIMEOUT));
430438
retryTimes = Integer.parseInt(
431439
props.getOrDefault(MCProperties.RETRY_COUNT, MCProperties.DEFAULT_RETRY_COUNT));
440+
mcqaQueryLimitThreshold = Long.parseLong(props.getOrDefault(
441+
MCProperties.MCQA_QUERY_LIMIT_THRESHOLD, MCProperties.DEFAULT_MCQA_QUERY_LIMIT_THRESHOLD));
432442
if (connectTimeout <= 0) {
433443
throw new DdlException(MCProperties.CONNECT_TIMEOUT + " must be greater than 0");
434444
}
@@ -441,9 +451,14 @@ public void checkProperties() throws DdlException {
441451
throw new DdlException(MCProperties.RETRY_COUNT + " must be greater than 0");
442452
}
443453

454+
if (mcqaQueryLimitThreshold <= 0) {
455+
throw new DdlException(MCProperties.MCQA_QUERY_LIMIT_THRESHOLD + " must be greater than 0");
456+
}
457+
444458
} catch (NumberFormatException e) {
445459
throw new DdlException("property " + MCProperties.CONNECT_TIMEOUT + "/"
446-
+ MCProperties.READ_TIMEOUT + "/" + MCProperties.RETRY_COUNT + "must be an integer");
460+
+ MCProperties.READ_TIMEOUT + "/" + MCProperties.RETRY_COUNT + "/"
461+
+ MCProperties.MCQA_QUERY_LIMIT_THRESHOLD + "must be an integer");
447462
}
448463

449464
MCUtils.checkAuthProperties(props);

0 commit comments

Comments
 (0)