帕尔克特.js
完全同步的纯节点.js 执行 Parquet 文件格式
此软件包包含一个完全同步的纯 JavaScript 执行 页:1 公园 文件格式。 执行工作符合 Parquet 规格 测试 与 Apache 的 Java 兼容 参考执行。 。 。 .
帕尔克是什么?: Parquet 是一个面向列的文件格式; 它允许您使用 将大量结构化数据写入文件, 压缩后读取部分 高效地退后 Parquet 格式基于 谷歌的德雷梅尔纸。 。 。 .
伪造通知
这是一个有各种来源代码的叉子仓库:
- 主要来源 铁源 npm: parquetjs (法语)
- 二级来源 兹琼森 npm: parquetjs-lite (法语)
安装
parquet.js 需要节点.js 20.20.2
$ npm install @dsnp/parquetjs
节点JS
用节点使用 :
import parquetjs from '@dsnp/parquetjs';
用 Bundler 浏览器
使用带捆绑器的浏览器时,根据您的需要,写出合适的插件或解析器,指向共同JS或ES模块版本:
// Common JS
'node_modules/@dsnp/parquetjs/dist/browser/parquetjs.cjs';
// ES Modules
'node_modules/@dsnp/parquetjs/dist/browser/parquetjs.esm';
或:
// Common JS
import parquetjs from '@dsnp/parquetjs/dist/browser/parquetjs.cjs';
// ES Modules
import parquetjs from '@dsnp/parquetjs/dist/browser/parquetjs.esm';
浏览器 直接: ES 模块
在浏览器中直接使用而不使用 ES 模块的捆绑器 :
- 构建软件包 :
npm install && npm run build:browser - 复制到
dist/browser/parquetjs.esm.js服务器 - 在您的 html 或其他 ES 模块中使用 :
<script type="module"> import parquetjs from '../parquet.esm.js'; // Use parquetjs </script>
浏览器 直接: Plain Ol' JavaScript
在没有捆绑或ES模块的浏览器中直接使用:
- 构建软件包 :
npm install && npm run build:browser - 复制到
dist/browser/parquetjs.js服务器 - 使用全局
parquetjs用于访问 parquetjs 函数的变量<script> // console.log(parquetjs) </script>
用法: 写入文件
一旦您安装了 parquet.js 库, 您可以将它作为单项导入 模块 :
var parquet = require('@dsnp/parquetjs');
Parquet文件有严格的计划,类似于SQL数据库中的表格. 这么说吧,
为了制作Parquet文件 我们首先需要宣布一个新的计划 给
是一个简单的例子,可以显示如何将 ParquetSchema 对象 :
本地Schema 定义
// declare a schema for the `fruits` table
var schema = new parquet.ParquetSchema({
name: { type: 'UTF8' },
quantity: { type: 'INT64' },
price: { type: 'DOUBLE' },
date: { type: 'TIMESTAMP_MILLIS' },
in_stock: { type: 'BOOLEAN' },
});
帮助函数
var schema = new parquet.ParquetSchema({
name: parquet.ParquetFieldBuilder.createStringField(),
quantity: parquet.ParquetFieldBuilder.createIntField(64),
price: parquet.ParquetFieldBuilder.createDoubleField(),
date: parquet.ParquetFieldBuilder.createTimestampField(),
in_stock: parquet.ParquetFieldBuilder.createBooleanField(),
});
杰森·斯克马
// declare a schema for the `fruits` JSON Schema
var schema = new parquet.ParquetSchema.fromJsonSchema({
type: 'object',
properties: {
name: {
type: 'string',
},
quantity: {
type: 'integer',
},
price: {
type: 'number',
},
date: {
type: 'string',
format: 'date-time',
},
in_stock: {
type: 'boolean',
},
},
required: ['name', 'quantity', 'price', 'date', 'in_stock'],
});
请注意, Parquet 计划支持筑巢, 所以你可以储存复杂,任意 将记录嵌入一行(较后),同时保持良好 压缩.
一旦我们有一个计划, 我们可以创建一个 ParquetWriter 对象。 作家会的
将输入行作为 JSON 对象,将其转换为 Parquet 格式并存储
它们在磁盘上.
// create new ParquetWriter that writes to 'fruits.parquet`
var writer = await parquet.ParquetWriter.openFile(schema, 'fruits.parquet');
// append a few rows to the file
await writer.appendRow({ name: 'apples', quantity: 10, price: 2.5, date: new Date(), in_stock: true });
await writer.appendRow({ name: 'oranges', quantity: 10, price: 2.5, date: new Date(), in_stock: true });
完成文件添加行后,必须告诉撰写对象
通过调用 close() 方法 :
添加开花过滤器
Bloom 过滤器可以添加到多列中,如下所示:
const options = {
bloomFilters: [
{
column: 'name',
numFilterBytes: 1024,
},
{
column: 'quantity',
numFilterBytes: 1024,
},
],
};
var writer = await parquet.ParquetWriter.openFile(schema, 'fruits.parquet', options);
默认情况下,不通过任何附加选项,则会根据不同值的默认数(128*1024)和默认的假正概率(0.001)来计算区块的最佳数,这就使过滤字节大小达到29,920.
提供了以下选项,以具备调整分块开花过滤器设置的能力.
numFilterBytes - 在字节中设定开花过滤器的欲望大小。 默认为128 1024 1024位.
falsePositiveRate - 为开花过滤器设定期望的假正比。 默认为0.001.
numDistinct - 设定不同数值的数目。 默认为128 * 1024比特.
注意如果提供了 numFilterBytes,则忽略了假 PositiveRate 和 numDistinct 选项 .
用法: 读取文件
一个parquet读取器可以按顺序从parquet文件中取回行. 基本用途是创建读取器,然后取回光标/绘图器 它允许您逐行消费,直到所有行被读取.
您可打开多个光标并同时使用 。 所有光标变为 关闭时无效 () 调用 读者反对.
// create new ParquetReader that reads from 'fruits.parquet`
let reader = await parquet.ParquetReader.openFile('fruits.parquet');
// create a new cursor
let cursor = reader.getCursor();
// read all records from the file and print them
let record = null;
while ((record = await cursor.next())) {
console.log(record);
}
创建光标时,您可以选择只请求一个子集 栏应从磁盘中读取。 例如:
// create a new cursor that will only return the `name` and `price` columns
let cursor = reader.getCursor(['name', 'price']);
在读完文件后, 您必须关闭此文件 避免泄露文件描述符.
await reader.close();
读取一个开花过滤器
Bloom 过滤器可以通过创建读取器从 parquet 文件取出
和电话 getBloomFiltersFor。 。 。 .
// create new ParquetReader that reads from 'fruits.parquet`
let reader = await parquet.ParquetReader.openFile('fruits.parquet');
// fetches bloom filter for the columns provided.
const bloomFilters = reader.getBloomFiltersFor(['name']);
=> {
name: [
{
rowGroupIndex: 0
columnName: 'name',
sbbf: SplitBlockBloomFilter<instance>
}
]
}
通话 getBloomFiltersFor 在读取器上返回一个对象,按键是一个列名,值是一个长度等于列组数的数组.
鉴于SplitBlockBloomFilter在过滤器中包含一个值,可以检查如下:
const sbbf = bloomFilters.name[0].ssbf;
sbbf.check('apples') ===> true
从url 读取数据
Parquet文件可以从url读取而无需下载整个文件.
您必须提供请求库作为第一个参数和请求参数
作为函数的第二个参数 parquetReader.openUrl。 。 。 .
const request = require('request');
let reader = await parquet.ParquetReader.openUrl(request, 'https://domain/fruits.parquet');
从 S3 读取数据
Parquet文件可以从一个S3对象读取而无需下载整个文件.
您必须提供 aws- sdk 客户端作为第一个参数和桶/ 键信息
作为函数的第二个参数 parquetReader.openS3。 。 。 .
const AWS = require('aws-sdk');
const client = new AWS.S3({
accessKeyId: 'xxxxxxxxxxx',
secretAccessKey: 'xxxxxxxxxxx',
});
const params = {
Bucket: 'xxxxxxxxxxx',
Key: 'xxxxxxxxxxx',
};
let reader = await parquet.ParquetReader.openS3(client, params);
从缓冲器读取数据
如果完整的parquet文件处于缓冲状态,则可以直接从内存中读取而无需再发生任何额外的 I/O.
const file = fs.readFileSync('fruits.parquet');
let reader = await parquet.ParquetReader.openBuffer(file);
编码
内部, Parquet 格式将连续存储每个字段的值 可用若干方案压缩/编码的数组.
普通编码( PLAIN)
最简单的编码方案是PLAIN编码. 它只是储存
值是没有压缩的。 PLAIN 编码目前
所有类型的默认值除外 BOOLEAN数字 :
var schema = new parquet.ParquetSchema({
name: { type: 'UTF8', encoding: 'PLAIN' },
});
运行长度编码( RLE)
Parquet 混合运行长度和位包编码允许压缩运行
数字非常高效。 注意 RLE 编码只能用于
结合 BOOLEAN, (中文(简体) ), INT32 财务报告和审定财务报表 INT64 类型。 RLE 编码
需要额外 typeLength 包含最大数量
存储字段最大值所需的比特.
var schema = new parquet.ParquetSchema({
age: { type: 'UINT_32', encoding: 'RLE', typeLength: 7 },
});
可选字段
默认情况下,所有字段都需要出现在每行中. 也可以标注 一个字段作为“ 可选的” 字段, 允许您存储缺少该字段的行 :
var schema = new parquet.ParquetSchema({
name: { type: 'UTF8' },
quantity: { type: 'INT64', optional: true },
});
var writer = await parquet.ParquetWriter.openFile(schema, 'fruits.parquet');
await writer.appendRow({ name: 'apples', quantity: 10 });
await writer.appendRow({ name: 'banana' }); // not in stock
嵌入式行和矩阵
Parquet 支持嵌入式计划,允许您存储更多行
复杂结构,而不是简单的平分值。 宣布一个计划
以嵌入地取出 type 在栏定义中添加 fields
列表改为:
举个例子,让我们可以储存一个更先进的"水果"表 其中每行包含名称、颜色列表和“库存”对象列表.
// advanced fruits table
var schema = new parquet.ParquetSchema({
name: { type: 'UTF8' },
colours: { type: 'UTF8', repeated: true },
stock: {
repeated: true,
fields: {
price: { type: 'DOUBLE' },
quantity: { type: 'INT64' },
},
},
});
// the above schema allows us to store the following rows:
var writer = await parquet.ParquetWriter.openFile(schema, 'fruits.parquet');
await writer.appendRow({
name: 'banana',
colours: ['yellow'],
stock: [
{ price: 2.45, quantity: 16 },
{ price: 2.6, quantity: 420 },
],
});
await writer.appendRow({
name: 'apple',
colours: ['red', 'green'],
stock: [
{ price: 1.2, quantity: 42 },
{ price: 1.3, quantity: 230 },
],
});
await writer.close();
// reading nested rows with a list of explicit columns
let reader = await parquet.ParquetReader.openFile('fruits.parquet');
let cursor = reader.getCursor([['name'], ['stock', 'price']]);
let record = null;
while ((record = await cursor.next())) {
console.log(record);
}
await reader.close();
可能并不明显,为什么人们想要实施或使用这种特征,如果 原则上也可以通过使用JSON对记录进行序列化来实现 (或类似方案)然后存储到UTF8字段:
把关于严格打字的优点的哲学讨论放在一边, 了解所有记录的结构和子类型(全球)意味着我们不 每个记录都必须复制此元数据(即字段名称)。 在顶上 其中,知道一个字段的类型 使我们能够压缩剩下的 数据效率更高.
巢穴/雅典娜的巢穴列表
列表必须附加注释才能被 AWS Athena 所征服. 见 平面图 在测试目录中列出更多细节和完整的工作范例(test/list.js(中文(简体) )
支持类型和编码列表
我们的目标是完成特色并增加新的功能,因为这些功能被添加到 Parquet 规格; 这是当前已执行的数据类型列表 编码 :
| 逻辑类型 | 初级类型 | 编码 |
|---|---|---|
| UTF8 主题 | BYTE 阿雷 | 诗 |
| 贾森 | BYTE 阿雷 | 诗 |
| 贝森 | BYTE 阿雷 | 诗 |
| BYTE 阿雷 | BYTE 阿雷 | 诗 |
| 时间( M) | INT32号 | 倒车,倒车 |
| 时间( M) | INT64 (英语) | 倒车,倒车 |
| 时光倒流 | INT64 (英语) | 倒车,倒车 |
| 时号( M) | INT64 (英语) | 倒车,倒车 |
| 玻利维亚 | 玻利维亚 | 倒车,倒车 |
| 浮图 | 浮图 | 诗 |
| 丢弃 | 丢弃 | 诗 |
| INT32号 | INT32号 | 倒车,倒车 |
| INT64 (英语) | INT64 (英语) | 倒车,倒车 |
| INT96号楼 | INT96号楼 | 诗 |
| INT 8 (中文(简体) ) | INT32号 | 倒车,倒车 |
| INT 16 请检查URL=值 (帮助) | INT32号 | 倒车,倒车 |
| INT 32 (英语) | INT32号 | 倒车,倒车 |
| 64国道 | INT64 (英语) | 倒车,倒车 |
| 无效 8 | INT32号 | 倒车,倒车 |
| UINT 16 请检查URL=值 (帮助) | INT32号 | 倒车,倒车 |
| UINT 32 请检查DATE=中的日期值 (帮助) | INT32号 | 倒车,倒车 |
| UINT 64 (中文(简体) ) | INT64 (英语) | 倒车,倒车 |
缓冲行组大小( R)
当写入 Parquet 文件时 ParquetWriter 将在内存中缓冲行
直到一行组完成(或 close() 然后写出行
组合到磁盘.
用户可配置行组的大小并控制最大值 任何特定时间在内存中缓冲的行数以及行数 磁盘上同一位置的行:
var writer = await parquet.ParquetWriter.openFile(schema, 'fruits.parquet');
writer.setRowGroupSize(8192);
浏览器测试
运行浏览器测试( 文件夹 : test/browser)在一个特定的浏览器中:
npm inpm run build:browsernpx serve .open http://localhost:3000/test/browser/在您首选的浏览器中( Trailing)/(所需)
依赖关系
平板用途 节俭 以编码图案和其他 元数据,但实际数据不使用节俭.
页:1
目前parquet-cpp不完全支持DATA PAGE V2. 你可以在这工作 通过将 DataPageV2 选项设置为虚假.