Ohhnews

分类导航

$ cd ..
DZone Java原文

使用Java与Apache IoTDB构建物联网时间序列应用

#apache iotdb#java#物联网#时间序列数据库#边缘计算

Apache IoTDB 非常适合这样的环境:来自联网设备和工业系统的时间序列数据持续生成,并且需要高效查询。典型用例包括监控温度、压力、振动、能耗、机器状态和设备遥测数据。这种方法也适用于制造业、智能基础设施、车队监控、公用事业和边缘计算。

IoTDB 的突出之处在于它专注于来自设备和工业系统的大规模时间序列工作负载。它是专为高频数据写入、历史分析和基于时间的查询而构建的。这使其非常适合需要洞察设备或流程当前状态和历史趋势的应用。

为什么 Apache IoTDB 很重要

Apache IoTDB 擅长长期管理大量由设备生成的数据。它解决的问题不止于存储,还包括持续的数据写入、按设备和时间戳高效组织数据,以及对近期值和历史值进行快速查询。这使 IoTDB 非常适合具有时序、面向设备数据模型的系统。常见用例包括工业物联网、智能工厂、能源监控、联网车辆、楼宇自动化、预测性维护和边缘计算。例如,制造商可以跟踪机械数据,公用事业公司可以分析众多电表的能耗,车队运营商可以监控位置和发动机遥测数据。在每种场景中,IoTDB 都能让应用确定当前状态、回顾设备随时间变化的行为,并检测超出预期范围的测量值。

动手实践:Apache IoTDB 与 Java

我们将使用 Apache IoTDB 构建一个简单的 Java 应用。为简单起见,IoTDB 将在本地 Docker 中运行。

$ bash
docker run -d \
  --name iotdb-instance \
  -p 6667:6667 \
  -e dn_rpc_address=0.0.0.0 \
  apache/iotdb:2.0.11-standalone

接下来,使用 IoTDB 的 Table SQL 方言创建数据库:

$ bash
docker exec -it iotdb-instance \
  /iotdb/sbin/start-cli.sh \
  -h 127.0.0.1 \
  -p 6667 \
  -u root \
  -pw root \
  -sql_dialect table \
  -e "CREATE DATABASE IF NOT EXISTS jnosql"

在这个本地示例中,我们使用默认的 root/root 凭据,并禁用客户端重定向。这些设置仅适用于单节点开发。在生产环境中,请使用安全凭据,并根据你的 IoTDB 集群拓扑配置重定向。

配置应用程序

接下来,在 microprofile-config.properties 中配置连接:

$ properties
jnosql.timeseries.database=jnosql
jnosql.iotdb.host=localhost
jnosql.iotdb.port=6667
jnosql.iotdb.username=root
jnosql.iotdb.password=root
jnosql.iotdb.enable.redirection=false

Eclipse JNoSQL 基于 CDI、JSON-B 和 Eclipse MicroProfile Config 等 Jakarta API 构建。这些 API 受到 Helidon、Quarkus、Open Liberty 及其他兼容 Jakarta EE 的环境等流行运行时支持。然后添加 Apache IoTDB 驱动:

org.eclipse.jnosql.databasesjnosql-iotdb ${jnosql.version}

对传感器数据建模

面向传感器的模型与 IoTDB 非常契合:

$ java
@Entity
public class SensorReading {
    @Id
    private Instant id;
    @Column
    private String sensor;
    @Column
    private double temperature;
    @Column
    private double humidity;

    // constructors, getters, and setters
}

Instant 字段记录读数的时间戳。其他字段捕获该时刻的测量值。该实体还可以通过 Jakarta Data 暴露:

$ java
@Repository
public interface SensorReadingRepository extends BasicRepository {
    List findBySensorOrderByIdDesc(
        String sensor,
        Limit limit);
}

使用 TimeSeriesTemplate

基础设施就绪后,插入几条读数,并检索最新值和近期历史记录:

$ java
"sensor-01", 22.1, 46.5
);

var latestReading = new SensorReading(
    Instant.parse("2026-09-20T10:15:00Z"),
    "sensor-01",
    23.6,
    48.2
);

