package com.xlkh.kafka;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.iotdb.rpc.IoTDBConnectionException;
import org.apache.iotdb.rpc.StatementExecutionException;
import org.apache.iotdb.session.pool.SessionPool;
import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
import org.apache.iotdb.tsfile.write.record.Tablet;
import org.apache.iotdb.tsfile.write.schema.MeasurementSchema;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component; import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors; @Slf4j
@Component("com.xlkh.kafka.DataLoaderKafkaConsumer")
public class DataLoaderKafkaConsumer { @Autowired
private SessionPool sessionPool; /**
* 保存已经创建的时间序列
*/
private final static Set<String> STATIC_PATHS = Sets.newConcurrentHashSet(); /**
* fluent_data,批量消费
*/
@KafkaListener(topics = "fluent_data", groupId = "fluent_data_demo", containerFactory = "batchFactory")
@SneakyThrows
public void listenBatchByFluent(List<ConsumerRecord<String, String>> records) {
log.error("从kafka消费fluent数据" + records.size() + "条,当前偏移量:" + records.get(0).offset()); //创建时间序列,如果序列已经存在,不再重新创建
createTimeseriesIfNotExist(records); log.info("开始把数据放到iotdb-----------------------"); insertIotdbByKafka(records); } private void insertIotdbByKafka(List<ConsumerRecord<String, String>> records) throws ParseException, IoTDBConnectionException, StatementExecutionException { //key为kks的路径,value是时间戳集合
Map<String, List<Long>> timeStampMap = new HashMap<>(); //key为kks路径,value是具体的数据
Map<String, List<Float>> values = new HashMap<>(); //保存kks编码
Set<String> kksSet = new HashSet<>(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
for (ConsumerRecord<String, String> record : records) {
String valueData = record.value();
JSONArray jsonArray = JSON.parseArray(valueData);
for (int i = 0; i < jsonArray.size(); i++) {
Map map = JSON.parseObject(String.valueOf(jsonArray.get(i)), Map.class);
JSONArray jsonArray1 = JSON.parseArray(String.valueOf(map.get("msg")));
for (int j = 0; j < jsonArray1.size(); j++) {
Map map1 = JSON.parseObject(String.valueOf(jsonArray1.get(j)), Map.class);
if (map1.containsKey("big_v")){
String kks = map1.get("kks").toString();
Date date = dateFormat.parse(map1.get("time").toString());
Float val = Float.parseFloat(String.valueOf(map1.get("big_v")));
if(!kksSet.contains(kks)){
timeStampMap.put(kks, new ArrayList<>());
values.put(kks, new ArrayList<>());
kksSet.add(kks);
}
timeStampMap.get(kks).add(date.getTime());
values.get(kks).add(val);
}
}
}
} //遍历批量插入每个设备的数据
for (String kks : kksSet) {
List<Long> longs = timeStampMap.get(kks); //声明Tablet对象设备属性
List<MeasurementSchema> schemas = new ArrayList<>();
schemas.add(new MeasurementSchema(kks,TSDataType.FLOAT));
Tablet tablet = new Tablet("root.param.demo", schemas, longs.size());
for (int row = 0; row < longs.size(); row++) {
int rowIndex = tablet.rowSize++;
//设备时间戳值
tablet.addTimestamp(rowIndex, longs.get(row));
//设置对应的值
tablet.addValue(schemas.get(0).getMeasurementId(), rowIndex, values.get(kks).get(row));
}
//批量插入数据
sessionPool.insertTablet(tablet);
}
log.info("数据成功插入到iotdb-----------------------"+"插入的数据量大小为:"+records.size()); } /**
* 创建时间序列,如果序列已经存在,不再重新创建
*
* @param records 批量数据
*/
private void createTimeseriesIfNotExist(List<ConsumerRecord<String, String>> records) {
try {
List<String> data = records.stream().map(ConsumerRecord::value).collect(Collectors.toList());
HashSet<String> paths = Sets.newHashSetWithExpectedSize(250);
for (String msg : data) { JSONArray jsonArray = JSON.parseArray(msg); for (int i = 0; i <jsonArray.size() ; i++) {
Map map = JSON.parseObject(String.valueOf(jsonArray.get(i)), Map.class);
JSONArray jsonArray1 = JSON.parseArray(String.valueOf(map.get("msg")));
for (int j = 0; j < jsonArray1.size(); j++){
Map map1 = JSON.parseObject(String.valueOf(jsonArray1.get(j)), Map.class);
String kks = map1.get("kks").toString();
String path = "root.param.demo." + kks;
paths.add(path);
}
}
} List<String> notExistPaths = Lists.newArrayList();
List<TSDataType> tsDataTypes = Lists.newArrayList();
List<TSEncoding> tsEncodings = Lists.newArrayList();
List<CompressionType> compressionTypes = Lists.newArrayList();
// List<Map<String, String>> propsList = Lists.newArrayList();
for (String path : paths) {
if (!STATIC_PATHS.contains(path)) {
if (sessionPool.checkTimeseriesExists(path)) {
STATIC_PATHS.add(path);
} else {
notExistPaths.add(path);
tsDataTypes.add(TSDataType.FLOAT);
tsEncodings.add(TSEncoding.RLE);
compressionTypes.add(CompressionType.SNAPPY);
}
}
}
if (CollectionUtil.isNotEmpty(notExistPaths)) {
//批量创建时间序列
sessionPool.createMultiTimeseries(notExistPaths, tsDataTypes, tsEncodings, compressionTypes, null, null, null, null);
//缓存时间序列
STATIC_PATHS.addAll(notExistPaths);
}
} catch (IoTDBConnectionException | StatementExecutionException e) {
log.error(e.getMessage(), e);
}
} }

