[文件格式/数据存储] Apache Parquet:开源、高效的列式存储文件格式协议

[文件格式/数据存储] Apache Parquet:开源、高效的列式存储文件格式协议

序:缘起 => 用 java 读取 parquet 文件

生产环境有设备出重大事故,又因一关键功能无法使用,亟需将生产环境的原始MQTT报文(以 parquet 文件格式 + zstd 压缩格式 落盘)DOWN到本地,读取并解析。

本文案例中,聚焦在 本地电脑,用 java 读取 parquet 文件。

相当多网络文档的读取代码无法正常运行,有必要记录一二,后续还需进一步研究 parquet 和 zstd 算法。

概述:Parquet

摘要:

Apache Parquet是一种高效、灵活且可扩展的列式存储格式,专为大规模数据处理而设计。

 它通过列式存储、数据压缩和编码优化,显著提高了数据的读取和写入性能。

 Parquet与多种数据处理框架和数据模型兼容,使其成为大数据生态系统中不可或缺的一部分。

什么是 Parquet? Apache Hadoop社区发起的、开源的、大数据量场景的、高效的列式存储、压缩与传输的文件格式协议

Parquet 是一个开源的、用于存储和传输大数据的、高效的、基于列式存储的文件格式,它使用一种称为 Columnar 的数据压缩算法来优化数据压缩和传输。

缘起。Parquet 的灵感来源于2010年 Google 发表的 Dremel 论文,该论文介绍了一种支持嵌套结构的列式存储格式。

创始与开发团队。最初由Twitter和Cloudera联合开发,并于2013年捐赠给Apache软件基金会,于2015年5月从 Apache 孵化器毕业,成为 Apache 顶级项目。

由 Apache 开源项目 Hadoop 创建,并作为 Hadoop 的一部分进行维护。

应用领域。Parquet专为大规模数据处理而设计,支持多种数据处理框架,如: Apache Spark、Hadoop MapReduce、Presto、Apache Flink等。

优势。Parquet文件格式的优势在于高效的压缩和高效的列式存储,使得它在大数据处理中具有很高的性能。

核心特点

列式存储:Parquet以列式格式存储数据。

这意味着每一列的数据被连续存储。这种存储方式使得对特定列的读取操作更加高效,因为只需要读取相关的列数据,而无需扫描整个行。这在处理大规模数据集时尤其有用,尤其是在执行聚合查询和分析时。

数据压缩:Parquet支持多种压缩算法,如:zstd、Snappy、Gzip、LZO等。

压缩可以显著减少存储空间的占用,并提高数据的读写速度。通过压缩,数据在磁盘上的存储效率更高,同时在读取时可以更快地加载到内存中。

数据编码:Parquet提供了多种数据编码方式,如字典编码、RLE(Run-Length Encoding)等。这些编码方式可以进一步优化数据的存储和读取性能,尤其是在处理重复数据时。

可扩展性:Parquet文件可以被分割成多个块(Row Groups),每个块可以独立读取和处理。

这种设计使得Parquet文件非常适合分布式处理框架,如Apache Spark和Hadoop MapReduce,因为它们可以并行处理文件的不同部分。

与多种数据模型兼容:Parquet支持多种数据模型,包括Avro、Thrift和Protobuf。

这意味着您可以使用不同的数据模型来定义和存储数据,而Parquet能够无缝地处理这些数据。

应用场景

Parquet广泛应用于以下领域:

大数据分析:由于其高效的存储和读取性能,Parquet非常适合用于大规模数据分析,如数据仓库、数据湖等。

机器学习:在机器学习中,Parquet可以用于存储和处理训练数据,支持快速的数据加载和特征提取。

实时数据处理:Parquet的列式存储和压缩特性使其在实时数据处理中表现出色,能够快速读取和处理数据。

官方文献

Parquet - Apache

https://parquet.apache.org/docs/file-format/

https://arrow.apache.org/docs/python/parquet.html

原理分析:Parquet文件格式( File Format)

文件格式:

Block(HDFS块):指的是HDFS中的一个块,对于描述这种文件格式,其含义不变。该文件格式设计得能够在HDFS上良好运作。

文件(File):一个必须包含文件元数据的HDFS文件。实际上,它不需要包含数据本身。

行组(Row group):数据在行方向的逻辑分区。对于行组,没有保证其存在物理结构。一个行组由数据集中每个列的列块组成。

