我想使用Apache的parquet-mr项目以Java编程方式读/写Parquet文件。我似乎无法找到有关如何使用此API的任何文档(除了浏览源代码并查看它是如何使用的) - 只是想知道是否存在任何此类文档?
答案 0 :(得分:7)
我写了一篇关于阅读镶木地板文件(http://www.jofre.de/?p=1459)的博客文章,并提出了以下能够读取INT96字段的解决方案。
您需要以下maven依赖项:
<dependencies>
<dependency>
<groupId>org.apache.parquet</groupId>
<artifactId>parquet-hadoop</artifactId>
<version>1.9.0</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.7.0</version>
</dependency>
</dependencies>
代码基本上是:
public class Main {
private static Path path = new Path("file:\\C:\\Users\\file.snappy.parquet");
private static void printGroup(Group g) {
int fieldCount = g.getType().getFieldCount();
for (int field = 0; field < fieldCount; field++) {
int valueCount = g.getFieldRepetitionCount(field);
Type fieldType = g.getType().getType(field);
String fieldName = fieldType.getName();
for (int index = 0; index < valueCount; index++) {
if (fieldType.isPrimitive()) {
System.out.println(fieldName + " " + g.getValueToString(field, index));
}
}
}
}
public static void main(String[] args) throws IllegalArgumentException {
Configuration conf = new Configuration();
try {
ParquetMetadata readFooter = ParquetFileReader.readFooter(conf, path, ParquetMetadataConverter.NO_FILTER);
MessageType schema = readFooter.getFileMetaData().getSchema();
ParquetFileReader r = new ParquetFileReader(conf, path, readFooter);
PageReadStore pages = null;
try {
while (null != (pages = r.readNextRowGroup())) {
final long rows = pages.getRowCount();
System.out.println("Number of rows: " + rows);
final MessageColumnIO columnIO = new ColumnIOFactory().getColumnIO(schema);
final RecordReader<Group> recordReader = columnIO.getRecordReader(pages, new GroupRecordConverter(schema));
for (int i = 0; i < rows; i++) {
final Group g = recordReader.read();
printGroup(g);
// TODO Compare to System.out.println(g);
}
}
} finally {
r.close();
}
} catch (IOException e) {
System.out.println("Error reading parquet file.");
e.printStackTrace();
}
}
}
答案 1 :(得分:3)
您可以在以下链接中找到文档:https://www.javadoc.io/doc/org.apache.parquet/parquet-column/1.10.0
使用左上方的下拉列表list进行导航
答案 2 :(得分:1)
文档有点稀疏,代码有点简洁。我发现ORC更容易使用,如果这是你的选择。
下面的代码片段使用Avro界面将Parquet文件转换为带有标题行的CSV - 如果文件中有INT96(Hive时间戳)类型(Avro接口限制),则会失败,并且小数点会显示为字节数组。
确保使用版本1.9.0或更高版本的parquet-avro库,否则日志记录有点混乱。
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(java.io.FileDescriptor.out), "ASCII"));
ParquetReader<GenericRecord> reader = AvroParquetReader.<GenericRecord>builder(path).build();
Schema sc = null;
List<Field> fields = null;
for(long i = 0; i < lines; i++) {
GenericRecord result = reader.read();
if(result == null) {
break;
}
if(i == 0) {
sc = result.getSchema();
fields = sc.getFields();
if(header) { // print header out?
for(int j = 0; j < fields.size(); j++) {
if(j != 0) {
out.write(",");
}
out.write(fields.get(j).name());
}
out.newLine();
}
}
for(int j = 0; j < fields.size(); j++) {
if(j != 0) {
out.write(",");
}
Object o = result.get(j);
if(o != null) {
String v = o.toString();
if(!v.equals("null")) {
out.write("\"" + v + "\"");
}
}
}
out.newLine();
}
out.flush();
reader.close();
答案 3 :(得分:0)
这是@padmalcom答案的补充。该答案上的代码只是缺少对嵌套值的递归操作。取而代之的是,我返回一个JSONObject,这取决于开发人员如何打印等。我使用的是下面的函数,而不是他的printGroup()函数。 (感谢原始灵感)
private static JSONObject convertParquetGroupToJSONObject(final Group g) {
JSONObject jsonObject = new JSONObject();
int fieldCount = g.getType().getFieldCount();
for (int field = 0; field < fieldCount; field++) {
int valueCount = g.getFieldRepetitionCount(field);
Type fieldType = g.getType().getType(field);
String fieldName = fieldType.getName();
for (int index = 0; index < valueCount; index++) {
if (fieldType.isPrimitive()) {
try {
jsonObject.put(fieldName, g.getValueToString(field, index));
} catch (JSONException e) {
e.printStackTrace();
}
} else{
try {
jsonObject.put(fieldName, convertParquetGroupToJSONObject(g.getGroup(field, index)));
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}
return jsonObject;
}