Skip to content

Commit 41019c3

Browse files
authored
cherrypick: improve decode (#642)
* improve path decode (#640) * improve path parser * fix path decode cache * fix fmt * improve int & string decode * remove decimal test for now * remove decimal test for now * fix path decode * update test * update test * update version * fix conflict * update test
1 parent 7abe608 commit 41019c3

7 files changed

Lines changed: 654 additions & 198 deletions

File tree

client/src/main/java/com/vesoft/nebula/driver/graph/data/ValueWrapper.java

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import static com.vesoft.nebula.driver.graph.decode.ColumnType.COLUMN_TYPE_ZONEDTIME;
3434

3535
import com.vesoft.nebula.driver.graph.decode.ColumnType;
36+
import com.vesoft.nebula.driver.graph.decode.DateFormatterConst;
3637
import com.vesoft.nebula.driver.graph.exception.InvalidValueException;
3738
import java.math.BigDecimal;
3839
import java.time.LocalDate;
@@ -50,13 +51,6 @@ public class ValueWrapper {
5051
private final Object value;
5152
private final ColumnType type;
5253

53-
DateTimeFormatter zonedDateTimeFormatter =
54-
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXXXX");
55-
DateTimeFormatter localDateTimeFormatter =
56-
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSS");
57-
DateTimeFormatter zonedTimeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss.SSSSSSXXXXX");
58-
DateTimeFormatter localTimeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss.SSSSSS");
59-
6054
public ValueWrapper(Object value, ColumnType type) {
6155
this.value = value;
6256
this.type = type;
@@ -673,13 +667,13 @@ public String toString() {
673667
} else if (isEdge()) {
674668
return asEdge().toString();
675669
} else if (isLocalTime()) {
676-
return asLocalTime().format(localTimeFormatter);
670+
return asLocalTime().format(DateFormatterConst.localTimeFormatter);
677671
} else if (isZonedTime()) {
678-
return asZonedTime().format(zonedTimeFormatter);
672+
return asZonedTime().format(DateFormatterConst.zonedTimeFormatter);
679673
} else if (isLocalDateTime()) {
680-
return asLocalDateTime().format(localDateTimeFormatter);
674+
return asLocalDateTime().format(DateFormatterConst.localDateTimeFormatter);
681675
} else if (isZonedDateTime()) {
682-
return asZonedDateTime().format(zonedDateTimeFormatter);
676+
return asZonedDateTime().format(DateFormatterConst.zonedDateTimeFormatter);
683677
} else if (isDate()) {
684678
return asDate().toString();
685679
} else if (isDuration()) {
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/* Copyright (c) 2025 vesoft inc. All rights reserved.
2+
*
3+
* This source code is licensed under Apache 2.0 License.
4+
*/
5+
6+
package com.vesoft.nebula.driver.graph.decode;
7+
8+
import java.time.format.DateTimeFormatter;
9+
10+
public class DateFormatterConst {
11+
public static DateTimeFormatter zonedDateTimeFormatter =
12+
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXXXX");
13+
public static DateTimeFormatter localDateTimeFormatter =
14+
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSS");
15+
public static DateTimeFormatter zonedTimeFormatter =
16+
DateTimeFormatter.ofPattern("HH:mm:ss.SSSSSSXXXXX");
17+
public static DateTimeFormatter localTimeFormatter =
18+
DateTimeFormatter.ofPattern("HH:mm:ss.SSSSSS");
19+
20+
}

client/src/main/java/com/vesoft/nebula/driver/graph/decode/DecodeUtils.java

Lines changed: 229 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@
55

66
package com.vesoft.nebula.driver.graph.decode;
77

8+
import static com.vesoft.nebula.driver.graph.decode.struct.SizeConstant.CHUNK_INDEX_START_POSITION_IN_STRING_HEADER;
9+
import static com.vesoft.nebula.driver.graph.decode.struct.SizeConstant.CHUNK_OFFSET_START_POSITION_IN_STRING_HEADER;
810
import static com.vesoft.nebula.driver.graph.decode.struct.SizeConstant.ELEMENT_NUMBER_SIZE_FOR_ANY_VALUE;
11+
import static com.vesoft.nebula.driver.graph.decode.struct.SizeConstant.STRING_MAX_VALUE_LENGTH_IN_HEADER;
12+
import static com.vesoft.nebula.driver.graph.decode.struct.SizeConstant.STRING_SIZE;
13+
import static com.vesoft.nebula.driver.graph.decode.struct.SizeConstant.STRING_VALUE_LENGTH_SIZE;
914

1015
import com.google.protobuf.ByteString;
1116
import com.vesoft.nebula.driver.graph.decode.datatype.VectorType;
@@ -18,6 +23,58 @@
1823
public class DecodeUtils {
1924
public static final Charset charset = Charsets.UTF_8;
2025

26+
/**
27+
* decode binary to int directly from ByteString without creating sub-byteString
28+
*
29+
* @param data binary data
30+
* @param offset offset in the data
31+
* @param order byte order
32+
* @return int value
33+
*/
34+
public static int bytesToInt32AtOffset(ByteString data, int offset, ByteOrder order) {
35+
if (order == ByteOrder.LITTLE_ENDIAN) {
36+
return (data.byteAt(offset) & 0xFF)
37+
| ((data.byteAt(offset + 1) & 0xFF) << 8)
38+
| ((data.byteAt(offset + 2) & 0xFF) << 16)
39+
| ((data.byteAt(offset + 3) & 0xFF) << 24);
40+
} else {
41+
return (data.byteAt(offset) << 24)
42+
| ((data.byteAt(offset + 1) & 0xFF) << 16)
43+
| ((data.byteAt(offset + 2) & 0xFF) << 8)
44+
| (data.byteAt(offset + 3) & 0xFF);
45+
}
46+
}
47+
48+
/**
49+
* decode binary to long directly from ByteString without creating sub-byteString
50+
*
51+
* @param data binary data
52+
* @param offset offset in the data
53+
* @param order byte order
54+
* @return long value
55+
*/
56+
public static long bytesToInt64AtOffset(ByteString data, int offset, ByteOrder order) {
57+
if (order == ByteOrder.LITTLE_ENDIAN) {
58+
return (long) (data.byteAt(offset) & 0xFF)
59+
| ((long) (data.byteAt(offset + 1) & 0xFF) << 8)
60+
| ((long) (data.byteAt(offset + 2) & 0xFF) << 16)
61+
| ((long) (data.byteAt(offset + 3) & 0xFF) << 24)
62+
| ((long) (data.byteAt(offset + 4) & 0xFF) << 32)
63+
| ((long) (data.byteAt(offset + 5) & 0xFF) << 40)
64+
| ((long) (data.byteAt(offset + 6) & 0xFF) << 48)
65+
| ((long) (data.byteAt(offset + 7) & 0xFF) << 56);
66+
} else {
67+
return ((long) data.byteAt(offset) << 56)
68+
| ((long) (data.byteAt(offset + 1) & 0xFF) << 48)
69+
| ((long) (data.byteAt(offset + 2) & 0xFF) << 40)
70+
| ((long) (data.byteAt(offset + 3) & 0xFF) << 32)
71+
| ((long) (data.byteAt(offset + 4) & 0xFF) << 24)
72+
| ((long) (data.byteAt(offset + 5) & 0xFF) << 16)
73+
| ((long) (data.byteAt(offset + 6) & 0xFF) << 8)
74+
| (data.byteAt(offset + 7) & 0xFF);
75+
}
76+
}
77+
2178
/**
2279
* decode binary to byte
2380
*
@@ -38,15 +95,43 @@ public static int bytesToUInt8(ByteString data) {
3895
return data.byteAt(0) & 0xFF;
3996
}
4097

98+
/**
99+
* decode binary to byte at offset
100+
*
101+
* @param data binary data
102+
* @param offset offset in the data
103+
* @return int value
104+
*/
105+
public static int bytesToInt8AtOffset(ByteString data, int offset) {
106+
return data.byteAt(offset);
107+
}
108+
109+
/**
110+
* decode binary to unsigned byte at offset
111+
*
112+
* @param data binary data
113+
* @param offset offset in the data
114+
* @return uint value
115+
*/
116+
public static int bytesToUInt8AtOffset(ByteString data, int offset) {
117+
return data.byteAt(offset) & 0xFF;
118+
}
119+
41120
/**
42121
* decode binary to short
43122
*
44123
* @param data binary data
45124
* @return short value
46125
*/
47126
public static Short bytesToInt16(ByteString data, ByteOrder order) {
48-
ByteBuffer buffer = ByteBuffer.wrap(data.toByteArray());
49-
return buffer.order(order).getShort();
127+
if (data.size() < 2) {
128+
throw new java.nio.BufferUnderflowException();
129+
}
130+
if (order == ByteOrder.LITTLE_ENDIAN) {
131+
return (short) ((data.byteAt(0) & 0xFF) | ((data.byteAt(1) & 0xFF) << 8));
132+
} else {
133+
return (short) ((data.byteAt(0) << 8) | (data.byteAt(1) & 0xFF));
134+
}
50135
}
51136

52137
/**
@@ -59,15 +144,55 @@ public static int bytesToUInt16(ByteString data, ByteOrder order) {
59144
return bytesToInt16(data, order) & 0xFFFF;
60145
}
61146

147+
/**
148+
* decode binary to unsigned short at offset
149+
*
150+
* @param data binary data
151+
* @param offset offset in the data
152+
* @param order byte order
153+
* @return short value
154+
*/
155+
public static int bytesToUInt16AtOffset(ByteString data, int offset, ByteOrder order) {
156+
return bytesToInt16AtOffset(data, offset, order) & 0xFFFF;
157+
}
158+
159+
/**
160+
* decode binary to short at offset
161+
*
162+
* @param data binary data
163+
* @param offset offset in the data
164+
* @param order byte order
165+
* @return short value
166+
*/
167+
public static short bytesToInt16AtOffset(ByteString data, int offset, ByteOrder order) {
168+
if (order == ByteOrder.LITTLE_ENDIAN) {
169+
return (short) ((data.byteAt(offset) & 0xFF) | ((data.byteAt(offset + 1) & 0xFF) << 8));
170+
} else {
171+
return (short) ((data.byteAt(offset) << 8) | (data.byteAt(offset + 1) & 0xFF));
172+
}
173+
}
174+
62175
/**
63176
* decode binary to int
64177
*
65178
* @param data binary data
66179
* @return int value
67180
*/
68181
public static int bytesToInt32(ByteString data, ByteOrder order) {
69-
ByteBuffer buffer = ByteBuffer.wrap(data.toByteArray());
70-
return buffer.order(order).getInt();
182+
if (data.size() < 4) {
183+
throw new java.nio.BufferUnderflowException();
184+
}
185+
if (order == ByteOrder.LITTLE_ENDIAN) {
186+
return (data.byteAt(0) & 0xFF)
187+
| ((data.byteAt(1) & 0xFF) << 8)
188+
| ((data.byteAt(2) & 0xFF) << 16)
189+
| ((data.byteAt(3) & 0xFF) << 24);
190+
} else {
191+
return (data.byteAt(0) << 24)
192+
| ((data.byteAt(1) & 0xFF) << 16)
193+
| ((data.byteAt(2) & 0xFF) << 8)
194+
| (data.byteAt(3) & 0xFF);
195+
}
71196
}
72197

73198

@@ -81,15 +206,109 @@ public static long bytesToUInt32(ByteString data, ByteOrder order) {
81206
return Integer.toUnsignedLong(bytesToInt32(data, order));
82207
}
83208

209+
/**
210+
* decode binary to float at offset
211+
*
212+
* @param data binary data
213+
* @param offset offset in the data
214+
* @param order byte order
215+
* @return float value
216+
*/
217+
public static float bytesToFloatAtOffset(ByteString data, int offset, ByteOrder order) {
218+
int bits = bytesToInt32AtOffset(data, offset, order);
219+
return Float.intBitsToFloat(bits);
220+
}
221+
222+
/**
223+
* decode binary to double at offset
224+
*
225+
* @param data binary data
226+
* @param offset offset in the data
227+
* @param order byte order
228+
* @return double value
229+
*/
230+
public static double bytesToDoubleAtOffset(ByteString data, int offset, ByteOrder order) {
231+
long bits = bytesToInt64AtOffset(data, offset, order);
232+
return Double.longBitsToDouble(bits);
233+
}
234+
235+
/**
236+
* decode binary to bool at offset
237+
*
238+
* @param data binary data
239+
* @param offset offset in the data
240+
* @return Boolean value
241+
*/
242+
public static boolean bytesToBoolAtOffset(ByteString data, int offset) {
243+
return data.byteAt(offset) == 0x01;
244+
}
245+
246+
/**
247+
* decode flat string directly from vector data at specified row
248+
*
249+
* @param vectorData vector data
250+
* @param rowIndex row index
251+
* @param order byte order
252+
* @return String value
253+
*/
254+
public static String decodeFlatString(ByteString vectorData, int rowIndex, ByteOrder order) {
255+
int offset = rowIndex * STRING_SIZE;
256+
257+
// Read string length
258+
int stringValueLength = bytesToInt32AtOffset(vectorData, offset, order);
259+
260+
if (stringValueLength <= STRING_MAX_VALUE_LENGTH_IN_HEADER) {
261+
// Short string: data is in the header
262+
int dataOffset = offset + STRING_VALUE_LENGTH_SIZE;
263+
return vectorData.substring(dataOffset, dataOffset + stringValueLength)
264+
.toString(charset);
265+
}
266+
267+
// Long string: read chunk index and offset
268+
int chunkIndex = bytesToInt32AtOffset(
269+
vectorData,
270+
offset + CHUNK_INDEX_START_POSITION_IN_STRING_HEADER,
271+
order);
272+
int chunkOffset = bytesToInt32AtOffset(
273+
vectorData,
274+
offset + CHUNK_OFFSET_START_POSITION_IN_STRING_HEADER,
275+
order);
276+
277+
// Note: For flat string, we can't access nested vectors without passing them
278+
// This method is optimized for the common case where the string is short
279+
// For long strings, fallback to the original bytesToString method
280+
return null;
281+
}
282+
84283
/**
85284
* decode binary to long
86285
*
87286
* @param data binary data
88287
* @return long value
89288
*/
90289
public static long bytesToInt64(ByteString data, ByteOrder order) {
91-
ByteBuffer buffer = ByteBuffer.wrap(data.toByteArray());
92-
return buffer.order(order).getLong();
290+
if (data.size() < 8) {
291+
throw new java.nio.BufferUnderflowException();
292+
}
293+
if (order == ByteOrder.LITTLE_ENDIAN) {
294+
return (long) (data.byteAt(0) & 0xFF)
295+
| ((long) (data.byteAt(1) & 0xFF) << 8)
296+
| ((long) (data.byteAt(2) & 0xFF) << 16)
297+
| ((long) (data.byteAt(3) & 0xFF) << 24)
298+
| ((long) (data.byteAt(4) & 0xFF) << 32)
299+
| ((long) (data.byteAt(5) & 0xFF) << 40)
300+
| ((long) (data.byteAt(6) & 0xFF) << 48)
301+
| ((long) (data.byteAt(7) & 0xFF) << 56);
302+
} else {
303+
return ((long) data.byteAt(0) << 56)
304+
| ((long) (data.byteAt(1) & 0xFF) << 48)
305+
| ((long) (data.byteAt(2) & 0xFF) << 40)
306+
| ((long) (data.byteAt(3) & 0xFF) << 32)
307+
| ((long) (data.byteAt(4) & 0xFF) << 24)
308+
| ((long) (data.byteAt(5) & 0xFF) << 16)
309+
| ((long) (data.byteAt(6) & 0xFF) << 8)
310+
| (data.byteAt(7) & 0xFF);
311+
}
93312
}
94313

95314

@@ -100,8 +319,8 @@ public static long bytesToInt64(ByteString data, ByteOrder order) {
100319
* @return float value
101320
*/
102321
public static float bytesToFloat(ByteString data, ByteOrder order) {
103-
ByteBuffer buffer = ByteBuffer.wrap(data.toByteArray());
104-
return buffer.order(order).getFloat();
322+
int bits = bytesToInt32(data, order);
323+
return Float.intBitsToFloat(bits);
105324
}
106325

107326
/**
@@ -111,8 +330,8 @@ public static float bytesToFloat(ByteString data, ByteOrder order) {
111330
* @return double value
112331
*/
113332
public static double bytesToDouble(ByteString data, ByteOrder order) {
114-
ByteBuffer buffer = ByteBuffer.wrap(data.toByteArray());
115-
return buffer.order(order).getDouble();
333+
long bits = bytesToInt64(data, order);
334+
return Double.longBitsToDouble(bits);
116335
}
117336

118337
/**

0 commit comments

Comments
 (0)