try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
    TimeSeriesTemplate template = container.select(TimeSeriesTemplate.class).get();
    template.insert(firstReading);
    template.insert(secondReading);
    template.insert(latestReading);

    var currentReading = template
        .select(SensorReading.class)
        .where("sensor")
        .eq("sensor-01")
        .orderBy("id")
        .desc()
        .limit(1)
        .singleResult();

    System.out.println(
        "Current sensor reading: " + currentReading
    );

    var history = template
        .select(SensorReading.class)
        .where("sensor")
        .eq("sensor-01")
        .orderBy("id")
        .desc()
        .skip(1)
        .limit(10)
        .result();

    System.out.println("Recent sensor history:");
    history.forEach(System.out::println);
}
}
}

第一个查询回答了一个常见的 IoT 问题:该传感器的最新读数是什么?第二个查询检索其近期历史记录,但不包括最新观测值。

使用 Jakarta Data

同一个用例也可以使用该存储库实现:

$ java
public class App2 {
    public static void main(String[] args) {
        var firstReading = new SensorReading(
            Instant.parse("2026-09-20T08:00:00Z"),
            "sensor-01",
            21.4,
            45.0
        );

        var secondReading = new SensorReading(
            Instant.parse("2026-09-20T09:00:00Z"),
            "sensor-01",
            22.1,
            46.5
        );

        var latestReading = new SensorReading(
            Instant.parse("2026-09-20T10:15:00Z"),
            "sensor-01",
            23.6,
            48.2
        );

        try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
            SensorReadingRepository repository = container.select(SensorReadingRepository.class).get();
            repository.save(firstReading);
            repository.save(secondReading);
            repository.save(latestReading);

            var currentReading = repository
                .findBySensorOrderByIdDesc(
                    "sensor-01",
                    Limit.of(1)
                )
                .stream()
                .findFirst();

            System.out.println(
                "Current sensor reading: " + currentReading
            );

            var history = repository
                .findBySensorOrderByIdDesc(
                    "sensor-01",
                    Limit.range(2, 10)
                );

            System.out.println("Recent sensor history:");
            history.forEach(System.out::println);
        }
    }
}

两种方法都围绕最新状态和历史观测来对领域建模。这正是像 Apache IoTDB 这样的时间序列数据库比使用将时间戳作为普通字段的通用数据库更有效的地方。

为什么 Apache IoTDB 不仅仅是传感器存储

虽然 Apache IoTDB 常与 IoT 联系在一起,但它的能力远不止基本的传感器数据存储。当组织必须长期管理大量以设备为中心的数据,同时保留测量值、设备和时间戳之间的关系时,它表现尤为出色。因此,IoTDB 对工业系统、公用事业、交通运输、智能基础设施、制造业和边缘计算都很有价值。例如,在预测性维护中,机器可能会持续报告振动、温度、压力、能耗和运行状态。真正的价值不仅存在于最新读数中,还在于研究这些测量值随时间如何共同变化。维护系统可以将近期数据与历史趋势进行比较,在故障发生前发现异常,或将多个设备之间的变化关联起来。这需要的不仅仅是简单的传感器数据存储。这种方法也有益于能源系统,其中智能电表、太阳能板、电池和电网设备会产生持续测量数据流,需要进行基于时间的分析。在交通运输中,车辆会产生速度、位置、油耗、电池状态和发动机遥测等持续数据。同样,智能建筑依赖来自 HVAC 系统、占用传感器和电能表的时间序列数据。当系统架构围绕设备及其测量值组织时,IoTDB 尤其有效。它可以作为运营系统的历史数据层,而其他技术负责管理事务型或业务信息。例如,关系数据库可以存储关于机器、其所有者、合同或维护计划的详细信息,而 IoTDB 管理机器生成的大量测量数据。这种分离让企业应用将遥测数据视为主要工作负载,而不是将高频设备数据强行塞入为业务实体和事务设计的模型中。

结论

Apache IoTDB 非常适合需要长期写入和分析设备生成数据的应用,尤其是在 IoT、工业、能源和边缘场景中。借助 Eclipse JNoSQL 1.1.18,Java 开发者可以通过熟悉的 Jakarta API 使用这些能力,在保持应用模型一致的同时,仍然利用 IoTDB 的时间序列专长。

DZone 贡献者表达的观点仅代表他们本人。