Skip to content

Commit 81f5ca6

Browse files
authored
[IOTDB-4156] import csv has error time after timestamp_precision set ns (apache#7032)
1 parent 66e53e1 commit 81f5ca6

File tree

7 files changed

+103
-64
lines changed

7 files changed

+103
-64
lines changed

cli/pom.xml

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,12 @@
8383
<groupId>org.apache.iotdb</groupId>
8484
<artifactId>iotdb-server</artifactId>
8585
<version>${project.version}</version>
86-
<scope>test</scope>
86+
<exclusions>
87+
<exclusion>
88+
<groupId>*</groupId>
89+
<artifactId>*</artifactId>
90+
</exclusion>
91+
</exclusions>
8792
</dependency>
8893
<dependency>
8994
<groupId>org.apache.commons</groupId>
@@ -124,6 +129,36 @@
124129
<skipITs>${cli.it.skip}</skipITs>
125130
</configuration>
126131
</plugin>
132+
<plugin>
133+
<groupId>org.apache.maven.plugins</groupId>
134+
<artifactId>maven-shade-plugin</artifactId>
135+
<version>3.3.0</version>
136+
<executions>
137+
<execution>
138+
<phase>package</phase>
139+
<goals>
140+
<goal>shade</goal>
141+
</goals>
142+
<configuration>
143+
<createDependencyReducedPom>false</createDependencyReducedPom>
144+
<artifactSet>
145+
<includes>
146+
<include>org.apache.iotdb:iotdb-cli</include>
147+
<include>org.apache.iotdb:iotdb-server</include>
148+
</includes>
149+
</artifactSet>
150+
<filters>
151+
<filter>
152+
<artifact>org.apache.iotdb:iotdb-server</artifact>
153+
<includes>
154+
<include>org/apache/iotdb/db/qp/utils/*</include>
155+
</includes>
156+
</filter>
157+
</filters>
158+
</configuration>
159+
</execution>
160+
</executions>
161+
</plugin>
127162
<plugin>
128163
<groupId>org.apache.maven.plugins</groupId>
129164
<artifactId>maven-assembly-plugin</artifactId>

cli/src/assembly/cli.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828
<includeBaseDirectory>false</includeBaseDirectory>
2929
<dependencySets>
3030
<dependencySet>
31+
<excludes>
32+
<exclude>org.apache.iotdb:iotdb-server</exclude>
33+
</excludes>
3134
<outputDirectory>lib</outputDirectory>
3235
</dependencySet>
3336
</dependencySets>

cli/src/main/java/org/apache/iotdb/tool/ImportCsv.java

Lines changed: 31 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
package org.apache.iotdb.tool;
2121

22+
import org.apache.iotdb.db.qp.utils.DatetimeUtils;
2223
import org.apache.iotdb.exception.ArgsErrorException;
2324
import org.apache.iotdb.rpc.IoTDBConnectionException;
2425
import org.apache.iotdb.rpc.StatementExecutionException;
@@ -42,7 +43,6 @@
4243
import java.io.FileInputStream;
4344
import java.io.IOException;
4445
import java.io.InputStreamReader;
45-
import java.text.ParseException;
4646
import java.text.SimpleDateFormat;
4747
import java.util.ArrayList;
4848
import java.util.Arrays;
@@ -82,6 +82,9 @@ public class ImportCsv extends AbstractCsvTool {
8282
private static final String CSV_SUFFIXS = "csv";
8383
private static final String TXT_SUFFIXS = "txt";
8484

85+
private static final String TIMESTAMP_PRECISION_ARGS = "tp";
86+
private static final String TIMESTAMP_PRECISION_NAME = "timestamp precision (ms/us/ns)";
87+
8588
private static final String TSFILEDB_CLI_PREFIX = "ImportCsv";
8689

8790
private static String targetPath;
@@ -93,6 +96,8 @@ public class ImportCsv extends AbstractCsvTool {
9396

9497
private static int batchPointSize = 100_000;
9598

99+
private static String timestampPrecision = "ms";
100+
96101
/**
97102
* create the commandline options.
98103
*
@@ -153,6 +158,14 @@ private static Options createOptions() {
153158
.build();
154159
options.addOption(opBatchPointSize);
155160

161+
Option opTimestampPrecision =
162+
Option.builder(TIMESTAMP_PRECISION_ARGS)
163+
.argName(TIMESTAMP_PRECISION_ARGS)
164+
.hasArg()
165+
.desc("Timestamp precision (ms/us/ns)")
166+
.build();
167+
options.addOption(opTimestampPrecision);
168+
156169
return options;
157170
}
158171

@@ -178,6 +191,10 @@ private static void parseSpecialParams(CommandLine commandLine) {
178191
if (commandLine.getOptionValue(ALIGNED_ARGS) != null) {
179192
aligned = Boolean.valueOf(commandLine.getOptionValue(ALIGNED_ARGS));
180193
}
194+
195+
if (commandLine.getOptionValue(TIMESTAMP_PRECISION_ARGS) != null) {
196+
timestampPrecision = commandLine.getOptionValue(TIMESTAMP_PRECISION_ARGS);
197+
}
181198
}
182199

183200
public static void main(String[] args) throws IoTDBConnectionException {
@@ -345,7 +362,6 @@ private static void writeDataAlignedByTime(
345362
List<List<TSDataType>> typesList = new ArrayList<>();
346363
List<List<Object>> valuesList = new ArrayList<>();
347364

348-
AtomicReference<SimpleDateFormat> timeFormatter = new AtomicReference<>(null);
349365
AtomicReference<Boolean> hasStarted = new AtomicReference<>(false);
350366
AtomicInteger pointSize = new AtomicInteger(0);
351367

@@ -355,7 +371,6 @@ private static void writeDataAlignedByTime(
355371
record -> {
356372
if (!hasStarted.get()) {
357373
hasStarted.set(true);
358-
timeFormatter.set(formatterInit(record.get(0)));
359374
} else if (pointSize.get() >= batchPointSize) {
360375
writeAndEmptyDataSet(deviceIds, times, typesList, valuesList, measurementsList, 3);
361376
pointSize.set(0);
@@ -403,17 +418,7 @@ record -> {
403418
}
404419
}
405420
if (!measurements.isEmpty()) {
406-
if (timeFormatter.get() == null) {
407-
times.add(Long.valueOf(record.get(timeColumn)));
408-
} else {
409-
try {
410-
times.add(timeFormatter.get().parse(record.get(timeColumn)).getTime());
411-
} catch (ParseException e) {
412-
System.out.println(
413-
"Meet error when insert csv because the format of time is not supported");
414-
System.exit(0);
415-
}
416-
}
421+
times.add(parseTimestamp(record.get(timeColumn)));
417422
deviceIds.add(deviceId);
418423
typesList.add(types);
419424
valuesList.add(values);
@@ -472,7 +477,7 @@ record -> {
472477
// only run in first record
473478
if (deviceName.get() == null) {
474479
deviceName.set(record.get(1));
475-
timeFormatter.set(formatterInit(record.get(0)));
480+
// timeFormatter.set(formatterInit(record.get(0)));
476481
} else if (!Objects.equals(deviceName.get(), record.get(1))) {
477482
// if device changed
478483
writeAndEmptyDataSet(
@@ -547,13 +552,7 @@ record -> {
547552
if (timeFormatter.get() == null) {
548553
times.add(Long.valueOf(record.get(timeColumn)));
549554
} else {
550-
try {
551-
times.add(timeFormatter.get().parse(record.get(timeColumn)).getTime());
552-
} catch (ParseException e) {
553-
System.out.println(
554-
"Meet error when insert csv because the format of time is not supported");
555-
System.exit(0);
556-
}
555+
times.add(parseTimestamp(record.get(timeColumn)));
557556
}
558557
typesList.add(types);
559558
valuesList.add(values);
@@ -739,32 +738,6 @@ private static boolean queryType(
739738
}
740739
}
741740

742-
/**
743-
* return a suit time formatter
744-
*
745-
* @param time
746-
* @return
747-
*/
748-
private static SimpleDateFormat formatterInit(String time) {
749-
try {
750-
Long.parseLong(time);
751-
return null;
752-
} catch (Exception ignored) {
753-
// do nothing
754-
}
755-
756-
for (String timeFormat : STRING_TIME_FORMAT) {
757-
SimpleDateFormat format = new SimpleDateFormat(timeFormat);
758-
try {
759-
format.parse(time);
760-
return format;
761-
} catch (java.text.ParseException ignored) {
762-
// do nothing
763-
}
764-
}
765-
return null;
766-
}
767-
768741
/**
769742
* return the TSDataType
770743
*
@@ -854,4 +827,14 @@ private static Object typeTrans(String value, TSDataType type) {
854827
return null;
855828
}
856829
}
830+
831+
private static long parseTimestamp(String str) {
832+
long timestamp;
833+
try {
834+
timestamp = Long.parseLong(str);
835+
} catch (NumberFormatException e) {
836+
timestamp = DatetimeUtils.convertDatetimeStrToLong(str, zoneId, timestampPrecision);
837+
}
838+
return timestamp;
839+
}
857840
}

docs/UserGuide/Write-And-Delete-Data/CSV-Tool.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,9 @@ Time,Device,str(TEXT),int(INT32)
174174

175175
```shell
176176
# Unix/OS X
177-
> tools/import-csv.sh -h <ip> -p <port> -u <username> -pw <password> -f <xxx.csv> [-fd <./failedDirectory>] [-aligned <true>]
177+
> tools/import-csv.sh -h <ip> -p <port> -u <username> -pw <password> -f <xxx.csv> [-fd <./failedDirectory>] [-aligned <true>] [-tp <ms/ns/us>]
178178
# Windows
179-
> tools\import-csv.bat -h <ip> -p <port> -u <username> -pw <password> -f <xxx.csv> [-fd <./failedDirectory>] [-aligned <true>]
179+
> tools\import-csv.bat -h <ip> -p <port> -u <username> -pw <password> -f <xxx.csv> [-fd <./failedDirectory>] [-aligned <true>] [-tp <ms/ns/us>]
180180
```
181181

182182
Description:
@@ -197,6 +197,9 @@ Description:
197197
- specifying the point's number of a batch. If the program throw the exception `org.apache.thrift.transport.TTransportException: Frame size larger than protect max size`, you can lower this parameter as appropriate.
198198
- example: `-batch 100000`, `100000` is the default value.
199199

200+
* `-tp <time-precision>`:
201+
- specifying a time precision. Options includes `ms`(millisecond), `ns`(nanosecond), and `us`(microsecond), `ms` is default.
202+
200203
### Example
201204

202205
```sh
@@ -208,6 +211,8 @@ Description:
208211
> tools\import-csv.bat -h 127.0.0.1 -p 6667 -u root -pw root -f example-filename.csv
209212
# or
210213
> tools\import-csv.bat -h 127.0.0.1 -p 6667 -u root -pw root -f example-filename.csv -fd .\failed
214+
# or
215+
> tools\import-csv.bat -h 127.0.0.1 -p 6667 -u root -pw root -f example-filename.csv -fd .\failed -tp ns
211216
```
212217

213218
### Note

docs/zh/UserGuide/Write-And-Delete-Data/CSV-Tool.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,9 +175,9 @@ Time,Device,str(TEXT),int(INT32)
175175

176176
```shell
177177
# Unix/OS X
178-
>tools/import-csv.sh -h <ip> -p <port> -u <username> -pw <password> -f <xxx.csv> [-fd <./failedDirectory>] [-aligned <true>]
178+
>tools/import-csv.sh -h <ip> -p <port> -u <username> -pw <password> -f <xxx.csv> [-fd <./failedDirectory>] [-aligned <true>] [-tp <ms/ns/us>]
179179
# Windows
180-
>tools\import-csv.bat -h <ip> -p <port> -u <username> -pw <password> -f <xxx.csv> [-fd <./failedDirectory>] [-aligned <true>]
180+
>tools\import-csv.bat -h <ip> -p <port> -u <username> -pw <password> -f <xxx.csv> [-fd <./failedDirectory>] [-aligned <true>] [-tp <ms/ns/us>]
181181
```
182182

183183
参数:
@@ -198,6 +198,9 @@ Time,Device,str(TEXT),int(INT32)
198198
- 用于指定每一批插入的数据的点数。如果程序报了`org.apache.thrift.transport.TTransportException: Frame size larger than protect max size`这个错的话,就可以适当的调低这个参数。
199199
- 例如: `-batch 100000``100000`是默认值。
200200

201+
* `-tp`:
202+
- 用于指定时间精度,可选值包括`ms`(毫秒),`ns`(纳秒),`us`(微秒),默认值为`ms`
203+
201204
### 运行示例
202205

203206
```sh
@@ -209,6 +212,8 @@ Time,Device,str(TEXT),int(INT32)
209212
>tools\import-csv.bat -h 127.0.0.1 -p 6667 -u root -pw root -f example-filename.csv
210213
# or
211214
>tools\import-csv.bat -h 127.0.0.1 -p 6667 -u root -pw root -f example-filename.csv -fd .\failed
215+
# or
216+
> tools\import-csv.bat -h 127.0.0.1 -p 6667 -u root -pw root -f example-filename.csv -fd .\failed -tp ns
212217
```
213218

214219
### 注意

server/src/main/java/org/apache/iotdb/db/qp/utils/DatetimeUtils.java

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,16 @@ private DatetimeUtils() {
450450
.toFormatter();
451451

452452
public static long convertDatetimeStrToLong(String str, ZoneId zoneId) {
453-
return convertDatetimeStrToLong(str, toZoneOffset(zoneId), 0);
453+
return convertDatetimeStrToLong(
454+
str,
455+
toZoneOffset(zoneId),
456+
0,
457+
IoTDBDescriptor.getInstance().getConfig().getTimestampPrecision());
458+
}
459+
460+
public static long convertDatetimeStrToLong(
461+
String str, ZoneId zoneId, String timestampPrecision) {
462+
return convertDatetimeStrToLong(str, toZoneOffset(zoneId), 0, timestampPrecision);
454463
}
455464

456465
public static long getInstantWithPrecision(String str, String timestampPrecision) {
@@ -478,10 +487,8 @@ public static long getInstantWithPrecision(String str, String timestampPrecision
478487
}
479488

480489
/** convert date time string to millisecond, microsecond or nanosecond. */
481-
public static long convertDatetimeStrToLong(String str, ZoneOffset offset, int depth) {
482-
483-
String timestampPrecision = IoTDBDescriptor.getInstance().getConfig().getTimestampPrecision();
484-
490+
public static long convertDatetimeStrToLong(
491+
String str, ZoneOffset offset, int depth, String timestampPrecision) {
485492
if (depth >= 2) {
486493
throw new DateTimeException(
487494
String.format(
@@ -490,12 +497,13 @@ public static long convertDatetimeStrToLong(String str, ZoneOffset offset, int d
490497
str, offset));
491498
}
492499
if (str.contains("Z")) {
493-
return convertDatetimeStrToLong(str.substring(0, str.indexOf('Z')) + "+00:00", offset, depth);
500+
return convertDatetimeStrToLong(
501+
str.substring(0, str.indexOf('Z')) + "+00:00", offset, depth, timestampPrecision);
494502
} else if (str.length() == 10) {
495-
return convertDatetimeStrToLong(str + "T00:00:00", offset, depth);
503+
return convertDatetimeStrToLong(str + "T00:00:00", offset, depth, timestampPrecision);
496504
} else if (str.length() - str.lastIndexOf('+') != 6
497505
&& str.length() - str.lastIndexOf('-') != 6) {
498-
return convertDatetimeStrToLong(str + offset, offset, depth + 1);
506+
return convertDatetimeStrToLong(str + offset, offset, depth + 1, timestampPrecision);
499507
} else if (str.contains("[") || str.contains("]")) {
500508
throw new DateTimeException(
501509
String.format(

server/src/test/java/org/apache/iotdb/db/qp/utils/DatetimeQueryDataSetUtilsTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ public void testConvertDatetimeStrToLongWithoutMS(ZoneOffset zoneOffset, ZoneId
189189
"2019.01.02T15:13:27" + zoneOffset,
190190
};
191191
for (String str : timeFormatWithoutMs) {
192-
Assert.assertEquals(res, DatetimeUtils.convertDatetimeStrToLong(str, zoneOffset, 0));
192+
Assert.assertEquals(res, DatetimeUtils.convertDatetimeStrToLong(str, zoneOffset, 0, "ms"));
193193
}
194194

195195
for (String str : timeFormatWithoutMs) {
@@ -215,7 +215,7 @@ public void testConvertDatetimeStrToLongWithMS(ZoneOffset zoneOffset, ZoneId zon
215215
"2019.01.02T15:13:27.689" + zoneOffset,
216216
};
217217
for (String str : timeFormatWithoutMs) {
218-
assertEquals(res, DatetimeUtils.convertDatetimeStrToLong(str, zoneOffset, 0));
218+
assertEquals(res, DatetimeUtils.convertDatetimeStrToLong(str, zoneOffset, 0, "ms"));
219219
}
220220

221221
for (String str : timeFormatWithoutMs) {
@@ -230,7 +230,7 @@ public void testConvertDateStrToLong(ZoneOffset zoneOffset, ZoneId zoneId, long
230230
"2019-01-02", "2019/01/02", "2019.01.02",
231231
};
232232
for (String str : timeFormatWithoutMs) {
233-
assertEquals(res, DatetimeUtils.convertDatetimeStrToLong(str, zoneOffset, 0));
233+
assertEquals(res, DatetimeUtils.convertDatetimeStrToLong(str, zoneOffset, 0, "ms"));
234234
}
235235

236236
for (String str : timeFormatWithoutMs) {

0 commit comments

Comments
 (0)