gpt4 book ai didi

java - 在Java中,如何创建等效的Apache Avro容器文件而又不被迫使用File作为媒介?

转载 作者:太空狗 更新时间:2023-10-29 22:35:55 24 4
gpt4 key购买 nike

万一精通Apache Avro的Java实现的读者正在阅读本文,这简直就是一片黑暗。

我的高级目标是通过某种方式在网络上传输一系列Avro数据(例如,以HTTP为例,但特定的协议(protocol)对于此目的并不那么重要)。在我的上下文中,我有一个HttpServletResponse,我需要以某种方式将此数据写入。

我最初尝试将数据写入等于avro容器文件的虚拟版本的数据(假设“响应”的类型为HttpServletResponse):

response.setContentType("application/octet-stream");
response.setHeader("Content-transfer-encoding", "binary");
ServletOutputStream outStream = response.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(outStream);

Schema someSchema = Schema.parse(".....some valid avro schema....");
GenericRecord someRecord = new GenericData.Record(someSchema);
someRecord.put("somefield", someData);
...

GenericDatumWriter<GenericRecord> datumWriter = new GenericDatumWriter<GenericRecord>(someSchema);
DataFileWriter<GenericRecord> fileWriter = new DataFileWriter<GenericRecord>(datumWriter);
fileWriter.create(someSchema, bos);
fileWriter.append(someRecord);
fileWriter.close();
bos.flush();

这一切都很好,很花哨,只是事实证明,Avro并没有提供一种除了读取实际文件之外的方法来读取容器文件:DataFileReader仅具有两个构造函数:
public DataFileReader(File file, DatumReader<D> reader);


public DataFileReader(SeekableInput sin, DatumReader<D> reader);

SeekableInput是一些特定于avro的自定义形式,其创建也最终会从文件中读取。现在,除非有某种方法可以将InputStream强制转换为文件(http://stackoverflow.com/questions/578305/create-a-java-file-object-or-equivalent-using-a-byte-不带内存的数组表示不存在,并且我也尝试查看Java文档),如果OutputStream另一端的阅读器收到该avro容器文件,则此方法将不起作用(我不确定为什么他们允许一个人将avro二进制容器文件输出到任意OutputStream,而没有提供从另一端的相应InputStream读取它们的方法,但这不重要。容器文件阅读器的实现似乎需要具体文件提供的“可搜索”功能。

好的,看来这种方法不会满足我的要求。如何创建模仿avro容器文件的JSON响应?
public static Schema WRAPPER_SCHEMA = Schema.parse(
"{\"type\": \"record\", " +
"\"name\": \"AvroContainer\", " +
"\"doc\": \"a JSON avro container file\", " +
"\"namespace\": \"org.bar.foo\", " +
"\"fields\": [" +
"{\"name\": \"schema\", \"type\": \"string\", \"doc\": \"schema representing the included data\"}, " +
"{\"name\": \"data\", \"type\": \"bytes\", \"doc\": \"packet of data represented by the schema\"}]}"
);

考虑到上述限制,我不确定这是否是解决此问题的最佳方法,但看来这可能会解决问题。我将模式(例如,来自上面的“Schema someSchema”的模式)作为字符串放入“schema”字段中,然后放入适合该模式的记录的avro-binary-serialized形式(即“GenericRecord” someRecord”)。

我实际上想知道下面将要描述的细节,但是我认为也有必要提供一个更大的背景,这样,如果有更好的高级方法,我可以采用(这种方法有效但感觉并不理想)请告诉我。

我的问题是,假设我采用这种基于JSON的方法,如何将Record的avro二进制表示形式写入AvroContainer模式的“data”字段中?例如,我起床到这里:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GenericDatumWriter<GenericRecord> datumWriter = new GenericDatumWriter<GenericRecord>(someSchema);
Encoder e = new BinaryEncoder(baos);
datumWriter.write(resultsRecord, e);
e.flush();

GenericRecord someRecord = new GenericData.Record(someSchema);
someRecord.put("schema", someSchema.toString());
someRecord.put("data", ByteBuffer.wrap(baos.toByteArray()));
datumWriter = new GenericDatumWriter<GenericRecord>(WRAPPER_SCHEMA);
JsonGenerator jsonGenerator = new JsonFactory().createJsonGenerator(baos, JsonEncoding.UTF8);
e = new JsonEncoder(WRAPPER_SCHEMA, jsonGenerator);
datumWriter.write(someRecord, e);
e.flush();

PrintWriter printWriter = response.getWriter(); // recall that response is the HttpServletResponse
response.setContentType("text/plain");
response.setCharacterEncoding("UTF-8");
printWriter.print(baos.toString("UTF-8"));

我最初尝试省略ByteBuffer.wrap子句,但随后
datumWriter.write(someRecord, e);

引发了一个异常,我无法将字节数组转换为ByteBuffer。公平地说,当调用Encoder类(JsonEncoder是其子类)来编写avro Bytes对象时,它看起来需要一个ByteBuffer作为参数。因此,我尝试用java.nio.ByteBuffer.wrap封装byte [],但是当打印出数据时,它被打印为连续的字节序列,而没有通过avro十六进制表示形式传递:
"data": {"bytes": ".....some gibberish other than the expected format...}

那似乎不对。根据avro文档,他们给的示例字节对象表示我需要放入一个json对象,该对象的示例看起来像“\u00FF”,而我输入的内容显然不是这种格式。我现在想知道的是以下内容:
  • avro字节格式的示例是什么?它看起来像“\uDEADBEEFDEADBEEF ...”吗?
  • 我如何将我的二进制avro数据(由BinaryEncoder输出到byte []数组中)强制转换为可以粘贴到GenericRecord对象中并使其在JSON中正确打印的格式?例如,我想要一个对象数据,可以在其上调用一些GenericRecord“someRecord.put(” data“,DATA);”我的avro序列化数据在里面?
  • 当给定文本JSON表示并想重新创建由AvroContainer格式JSON表示的GenericRecord时,我该如何将数据读回到另一端(消费者)的字节数组中?
  • (重申之前的问题)是否有更好的方法可以进行所有这些操作?
  • 最佳答案

    正如Knut所说,如果要使用文件以外的其他内容,则可以:

    正如Knut所说,

  • 使用SeekableByteArrayInput来进行任何可以将其插入字节数组的操作
  • 以您自己的方式实现SeekablInput-例如,如果您是从某种奇怪的数据库结构中获取它的。
  • 或只使用一个文件。为什么不?

  • 这些是您的答案。

    关于java - 在Java中,如何创建等效的Apache Avro容器文件而又不被迫使用File作为媒介?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7537959/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com