 切记:对于iotdb来说,节点的第一层一直到倒数第二层,都属于设备id,只有最后一层才是你的属性

java把数据批量插入iotdb的更多相关文章

  1. Java使用iBatis批量插入数据到Oracle数据库

    Java使用iBatis批量插入数据到Oracle数据库 因为我们的数据跨库(mysql,oracle),单独取数据的话需要遍历好多遍,所以就想着先从mysql数据库中取出来的数据然后在oracle数 ...

  2. 多线程查询数据,将结果存入到redis中,最后批量从redis中取数据批量插入数据库中【我】

    多线程查询数据,将结果存入到redis中,最后批量从redis中取数据批量插入数据库中 package com.xxx.xx.reve.service; import java.util.ArrayL ...

  3. 使用事务操作SQLite数据批量插入,提高数据批量写入速度,源码讲解

    SQLite数据库作为一般单机版软件的数据库,是非常优秀的,我目前单机版的软件产品线基本上全部替换Access作为优选的数据库了,在开发过程中,有时候需要批量写入数据的情况,发现传统的插入数据模式非常 ...

  4. C#中几种数据库的大数据批量插入

    C#语言中对SqlServer.Oracle.SQLite和MySql中的数据批量插入是支持的,不过Oracle需要使用Orace.DataAccess驱动. IProvider里有一个用于实现批量插 ...

  5. SQL SERVER 使用BULK Insert将txt文件中的数据批量插入表中(1)