列块(Column chunk):一个特定列的数据块。它们存在于特定的行组中,并且在文件中保证是连续的。

页面(Page):列块被划分成页面。页面在概念上是一个不可分割的最小单元(就压缩和编码而言)。在一个列块中可以有多个页面类型,它们交织在一起。

从层次上看,一个文件包含一个或多个行组。一个行组包含每列恰好一个列块。列块包含一个或多个页面。

Parquet文件 - 行组 - 列块 - 页面

实现框架与客户端

ParquetViewer : 开源的 Parquet 文件查看器

ParquetViewer 项目

https://github.com/mukunku/ParquetViewer/releases

https://github.com/mukunku/ParquetViewer/releases/download/v3.0.0.1/ParquetViewer_SelfContained.exe

VSCode + Parquet-Viewer插件

url

https://marketplace.visualstudio.com/items?itemName=dvirtz.parquet-viewer

Parquet-Viewer : Parquet文件在线浏览网站

url

https://www.parquet-viewer.com/

org.apache.parquet:*: Java SDK

详情参见本文档:【案例实践】章节,"org.apache.parquet"

Pandas : 集成了 Parquet 的 Python Data Analysis Library

python pandas 支持Parquet 格式,与csv 一下简单对比,首先我们测试存储情况

import pandas as pd

df = pd.read_csv('results.csv')

# df.to_parquet('df_test.parquet.zstd', compression='zstd')  

df.to_parquet('df_test.parquet.gzip', compression='gzip')  

df.to_parquet('df_test.parquet.snappy', compression='snappy')  

df.to_parquet('df_test.parquet', compression=None)  

import os

file_size = os.path.getsize('results.csv')

print("results.csv size:", f'{file_size:,}', "bytes")

file_size = os.path.getsize('df_test.parquet.gzip')

print("df_test.parquet.gzip size:", f'{file_size:,}', "bytes")

file_size = os.path.getsize('df_test.parquet.snappy')

print("df_test.parquet.snappy size:", f'{file_size:,}', "bytes")

file_size = os.path.getsize('df_test.parquet')

print("df_test.parquet size:", f'{file_size:,}', "bytes")

parquet格式的存储,相比 csv 减少80%,结合压缩后是 csv 的 10%,可以节约90% 的存储空间。

为数据加载测试,我们将数据放大100倍。

%time df = pd.read_csv('df_test.csv')

%time df = pd.read_parquet('df_test.parquet.gzip')

%time df = pd.read_parquet('df_test.parquet.snappy')

%time df = pd.read_parquet('df_test.parquet')

使用pandas 加载 dataframe 也有大幅度提升,提升了2-3倍。

案例实践

CASE : 基于 Java SDK 读取Parquet文件

引入依赖

<properties>

 <!-- 1.13.1 / 1.12.0 -->

 <parquet.version>1.13.1</parquet.version>

 <avro.version>1.10.2</avro.version>

 <!-- 3.2.1 / 2.7.3 -->

 <hadoop.version>3.2.1</hadoop.version>

 <!-- 1.5.0-1 / 1.5.5-5 / 与 kafka-clients:1.4-xxx 版本冲突 -->

 <zstd.version>1.5.0-1</zstd.version>

</properties>

<dependency>

 <groupId>org.apache.parquet</groupId>

 <artifactId>parquet-avro</artifactId>

 <version>${parquet.version}</version>

</dependency>

<dependency>

 <groupId>org.apache.parquet</groupId>

 <artifactId>parquet-hadoop</artifactId>

 <version>${parquet.version}</version>

</dependency>

<dependency>

 <groupId>org.apache.hadoop</groupId>

 <artifactId>hadoop-mapreduce-client-core</artifactId>

 <version>${hadoop.version}</version>

 <exclusions>

  <exclusion>

   <artifactId>commons-compress</artifactId>

   <groupId>org.apache.commons</groupId>

  </exclusion>

 </exclusions>

</dependency>

<dependency>

 <groupId>org.apache.hadoop</groupId>

 <artifactId>hadoop-common</artifactId>

 <version>${hadoop.version}</version>

 <exclusions>

  <exclusion>

   <artifactId>commons-compress</artifactId>

   <groupId>org.apache.commons</groupId>

  </exclusion>

 </exclusions>

</dependency>

<dependency>

 <groupId>org.apache.hadoop</groupId>

 <artifactId>hadoop-hdfs</artifactId>

 <version>${hadoop.version}</version>

