将 Arrow 数据发送到浏览器的最佳方式是什么?

What is the best way to send Arrow data to the browser?

提问人:Brian 提问时间:1/4/2023 最后编辑:Brian 更新时间:1/6/2023 访问量:1301

问:

我在服务器(Python)上有Apache Arrow数据,需要在浏览器中使用它。Arrow Flight 似乎没有在 JS 中实现。将数据发送到浏览器并在那里使用它的最佳选择是什么?

我什至不需要浏览器中的箭头格式。这个问题还没有收到任何回复,所以我为我正在寻找的内容添加了一些额外的标准:

  • 自描述:不想维护单独的架构定义
  • 最小开销:例如,float32 数组应作为紧凑的内容传输,例如数据类型指示符、长度值和 4 字节浮点值序列
  • 跨平台:能够轻松地从 Python 发送,并以直接的方式在浏览器中接收和使用

这肯定是一个已解决的问题吗?如果是这样,我一直无法找到解决方案。请帮忙!

序列化 apache-arrow apache-arrow-flight

评论

0赞 li.davidm 1/5/2023
不必使用 Flight 来发送 Arrow 数据。您可以使用 Arrow 流编写器序列化 Arrow 数据,通过 HTTP 或 WebSockets 发送数据,并使用 Arrow JavaScript 库从浏览器加载数据。
0赞 Brian 1/5/2023
@li.davidm 谢谢你的提示!你能提供一个在Python中执行此操作的例子吗?我正在看图书馆,我不清楚。在 Python 方面,看起来流式处理函数希望流式传输到文件,而我将尝试通过 Starlette 响应发送它,该响应接受用于流式处理响应的生成器或迭代器。在浏览器方面,我认为只要我使用获取请求来读取数据,它就会起作用。tableFromIPC()
0赞 li.davidm 1/6/2023
在 Python 中,“文件”也可以只是一个 BytesIO,然后你可以把它塞进 Starlette(我自己不熟悉这个框架)。这行得通吗?我以后可以写出一个更长的答案
0赞 li.davidm 1/6/2023
啊,如果你确实想流式传输数据,它会变得有点复杂......
0赞 Brian 1/6/2023
我不一定需要流媒体。我正在研究流式处理,因为您提到了箭头流编写器。序列化到 bytesio 现在就可以了。

答:

3赞 amoeba 1/6/2023 #1

在David Li对原始帖子的评论的基础上,您可以在服务器端使用PyArrow和在客户端使用Apache Arrow JS绑定来实现您想要的非流式版本,而无需太多代码。Arrow IPC 格式可以满足您的要求,因为它随数据一起提供架构,节省空间且零拷贝,并且是跨平台的。

下面是一个玩具示例,演示如何在服务器上生成记录批处理并在客户端上接收它:

服务器:

from io import BytesIO

from flask import Flask, send_file
from flask_cors import CORS
import pyarrow as pa

app = Flask(__name__)
CORS(app)

@app.get("/data")
def data():
    data = [
        pa.array([1, 2, 3, 4]),
        pa.array(['foo', 'bar', 'baz', None]),
        pa.array([True, None, False, True])
    ]
    batch = pa.record_batch(data, names=['f0', 'f1', 'f2'])

    sink = pa.BufferOutputStream()

    with pa.ipc.new_stream(sink, batch.schema) as writer:
        writer.write_batch(batch)

    return send_file(BytesIO(sink.getvalue().to_pybytes()), "data.arrow")

客户

const table = await tableFromIPC(fetch(URL));
// Do what you like with your data

编辑:我在 https://github.com/amoeba/arrow-python-js-ipc-example 添加了一个可运行的示例。

评论

0赞 Felix B. 5/4/2023
为什么有这么多样板?如果我理解正确,数据缺少列名,这在 .然后我不确定 BufferOutputStream 在做什么,然后是 new_stream,然后一切都转换为 BytesIO 并最终发送?这似乎也总是一样的,为什么我不能假设样板的存在一定是有原因的batch=...send(batch)