    1/首先建立数据表 CREATE TABLE BasicMsg( RecvTime FLOAT NOT NULL , --接收时间,不存在时间相同的数据 AA INT NOT NULL, --24位地 ...

  6. C#:几种数据库的大数据批量插入

    在之前只知道SqlServer支持数据批量插入,殊不知道Oracle.SQLite和MySql也是支持的,不过Oracle需要使用Orace.DataAccess驱动,今天就贴出几种数据库的批量插入解 ...

  7. c#数据批量插入

    由于之前面试中经常被问到有关EF的数据批量插入问题,今天以Sqlserver数据库为例,对.net中处理数据批量处理的方案进行了测试对比. 1.四种测试方案 (1)普通的EF数据批量插入:即调用DbS ...

  8. C#:几种数据库的大数据批量插入(转)

    在之前只知道SqlServer支持数据批量插入,殊不知道Oracle.SQLite和MySql也是支持的,不过Oracle需要使用Orace.DataAccess驱动,今天就贴出几种数据库的批量插入解 ...

  9. C#:几种数据库的大数据批量插入 - faib

    在之前只知道SqlServer支持数据批量插入,殊不知道Oracle.SQLite和MySql也是支持的,不过Oracle需要使用Orace.DataAccess驱动,今天就贴出几种数据库的批量插入解 ...

  10. PHP如何将多维数组中的数据批量插入数据库?

    PHP将多维数组中的数据批量插入到数据库中,顾名思义,需要用循环来插入. 1.循环insert into 语句,逐渐查询 <?php /* www.qSyz.net */ @mysql_conn ...

随机推荐

  1. Java中的线程池使用及原理

    开篇-为什么要使用线程池? ​ Java 中的线程池是运用场景最多的并发框架,几乎所有需要异步或并发执行任务的程序都可以使用线程池.在开发过程中,合理地使用线程池能够带来 3 个好处. ​ 第一:降低 ...

  2. WPF自定义标题栏

    往往原有的标题栏无法满足需求,此时就需要进行自定义标题栏. 重新定义Window的Template 首先,需修改WindowChrome的几个属性 CaptionHeight属性值就是自定义标题栏的高 ...

  3. asset module type 替代 loader 处理图片字体等文件资源

    前面文章中 体验了webpack的打包 .解析css资源 ,接下来看看项目中常用到的图片.字体.文件该怎么处理吧~ 项目路径如下,在上一篇 解析css资源 项目基础上增加了一些文件 demo ├─ s ...

  4. [kubernetes]二进制部署k8s集群

    0. 前言 采用二进制部署三主三工作节点的k8s集群,工作节点和Master节点共用服务器,因此只用到了三台服务器.master采用haproxy + keepalive实现高可用.实际生产环境中,建 ...

  5. [mysql]MGR简介与部署

    前言 MySQL Group Replication,简称MGR,是MySQL官方于2016年推出的一个全新的高可用解决方案,采用Paxos分布式一致性协议作为高可用和一致性解决方案.在MGR之前的高 ...

  6. 从零玩转系列之微信支付实战PC端项目构建+页面基础搭建 | 技术创作特训营第一期

    一.前言 欢迎来到本期的博客!在这篇文章中,我们将带您深入了解前端开发领域中的一个热门话题: 如何使用 Vue 3 和 Vite 构建前端项目.随着现代 Web 应用程序的需求不断演进, 选择适当的工 ...

  7. Pytest+Jenkins 学习笔记

    Pytest+Jenkins 学习笔记 在软件测试工作中,单元测试通常是由开发人员执行的.针对最小单元粒度的组件测试,在完成了单元粒度的测试任务之后,通常就需要交由专职的测试人员将这些单元级的组件放到 ...

  8. 使用 Rancher 安装 K8s 集群

    舞台环境 Ubuntu 22.04.2 LTS Docker 24.0.2 2GB RAM或者更多 CPU 2核心或者更多 Rancher 2.6.9 测试环境中,我准备了两台 Ubuntu 服务器, ...

  9. Python字符串操作函数split()和join()

    字符串拆分 在python中有切片(Slice)操作符,可以对字符串进行截取,还提供了split()函数可以将一个 字符串分裂成多个字符串组成的列表.在使用split()函数来拆分字符串之前,我们先来 ...

  10. 文心一言 VS 讯飞星火 VS chatgpt (85)-- 算法导论8.2 2题

    二.用go语言,试证明 COUNTING-SORT 是稳定的. 文心一言: 要证明 COUNTING-SORT 是稳定的,我们需要证明在排序过程中,具有相同值的元素在排序后仍保持其原始的相对顺序.CO ...