</dependency>

<!-- ztsd

 Zstd 的 RecyclingBufferPool‌ 是一种内存管理机制,用于高效地重用缓冲区,减少内存分配和释放的开销。

 Zstd库中的BufferPool接口提供了多种实现,其中RecyclingBufferPool是一种常见的实现方式。 -->

<dependency>

 <groupId>com.github.luben</groupId>

 <artifactId>zstd-jni</artifactId>

 <!-- 1.5.5-5 / kafka-clients 包冲突 -->

 <version>${zstd.version}</version>

</dependency>

ReadParquetFormatMQTTMessageRawDataDemo

import com.xx.yy.common.utils.DatetimeUtil;

import com.xx.yy.common.utils.FileUtil;

import com.alibaba.fastjson2.JSON;

import lombok.SneakyThrows;

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.io.FileUtils;

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.fs.Path;

import org.apache.parquet.hadoop.ParquetFileReader;

import org.apache.parquet.hadoop.ParquetReader;

import org.apache.parquet.example.data.Group;

import org.apache.parquet.hadoop.example.GroupReadSupport;

import org.apache.parquet.hadoop.metadata.ColumnChunkMetaData;

import org.apache.parquet.hadoop.metadata.ParquetMetadata;

import java.io.IOException;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

/**

 * 本地读取 Parquet 文件

 * @reference-doc

 * [1] java读取parquet文件 - https://blog.csdn.net/letterss/article/details/131417952

 * [2] datax读取Parquet格式文件总列数 - https://blog.csdn.net/letterss/article/details/131189471

 */

@Slf4j

public class ReadParquetFormatMQTTMessageRawDataDemo {

    @SneakyThrows

    public static void main(String[] args) {

        String baseDir = "file:///E:/tmp_data/parquet_mqtt_messages/ods_raw_data_history/";

        String parquetFilePathStr = baseDir + "20081-XXXX-XXXXXXXXXX/e7db5c81e70131d55d4fb4a1752b90f2-1.parquet"; //"output.parquet"

        try {

            // 指定 Parquet 文件路径

            //Path parquetFilePath = new Path("C:\\\\Users\\\\Administrator\\\\Desktop\\\\07fe7433-99c2-41d8-a91d-27a77d99f690-0_4-8-0_20230510103931772.parquet");

            Path parquetFilePath = new Path(parquetFilePathStr);

            //查询总列数,参考博客: https://blog.csdn.net/letterss/article/details/131189471

            int allColumnsCount = getParquetAllColumnsCount(parquetFilePath);

            int columnIndexMax = -1;

            columnIndexMax = allColumnsCount - 1;

            // 创建 ParquetReader.Builder 实例

            ParquetReader.Builder<Group> builder = ParquetReader.builder(new GroupReadSupport(), parquetFilePath);

            // 创建 ParquetReader 实例

            ParquetReader<Group> reader = builder.build();

            // 循环读取 Parquet 文件中的记录

            Group record;

            List<Map<String, Object>> records = new ArrayList<>();

            while ((record = reader.read()) != null) {

                Map<String, Object> recordMap = new HashMap<>();

                // 处理每个记录的逻辑

                for (int i = 0; i <= columnIndexMax; i++) {

                    String fieldKey = record.getType().getType(i).getName(); //record.getType().getFieldName(i);

                    Object fieldValue = record.getValueToString(i, 0);

                    recordMap.put( fieldKey , fieldValue);

                    System.out.println(fieldValue);

                }

                records.add( recordMap );

                //writeMqttMessageRawDataToLocal(recordMap);

            }

            System.out.println(JSON.toJSONString( records ));

            // 关闭读取器

            reader.close();

        } catch (IOException e) {

            e.printStackTrace();

        }

    }

    @SneakyThrows

    public static void writeMqttMessageRawDataToLocal(Map<String, Object> recordMap){

        String targetBaseDir = "E:\\tmp_data\\batch_parse_raw_mqtt_messages\\";

        String hexMqttMessageRawData = (String) recordMap.get("raw_data");

        String deviceId = (String) recordMap.get("device_id");

        Long collectTime = Long.valueOf( (String) recordMap.get("collect_time") );

        String mqttMessageRawDataFile = String.format("%s.%d(%s).hex-bin", deviceId, collectTime, DatetimeUtil.longToString(collectTime, DatetimeUtil.MILLISECOND_TIME_WITH_NUMBER_FORMAT) );

        FileUtil.writeToFile(hexMqttMessageRawData, targetBaseDir + mqttMessageRawDataFile);

        //FileUtils.write();

    }

