Apache TsFile 快速入门与集成示例
tsfile 2.4.0 完整快速入门工程:pom 全文、schema 定义、多设备写入、条件查询与表模型示例,附编码压缩对比实测、Python SDK 示例及 IoTDB、Flume、Flink 集成说明。
Apache TsFile 快速入门与集成示例
一、版本与环境
本文基于 tsfile 2.4.0(Maven Central 最新稳定版,强制 JDK 17+)实测,宿主环境 OpenJDK 17 + Maven 3.6.3/3.9.16,Ubuntu 22.04 与 CentOS 8 双端验证结果一致。若需对接 IoTDB 落库,请先确认版本对应关系:IoTDB 1.3.4 依赖 tsfile 1.1.1、IoTDB 2.0.2 依赖 tsfile 2.0.2(均实测自双方 Maven 父 POM)。
二、完整快速入门工程
2.1 pom.xml 全文
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>tsfile-demo</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<tsfile.version>2.4.0</tsfile.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.tsfile</groupId>
<artifactId>tsfile</artifactId>
<version>${tsfile.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.17</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.2.0</version>
</plugin>
</plugins>
</build>
</project>
依赖说明:tsfile 2.4.0 传递引入 common-2.4.0、zstd-jni 1.5.6-3、snappy-java 1.1.10.5、lz4-java 1.10.1、xz 1.10、slf4j-api 2.0.17、antlr4-runtime 4.13.2(实测 mvn dependency:tree 回显);slf4j-simple 仅做日志绑定,可换成业务侧已有实现。
2.2 schema 定义
树模型下按「设备 → 测点」组织 schema。要点:2.x 的 TSDataType 在 org.apache.tsfile.enums 包;Schema.registerMeasurementGroup(Path, MeasurementGroup) 注册一组测点,MeasurementGroup 第一个参数表示是否对齐序列;每个 MeasurementSchema 可独立指定编码与压缩:
Schema schema = new Schema();
List<IMeasurementSchema> m1 = new ArrayList<>();
m1.add(new MeasurementSchema("temperature", TSDataType.FLOAT, TSEncoding.RLE, CompressionType.SNAPPY));
m1.add(new MeasurementSchema("humidity", TSDataType.DOUBLE, TSEncoding.GORILLA, CompressionType.ZSTD));
m1.add(new MeasurementSchema("status", TSDataType.TEXT, TSEncoding.PLAIN, CompressionType.UNCOMPRESSED));
schema.registerMeasurementGroup(new Path("root.demo.device1"),
new MeasurementGroup(false, m1));
List<IMeasurementSchema> m2 = new ArrayList<>();
m2.add(new MeasurementSchema("voltage", TSDataType.INT32, TSEncoding.TS_2DIFF, CompressionType.LZ4));
m2.add(new MeasurementSchema("current", TSDataType.INT64, TSEncoding.TS_2DIFF, CompressionType.GZIP));
schema.registerMeasurementGroup(new Path("root.demo.device2"),
new MeasurementGroup(false, m2));
类型与编码的合法组合可运行期查询 TSEncoding.TYPE_SUPPORTED_ENCODINGS(如 FLOAT 支持 GORILLA/CHIMP/SPRINTZ/RLE/PLAIN/RLBE/TS_2DIFF/GORILLA_V1;TEXT 仅 PLAIN/DICTIONARY)。
2.3 写入代码
完整类 demo.WriteDemo:写入两个设备共 5 个测点、每设备 2000 行、每批 500 行。注意 Tablet 默认容量 1024 行,行数用 setRowSize 设置(2.4.0 无 setRowNumber 方法,实测编译报 cannot find symbol):
package demo;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.apache.tsfile.common.conf.TSFileConfig;
import org.apache.tsfile.common.conf.TSFileDescriptor;
import org.apache.tsfile.enums.TSDataType;
import org.apache.tsfile.file.metadata.enums.CompressionType;
import org.apache.tsfile.file.metadata.enums.TSEncoding;
import org.apache.tsfile.write.TsFileWriter;
import org.apache.tsfile.write.record.Tablet;
import org.apache.tsfile.write.schema.IMeasurementSchema;
import org.apache.tsfile.write.schema.MeasurementSchema;
import org.apache.tsfile.write.schema.Schema;
public class WriteDemo {
public static void main(String[] args) throws Exception {
TSFileConfig config = TSFileDescriptor.getInstance().getConfig();
config.setPageSizeInByte(64 * 1024);
config.setGroupSizeInByte(8 * 1024 * 1024);
File f = new File("demo.tsfile");
if (f.exists()) {
f.delete();
}
Schema schema = new Schema();
String device1 = "root.demo.device1";
String device2 = "root.demo.device2";
List<IMeasurementSchema> m1 = new ArrayList<>();
m1.add(new MeasurementSchema("temperature", TSDataType.FLOAT, TSEncoding.RLE, CompressionType.SNAPPY));
m1.add(new MeasurementSchema("humidity", TSDataType.DOUBLE, TSEncoding.GORILLA, CompressionType.ZSTD));
m1.add(new MeasurementSchema("status", TSDataType.TEXT, TSEncoding.PLAIN, CompressionType.UNCOMPRESSED));
schema.registerMeasurementGroup(new org.apache.tsfile.read.common.Path(device1),
new org.apache.tsfile.utils.MeasurementGroup(false, m1));
List<IMeasurementSchema> m2 = new ArrayList<>();
m2.add(new MeasurementSchema("voltage", TSDataType.INT32, TSEncoding.TS_2DIFF, CompressionType.LZ4));
m2.add(new MeasurementSchema("current", TSDataType.INT64, TSEncoding.TS_2DIFF, CompressionType.GZIP));
schema.registerMeasurementGroup(new org.apache.tsfile.read.common.Path(device2),
new org.apache.tsfile.utils.MeasurementGroup(false, m2));
long start = System.currentTimeMillis();
try (TsFileWriter writer = new TsFileWriter(f, schema, config)) {
long baseTime = 1700000000000L;
int batch = 500;
for (long t = 0; t < 2000; t += batch) {
Tablet tab1 = new Tablet(device1, m1);
for (int r = 0; r < batch; r++) {
long ts = baseTime + (t + r) * 1000L;
tab1.addTimestamp(r, ts);
tab1.addValue("temperature", r, 20.0f + (t + r) % 10);
tab1.addValue("humidity", r, 45.0 + (t + r) % 5);
tab1.addValue("status", r, ((t + r) % 2 == 0) ? "OK" : "WARN");
}
tab1.setRowSize(batch);
writer.writeTree(tab1);
Tablet tab2 = new Tablet(device2, m2);
for (int r = 0; r < batch; r++) {
long ts = baseTime + (t + r) * 1000L;
tab2.addTimestamp(r, ts);
tab2.addValue("voltage", r, (int) (220 + (t + r) % 3));
tab2.addValue("current", r, 1000L + (t + r) % 7);
}
tab2.setRowSize(batch);
writer.writeTree(tab2);
}
writer.flush();
}
System.out.println("写入完成: " + f.getAbsolutePath()
+ " 大小=" + f.length() + " 字节");
}
}
2.4 读取代码
完整类 demo.ReadDemo:TsFileSequenceReader 负责文件元数据(设备、测点类型);TsFileReader.query(QueryExpression) 负责条件查询,时间过滤用 TimeFilterApi 组合 GlobalTimeExpression(实测 2.4.0 中 TimeFilterApi.gtEq/lt 返回类型即 Filter 子类,可直接包装):
package demo;
import java.util.List;
import org.apache.tsfile.enums.TSDataType;
import org.apache.tsfile.file.metadata.IDeviceID;
import org.apache.tsfile.read.TsFileReader;
import org.apache.tsfile.read.TsFileSequenceReader;
import org.apache.tsfile.read.common.Field;
import org.apache.tsfile.read.common.Path;
import org.apache.tsfile.read.common.RowRecord;
import org.apache.tsfile.read.expression.IExpression;
import org.apache.tsfile.read.expression.QueryExpression;
import org.apache.tsfile.read.expression.impl.BinaryExpression;
import org.apache.tsfile.read.expression.impl.GlobalTimeExpression;
import org.apache.tsfile.read.filter.factory.TimeFilterApi;
import org.apache.tsfile.read.query.dataset.QueryDataSet;
public class ReadDemo {
public static void main(String[] args) throws Exception {
String file = "demo.tsfile";
TsFileSequenceReader seqReader = new TsFileSequenceReader(file);
System.out.println("== 设备列表 ==");
List<IDeviceID> devices = seqReader.getAllDevices();
for (IDeviceID dev : devices) {
System.out.println("device: " + dev);
}
System.out.println("== 设备测点(类型) ==");
for (IDeviceID dev : devices) {
seqReader.getMeasurement(dev).forEach((m, t) ->
System.out.println(dev + " -> " + m + " : " + t));
}
seqReader.close();
TsFileSequenceReader reader = new TsFileSequenceReader(file);
try (TsFileReader tsFileReader = new TsFileReader(reader)) {
QueryExpression query = QueryExpression.create()
.addSelectedPath(new Path("root.demo.device1", "temperature", true))
.addSelectedPath(new Path("root.demo.device1", "humidity", true));
long start = 1700000000000L;
IExpression timeFilter = BinaryExpression.and(
new GlobalTimeExpression(TimeFilterApi.gtEq(start)),
new GlobalTimeExpression(TimeFilterApi.lt(start + 3000)));
query.setExpression(timeFilter);
QueryDataSet dataSet = tsFileReader.query(query);
System.out.println("== 查询结果 ==");
int rows = 0;
while (dataSet.hasNext() && rows < 3) {
RowRecord record = dataSet.next();
StringBuilder sb = new StringBuilder();
sb.append(record.getTimestamp());
for (Field field : record.getFields()) {
sb.append(" | ").append(field.getDataType()).append(":")
.append(field.getObjectValue(field.getDataType()));
}
System.out.println(sb);
rows++;
}
System.out.println("共命中 " + rows + " 行(本次仅展示 3 行)");
}
}
}
2.5 运行回显
cd /root/tsfile-demo
export MAVEN_OPTS="-Xms256m -Xmx512m -Dfile.encoding=UTF-8"
mvn -q compile exec:java -Dexec.mainClass=demo.WriteDemo
mvn -q compile exec:java -Dexec.mainClass=demo.ReadDemo
写入实测回显:
写入完成: /root/tsfile-demo/demo.tsfile 大小=9984 字节, 耗时=125ms
读取实测回显:
device: root.demo.device1
device: root.demo.device2
== 设备测点(类型) ==
root.demo.device1 -> temperature : FLOAT
root.demo.device1 -> humidity : DOUBLE
root.demo.device1 -> status : TEXT
root.demo.device2 -> current : INT64
root.demo.device2 -> voltage : INT32
== 查询结果(root.demo.device1 temperature/humidity, 3 秒窗口) ==
1700000000000 | FLOAT:20.0 | DOUBLE:45.0
1700000001000 | FLOAT:21.0 | DOUBLE:46.0
1700000002000 | FLOAT:22.0 | DOUBLE:47.0
共命中 3 行(本次仅展示 3 行)
Ubuntu 22.04 与 CentOS 8 两端回显一致(CentOS 端耗时 141ms,文件同为 9984 字节)。文件魔数校验(Ubuntu 端 od -c 实测):首 10 字节 T s F i l e 004 \0 002 022,尾 10 字节 \0 \0 \0 302 T s F i l e。
三、表模型写入(v4 API)
tsfile 2.4.0 提供了新的表模型写入 API(org.apache.tsfile.write.v4 包),面向「表 + 标签列 + 物理量列」的结构化场景,实测可用:
package demo;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.apache.tsfile.enums.ColumnCategory;
import org.apache.tsfile.enums.TSDataType;
import org.apache.tsfile.file.metadata.ColumnSchema;
import org.apache.tsfile.file.metadata.ColumnSchemaBuilder;
import org.apache.tsfile.file.metadata.TableSchema;
import org.apache.tsfile.write.record.Tablet;
import org.apache.tsfile.write.v4.ITsFileWriter;
import org.apache.tsfile.write.v4.TsFileWriterBuilder;
public class TableWriteDemo {
public static void main(String[] args) throws Exception {
File f = new File("demo_table.tsfile");
if (f.exists()) {
f.delete();
}
List<ColumnSchema> columns = new ArrayList<>();
columns.add(new ColumnSchemaBuilder().name("region")
.dataType(TSDataType.TEXT).category(ColumnCategory.TAG).build());
columns.add(new ColumnSchemaBuilder().name("temperature")
.dataType(TSDataType.FLOAT).category(ColumnCategory.FIELD).build());
columns.add(new ColumnSchemaBuilder().name("humidity")
.dataType(TSDataType.DOUBLE).category(ColumnCategory.FIELD).build());
TableSchema tableSchema = new TableSchema("sensor", columns);
try (ITsFileWriter writer = new TsFileWriterBuilder()
.file(f)
.tableSchema(tableSchema)
.memoryThreshold(8 * 1024 * 1024)
.build()) {
List<String> names = new ArrayList<>();
names.add("region");
names.add("temperature");
names.add("humidity");
List<TSDataType> types = new ArrayList<>();
types.add(TSDataType.TEXT);
types.add(TSDataType.FLOAT);
types.add(TSDataType.DOUBLE);
Tablet tablet = new Tablet(names, types);
long base = 1700000000000L;
for (int r = 0; r < 1000; r++) {
tablet.addTimestamp(r, base + r * 1000L);
tablet.addValue("region", r, "north");
tablet.addValue("temperature", r, 20.0f + r % 5);
tablet.addValue("humidity", r, 60.0 + r % 3);
}
tablet.setRowSize(1000);
writer.write(tablet);
}
System.out.println("表模型写入完成: " + f.getAbsolutePath()
+ " 大小=" + f.length() + " 字节");
}
}
实测回显:
表模型写入完成: /root/tsfile-demo/demo_table.tsfile 大小=673 字节
注意:表模型 Tablet 用 List<String> 列名 + List<TSDataType> 构造,表归属由 builder 的 tableSchema 承担;树模型 Tablet(String 设备名 + List<IMeasurementSchema>)则用 writeTree 提交,两条路径不要混用。
四、编码与压缩对比实测
同一 20000 点 float 正弦序列(root.bench.d1,毫秒时间戳,间隔 1 秒),实测各 encoder × compressor 组合的文件体积(字节)。注意单条 Tablet 限 1024 行,长序列必须分批(实测超限抛 ArrayIndexOutOfBoundsException: Index 1024):
| encoder\compressor | UNCOMPRESSED | SNAPPY | GZIP | LZ4 | ZSTD |
|---|---|---|---|---|---|
| PLAIN | 84140 | 81504 | 70306 | 81826 | 69179 |
| RLE | 36728 | 34092 | 33508 | 34220 | 32960 |
| GORILLA | 74112 | 71476 | 64385 | 71759 | 63723 |
| TS_2DIFF | 26478 | 14386 | 10006 | 13996 | 8780 |
选型结论(实测数据支撑):
- 光滑缓变浮点序列:TS_2DIFF + ZSTD 体积最小(本例 8780 字节,约为 PLAIN + UNCOMPRESSED 的 1/10),GZIP 次之但 CPU 更贵。
- 快速波动浮点:GORILLA 系(含 CHIMP)更稳,压缩/解压开销低。
- 整型遥测:TS_2DIFF 几乎总是优于 RLE;开关量/枚举用 RLE 或 BITMAP。
- 文本:仅 PLAIN/DICTIONARY 可选,高重复文本用 DICTIONARY。
- 压缩器层面:ZSTD 压缩率最好,SNAPPY/LZ4 压缩速度最快,与主流实践一致。
五、Python SDK 实测示例
PyPI 提供独立 tsfile 包(当前 2.4.0,与 Java 同步发布),实测环境 Ubuntu 22.04 + Python 3.10.12 + pip 22.0.2:
pip3 install tsfile # 实测装到 /usr/local/lib/python3.10/dist-packages/tsfile
完整读写示例 /root/py_demo.py(三个实测要点:树模型写入前必须 set_table_name 指定目标设备否则抛 DeviceNotExistError;Python 端 Tablet 无需手动设行数,内部游标自增;树模型查询用 query_tree_by_row 而不是不存在的 query 方法):
# -*- coding: utf-8 -*-
import os
from tsfile import TsFileWriter, TsFileReader, DeviceSchema
from tsfile import TimeseriesSchema, Tablet, TSDataType
path = "/tmp/py_demo.tsfile"
if os.path.exists(path):
os.remove(path)
w = TsFileWriter(path)
ts_list = [
TimeseriesSchema("temp", TSDataType.FLOAT),
TimeseriesSchema("hum", TSDataType.DOUBLE),
]
w.register_device(DeviceSchema("root.py.device1", ts_list))
tablet = Tablet(["temp", "hum"], [TSDataType.FLOAT, TSDataType.DOUBLE])
tablet.set_table_name("root.py.device1")
for i in range(100):
tablet.add_timestamp(i, 1700000000000 + i * 1000)
tablet.add_value_by_name("temp", i, 20.0 + i % 5)
tablet.add_value_by_name("hum", i, 50.0 + i % 3)
w.write_tablet(tablet)
w.close()
print("写入完成, 大小:", os.path.getsize(path), "字节")
r = TsFileReader(path)
print("设备:", list(r.get_all_devices()))
rs = r.query_tree_by_row(["root.py.device1"], ["temp", "hum"], 0, 5)
print("结果集列:", rs.get_result_column_info())
while rs.next():
print("temp =", rs.get_value_by_name("temp"), ", hum =", rs.get_value_by_name("hum"))
rs.close()
r.close()
实测回显:
写入完成, 大小: 1646 字节
设备: [DeviceID(path='root.py.device1', table_name='root.py', segments=('root.py', 'device1'))]
结果集列: {'time': <TSDataType.INT64: 2>, 'root.py.device1.temp': <TSDataType.FLOAT: 3>, 'root.py.device1.hum': <TSDataType.DOUBLE: 4>}
temp = 20.0 , hum = 50.0
temp = 21.0 , hum = 51.0
temp = 22.0 , hum = 52.0
temp = 23.0 , hum = 50.0
temp = 24.0 , hum = 51.0
⚠️ 实测条件说明:以上 Python 结果仅在 Ubuntu 22.04(Python 3.10 / pip 22)实测通过。CentOS 8 仓库自带的 Python 3.6 + pip 9.0.3 实测无法安装(No matching distribution found for tsfile),CentOS 场景请以 Java SDK 为主,或自行升级 Python 3.8+ 后再装。
另实测 Python 端默认编码/压缩为 GORILLA + LZ4(get_all_timeseries_schemas 回显 TimeseriesSchema(temp, FLOAT, GORILLA, LZ4)),与 Java 端默认不同,跨语言混用建议显式指定。
六、扩展集成说明
6.1 与 Apache IoTDB 集成
TsFile 即 IoTDB 的底层文件格式:本工程生成的文件可直接被 IoTDB 的 load 工具加载,或经 IoTDB Java 原生 Session 写入后由 IoTDB 统一管理。对接 IoTDB 服务端联调时,实验环境使用其默认超级账号 root、密码 q1w2e3r4 即可完成验证。版本选择务必参考第一章对应关系表(IoTDB 1.3.x ↔ tsfile 1.x;IoTDB 2.0.x ↔ tsfile 2.0.x);用 2.4.0 生成的文件建议仅在独立链路使用,避免与旧版 IoTDB 混用。
6.2 Flume 连接器
IoTDB 官方发行包(iotdb-flume-sink 等)提供把 Flume Event 中的时序数据写入 IoTDB/TsFile 的通道能力,属于 IoTDB 侧组件而非 tsfile 库本身。集成思路:自定义 Source/Interceptor 把采集数据转为「设备名 + 测点 + 时间戳」结构,再由 Sink 落盘。由于 tsfile 2.4.0 与 IoTDB 1.x 的 Flume 插件分属不同版本线,生产集成前需先统一版本。
6.3 Hadoop 集成
IoTDB 发行包内含 iotdb-hadoop 模块,提供 TsFile 的 HDFS 读写 InputFormat/OutputFormat 适配,可在 MapReduce/Spark 作业中直接扫描 TsFile。自研场景的轻量替代:tsfile 库本身可读写 HDFS 路径(TSFileConfig 中含 dfs 相关开关,如 dfsHaAutomaticFailoverEnabled 默认 true),配合 Hadoop FileSystem API 封装即可。
6.4 Flink 集成
IoTDB 官方提供 iotdb-flink 连接器(Source 读取 TsFile/IoTDB、Sink 写入)。以独立 tsfile 库对接 Flink 的常见模式:RichSinkFunction 内持有 TsFileWriter,checkPoint 时 close 触发文件完整落盘;读方向在 SourceFunction 中用 TsFileSequenceReader 顺序扫描后发往下游。注意两点实测结论:写端 Tablet 按批提交(≤1024 行/批)配合 checkPoint 频率控制内存;setMemoryThreshold 可在缓冲接近上限时触发自动 flush。
以上集成组件均属 IoTDB 发行物,本文未逐一实测其联调链路,仅给出架构性说明与实测边界。
七、JVM 堆验证
统一按 256–512 MB 堆档位运行本工程:
- Maven exec:java 场景:
export MAVEN_OPTS="-Xms256m -Xmx512m"(写入 ~/.bashrc 持久化)。 - 打包直跑场景:
java -Xms256m -Xmx512m -cp 'target/tsfile-demo-1.0.0.jar:target/dependency/*' demo.WriteDemo。
实测验证(Ubuntu 22.04,程序驻留期间执行 ps -ef | grep [j]ava):
root 7582 1 33 12:11 ? 00:00:04 /usr/bin/java -Xms256m -Xmx512m -classpath /usr/share/maven/boot/plexus-classworlds-2.x.jar ... org.codehaus.plexus.classworlds.launcher.Launcher -q exec:java -Dexec.mainClass=demo.HeapHolder
jps -v 回显:
7582 Launcher -Xms256m -Xmx512m -Dclassworlds.conf=/usr/share/maven/bin/m2.conf ...
程序内打印 Runtime.getRuntime().maxMemory() 实测 maxMemory=512MB。CentOS 8 + Maven 3.9.16 端 ps 回显一致可见 -Xms256m -Xmx512m(另有 JDK 17 的 --enable-native-access=ALL-UNNAMED 参数)。
八、常见问题
Q1:写入抛 ArrayIndexOutOfBoundsException: Index 1024?
A:Tablet 默认容量 1024 行。要么按批写满即调 writeTree 后 tablet.reset() 复用,要么构造时指定更大容量(实测复现与修复均通过)。
Q2:写入抛 NoDeviceException: No device for root.bench.d1?
A:用无 Schema 的 new TsFileWriter(File) 构造时未注册设备。先构建 Schema 并 registerMeasurementGroup,再以 new TsFileWriter(file, schema, config) 创建(实测复现)。
Q3:编译报 cannot find symbol: method setRowNumber(int)?
A:2.4.0 的 Tablet 行数方法为 setRowSize(int),网上旧版资料中的 setRowNumber 不存在(实测 javap 确认)。
Q4:查询结果为空?
A:确认查询路径与写入的设备/测点完全一致(含大小写),且时间过滤的时间戳为毫秒(本工程基线 1700000000000);QueryExpression 中 addSelectedPath 的路径需与 schema 注册名逐段相同。若仍为空,用 ReadDemo 里的元数据遍历先核对文件内实际设备与测点名。
Q5:Python 写入抛 DeviceNotExistError?
A:树模型下必须先 tablet.set_table_name("root.py.device1") 指定目标设备,且设备需已 register_device(实测复现与修复均通过)。
Q6:exec:java 中文乱码?
A:MAVEN_OPTS 追加 -Dfile.encoding=UTF-8。
九、参考链接
- TsFile 官网:https://tsfile.apache.org/
- TsFile GitHub 仓库:https://github.com/apache/tsfile
- Maven Central:https://central.sonatype.com/artifact/org.apache.tsfile/tsfile
- PyPI tsfile 包:https://pypi.org/project/tsfile/
- IoTDB 官方文档(Java 原生 SDK):https://iotdb.apache.org/zh/UserGuide/latest/API/Programming-Java-Native-SDK.html
- IoTDB 官网(Flume/Hadoop/Flink 集成模块入口):https://iotdb.apache.org/