    /**

  * 获取 parquet 的 总列数

  * @reference-doc

  * [1] datax读取Parquet格式文件总列数 - https://blog.csdn.net/letterss/article/details/131189471

  */

    public static int getParquetAllColumnsCount(Path path){

        int columnCount = -1;

        Configuration configuration = new Configuration();

        //Path path = new Path(parquetFilePath);

        try {

            ParquetMetadata metadata = ParquetFileReader.readFooter(configuration, path);

            List<ColumnChunkMetaData> columns = metadata.getBlocks().get(0).getColumns();

            columnCount = columns.size();

            System.out.println("Total column count: " + columnCount);

        } catch (Exception e) {

            e.printStackTrace();

        }

        return columnCount;

    }

}

CASE : Python Pands On Parquet

参见本文档: Pandas 的 描述

CASE : DuckDB 数据库 On Parquet

DuckDB 与 Parquet 的集成是无缝的,使得轻松使用SQL进行Parquet 文件上数据进行分析、查询和统计。

DuckDB 最大的优势在于能够对庞大的数据集运行查询,无论是具有大量小文件还是一个巨大的文件。使用熟悉的 SQL 语法在个人电脑/笔记本上执行探索性数据分析(EDA)任务,为分析大量数据带来了新的视角。

select 

    home_team ,count(*),avg(home_score) 

from read_parquet('/home/df_test.parquet.snappy') 

group by home_team

Y FAQ

Q: Apache Parquet、Apache Avro 和 ZSTD 之间的关系和区别是什么?

Apache Parquet、Apache Avro 和 ZSTD 在大数据处理中各自扮演着不同的角色,它们之间的关系和区别如下:

Parquet 与 Avro

存储格式:

Parquet:列式存储格式,数据按列存储,适合读取密集型操作和分析查询。它在处理大规模数据集时效率更高,尤其是在需要对特定列进行聚合或过滤时。

Avro:行式存储格式,数据按行存储,适合写入密集型操作和需要快速序列化/反序列化的场景。它在处理事务性系统或消息序列化时表现更好。

模式管理:

Parquet:模式存储在文件尾部,使用Thrift格式,模式演变相对不那么灵活。

Avro:模式以JSON格式存储,支持强大的模式演变,包括向后、向前和完全兼容。

压缩与性能:

Parquet:支持列级压缩(如Snappy、Gzip、ZSTD等),在分析查询中效率更高。

Avro:支持块级压缩(如Snappy、Deflate等),在处理整行数据时效率更高。

使用场景:

Parquet:适合数据仓库、大数据分析和批处理。

Avro:适合流处理系统(如Apache Kafka)、消息序列化和需要频繁写入的场景。

Parquet 与 ZSTD

ZSTD 是一种高效的压缩算法,以高压缩率和快速解压缩速度著称。

Parquet 是一种文件格式协议,支持多种压缩算法,包括 ZSTD。使用 ZSTD 压缩可以显著减少 Parquet 文件的存储空间,同时保持较高的读取速度。

在实际应用中,ZSTD 压缩在 Parquet 文件中表现出色,尤其是在需要高效存储和快速读取的场景中。

总结

Parquet 是一种列式存储格式,适合分析和读取密集型操作,支持多种压缩算法(包括ZSTD)。

Avro 是一种行式存储格式,适合写入密集型操作和消息序列化,支持灵活的模式演变。

ZSTD 是一种高效的压缩算法,可以与 Parquet 结合使用,以提高存储效率和读取速度。

选择哪种格式取决于您的具体需求:如果需要高效读取和分析数据,Parquet 是更好的选择;如果需要快速写入和序列化数据,Avro 更适合。而 ZSTD 压缩算法可以在 Parquet 文件中提供高效的存储和读取性能。

Q: Parquet 与 Avro 如何结合使用?

Parquet和Avro可以结合使用,以充分利用两者的优势。以下是它们结合使用的方式和场景:

数据存储与读取

 Avro用于数据写入:Avro是一种基于行的存储格式,适合写入密集型操作,尤其是在需要快速序列化和反序列化数据的场景中(如Kafka)。它支持灵活的模式演变,能够轻松处理数据结构的变化。

 Parquet用于数据读取:Parquet是一种基于列的存储格式,适合读取密集型操作,尤其是在需要对数据进行分析和查询的场景中。它支持高效的列式存储和压缩,能够显著减少I/O操作。

数据转换

 从Avro到Parquet:在数据湖或数据仓库中,可以将Avro格式的数据转换为Parquet格式。这样可以在保留Avro的写入性能的同时,利用Parquet的高效读取性能。例如,可以使用Apache Spark或Hadoop MapReduce来完成这种转换。

 从Parquet到Avro:在某些需要快速写入的场景中,可以将Parquet格式的数据转换为Avro格式,以便更好地支持流处理。

混合使用

 结合使用场景:在实际应用中,可以将Avro和Parquet结合使用。例如,可以将较新的数据存储为Avro文件,以便快速写入;而将历史数据转换为Parquet文件,以便高效读取。这种混合使用方式可以在不同的数据处理阶段发挥各自的优势。

工具支持

 Apache Spark:Apache Spark支持对Avro和Parquet文件的读写操作。可以使用Spark的API将Avro文件转换为Parquet文件,或者在需要时将Parquet文件转换为Avro文件。

 Hadoop MapReduce:Hadoop MapReduce也支持对这两种格式的处理,可以编写MapReduce作业来完成数据格式的转换。

总结

Parquet和Avro的结合使用可以充分发挥两者的优势。

Avro适合快速写入和数据序列化,而Parquet适合高效读取和数据分析。通过在不同的数据处理阶段选择合适的格式,可以优化数据存储和处理的性能。

X 参考文献

一文带您理解Apache Parquet:高效存储和处理大数据的利器 - zhihu

java读取parquet文件 - CSDN 【参考/推荐】

datax读取Parquet格式文件总列数 - CSDN 【参考/推荐】

Java读取本地Parquet文件 - CSDN

Parquet 文件生成和读取 - CSDN

org.apache.parquet.io.InputFile的S3实现? - 腾讯云

Configuration conf = new Configuration();

conf.set(Constants.ENDPOINT, "https://s3.eu-central-1.amazonaws.com/");

conf.set(Constants.AWS_CREDENTIALS_PROVIDER,

    DefaultAWSCredentialsProviderChain.class.getName());

// maybe additional configuration properties depending on the credential provider

URI uri = URI.create("s3a://bucketname/path");

org.apache.hadoop.fs.Path path = new Path(uri);

ParquetFileReader pfr = ParquetFileReader.open(HadoopInputFile.fromPath(path, conf))

Parquet文件读写与合并小Parquet文件 - CSDN

java 解析 parquet文件怎么打开 - 51CTO

Parquet 文件生成和读取 - CSDN

方式一:依赖于大数据环境(是不是必须依不依赖大数据环境还有待商榷)

  AvroParquetWriter 写入:

方式二:不依赖于大数据环境

  AvroParquetWriter 写入:

  AvroParquetReader 读取,需要指定对象 class:

  ParquetFileReader 读取,只需虚拟 haddop:

    方式一:

    方式二:行式读取、列式读取:

  ParquetReader 读取:

  ExampleParquetWriter 写入:Spring boot 方式

  GroupWriteSupport 写入:

Parquet文件读写与合并小Parquet文件 - CSDN 【推荐】

一、Parquet简介

二、schema(MessageType)

三、MessageType获取

3.1 从字符串构造

3.2 从代码创建

3.3 通过Parquet文件获取

3.4 完整示例

四、Parquet读写

4.1 读写本地文件

4.2 读写HDFS文件

五、合并 Parquet 小文件

六、pom文件

java 解析 parquet文件怎么打开 - 51CTO

VS Code 14 个神级扩展,提高生产力! - 51CTO 【推荐】

Jupyter : 用于交互式笔记本和数据探索

https://marketplace.visualstudio.com/items?itemName=ms-toolsai.jupyter

Docker : 用于容器化和环境管理

此扩展通过让你直接在 VS Code 内与 Docker 容器交互来简化容器管理

https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker

Parquet Viewer : 用于无缝查看 Parquet 文件

Parquet 是大数据工作流中最广泛使用的列式数据格式之一,尤其是在Apache Spark或Hadoop等系统中。Parquet Viewer扩展可让你直接在 VS Code 中轻松查看和检查 Parquet 文件。

https://marketplace.visualstudio.com/items?itemName=dvirtz.parquet-viewer

Rainbow CSV : 为了获得更干净、更易读的 CSV/TSV 文件

数据清理是数据工程师生活中的一大部分,处理CSV或TSV文件往往是不可避免的。

 Rainbow CSV可以解决这个问题,它为 CSV/TSV 文件添加了颜色突出显示,使文件更易于阅读和解释。

 它以视觉上可区分的方式格式化列,并帮助你一眼就发现诸如值放错位置或分隔符不正确等问题。

https://marketplace.visualstudio.com/items?itemName=mechatroner.rainbow-csv

YAML : 用于管理配置文件

https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml

Data Wrangler : 用于数据清理和转换

无论你的自动化程度如何,数据清理都是每个数据工程项目的一部分。

 Data Wrangler提供了丰富的用户界面,可直接在 VS Code 中分析、清理和转换数据。

 它提供有见地的统计数据、可视化效果,甚至在你清理时自动生成 Pandas 代码。

 非常适合快速探索数据集并在将其传递到管道之前对其进行转换。

https://marketplace.visualstudio.com/items?itemName=ms-toolsai.datawrangler

Copilot(Microsoft) / 通义灵码(阿里巴巴): 人工智能代码辅助

需要编写 SQL 查询或操作数据集,但又觉得重复的任务让人不知所措?GitHub Copilot就是你的新朋友。

 Copilot 由OpenAI 的 GPT提供支持,可帮助生成代码片段、解决复杂逻辑,甚至提出优化建议。它是加速代码编写的强大工具,让你可以更专注于解决问题,而不是编写样板代码。

https://marketplace.visualstudio.com/items?itemName=GitHub.copilot

Pylance : 对于 Python IntelliSense 和类型检查

Pylance 则通过高级 IntelliSense 功能增强了你的编码体验。

 它提供类型检查、更好的自动完成功能和更准确的建议,所有这些都可以帮助你编写更简洁、更高效的 Python 代码

https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance

SQLTools : 用于数据库探索和 SQL 查询

SQLTools简化了 VS Code 中的数据库管理,让你可以轻松连接和查询PostgreSQL、MySQL 和其他关系数据库。

 借助内置的查询运行器、架构探索器和自动完成功能,SQLTools 非常适合快速探索数据库和优化查询。

https://marketplace.visualstudio.com/items?itemName=mtxr.sqltools

Cloud Code : 对于 GCP 云开发和 Gemini AI

Cloud Code扩展程序利用 Google Cloud 和 Gemini 的强大功能,帮助你比以往更快、更轻松地构建应用程序。

 它就像 VS Code 中云原生开发的个人助理。它可帮助你无缝地与 Kubernetes、Cloud Run 和 Google Cloud API 协作。

 无论你部署应用程序、编写 YAML 配置还是在云中进行调试,它都能为你提供智能工具和流畅的工作流程。

 它非常适合管理基于云的管道和服务的数据工程师 - 不再为云设置而烦恼!

https://marketplace.visualstudio.com/items?itemName=GoogleCloudTools.cloudcode

Indent-Rainbow : 为了更清洁、更易于导航的代码

使用 Python 或 YAML 的挑战之一是复杂文件可能难以导航。

 Indent -Rainbow为缩进级别添加了颜色编码,这使得理解深度嵌套文件的结构变得更加容易。非常适合调试或重构复杂的数据转换脚本。

https://marketplace.visualstudio.com/items?itemName=oderwat.indent-rainbow

SQLite Viewer : 用于快速地对SQLLite数据库探索

有时,你只需要快速查看 SQLite 文件。无论你是在设计原型还是调试应用程序,SQLite Viewer都允许你直接在 V

S Code 中打开和查询 SQLite 数据库。

 当你想在小型数据集进入主管道之前检查它们或测试数据提取工作流时,这尤其有用。

https://marketplace.visualstudio.com/items?itemName=qwtel.sqlite-viewer

Postman : 用于 API 测试和监控

当你的数据提取涉及 API 时(无论是从外部源提取数据还是将其发送到下游系统),Postman都是无价之宝。

 此扩展将 API 测试直接集成到 VS Code 中,允许你发送请求、监控响应和实时调试 API 调用。

 对于构建复杂 ETL 管道的数据工程师来说,这是一个必备工具,可确保你的 API 集成按预期运行。

https://marketplace.visualstudio.com/items?itemName=Postman.postman-for-vscode

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牛马程序员2025

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值