You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Arrow Flight服务器接收多Schema的GeoDataFrame与DataFrame?

解决Arrow Flight接收多Schema数据集的三种方案

针对你需要发送geopandas.GeoDataFrame和pandas.DataFrame两种不同Schema数据到Arrow Flight服务器的需求,这里提供三种可行的实现方式:

方案一:添加类型标记列合并为单表发送

给两个数据集分别添加一个用于区分的标记列,合并成一个Arrow表后发送,服务器接收后再根据标记拆分出原始数据集。

客户端代码示例

import pyarrow as pa
import pandas as pd
import geopandas as gpd
from pyarrow.flight import FlightClient, FlightDescriptor

# 构造测试数据
geo_df = gpd.GeoDataFrame({'name': ['A', 'B'], 'geometry': gpd.points_from_xy([1,2], [3,4])})
coords_df = pd.DataFrame({'x': [10,20], 'y': [30,40]})

# 添加类型标记列
geo_df['dataset_type'] = 'geo'
coords_df['dataset_type'] = 'coords'

# 转换为Arrow表并合并
geo_table = pa.Table.from_pandas(geo_df)
coords_table = pa.Table.from_pandas(coords_df)
combined_table = pa.concat_tables([geo_table, coords_table])

# 发送到服务器
client = FlightClient("grpc://localhost:50051")
descriptor = FlightDescriptor.for_path("combined_data")
writer, _ = client.do_put(descriptor, combined_table.schema)
writer.write_table(combined_table)
writer.close()

服务器代码示例

import pyarrow as pa
from pyarrow.flight import FlightServerBase, FlightDescriptor, FlightInfo, SchemaResult, FlightData

class CustomFlightServer(FlightServerBase):
    def __init__(self, location):
        super().__init__(location)
        self.geo_data = None
        self.coords_data = None

    def do_put(self, context, descriptor, reader, writer):
        # 读取合并后的表
        combined_table = reader.read_all()
        # 根据标记列拆分
        self.geo_data = combined_table.filter(pa.field('dataset_type') == 'geo').drop(['dataset_type'])
        self.coords_data = combined_table.filter(pa.field('dataset_type') == 'coords').drop(['dataset_type'])
        # 执行后续计算逻辑
        self._run_calculation()

    def _run_calculation(self):
        # 这里写你的内存计算逻辑
        if self.geo_data is not None and self.coords_data is not None:
            print("Geo数据行数:", self.geo_data.num_rows)
            print("坐标数据行数:", self.coords_data.num_rows)

if __name__ == "__main__":
    server = CustomFlightServer("grpc://localhost:50051")
    print("Server starting on port 50051...")
    server.serve()

方案二:分两次调用do_put,用FlightDescriptor区分

通过两次独立的do_put请求,用不同的FlightDescriptor(比如path参数)标记不同的数据集,服务器根据descriptor将数据存储到不同的内存变量中,待两个数据集都接收完成后执行计算。

客户端代码示例

import pyarrow as pa
import pandas as pd
import geopandas as gpd
from pyarrow.flight import FlightClient, FlightDescriptor

# 构造测试数据
geo_df = gpd.GeoDataFrame({'name': ['A', 'B'], 'geometry': gpd.points_from_xy([1,2], [3,4])})
coords_df = pd.DataFrame({'x': [10,20], 'y': [30,40]})

# 转换为Arrow表
geo_table = pa.Table.from_pandas(geo_df)
coords_table = pa.Table.from_pandas(coords_df)

# 发送Geo数据
client = FlightClient("grpc://localhost:50051")
geo_descriptor = FlightDescriptor.for_path("geo_data")
writer, _ = client.do_put(geo_descriptor, geo_table.schema)
writer.write_table(geo_table)
writer.close()

# 发送坐标数据
coords_descriptor = FlightDescriptor.for_path("coords_data")
writer, _ = client.do_put(coords_descriptor, coords_table.schema)
writer.write_table(coords_table)
writer.close()

服务器代码示例

import pyarrow as pa
from pyarrow.flight import FlightServerBase, FlightDescriptor

class CustomFlightServer(FlightServerBase):
    def __init__(self, location):
        super().__init__(location)
        self.geo_data = None
        self.coords_data = None

    def do_put(self, context, descriptor, reader, writer):
        # 根据descriptor的path判断数据类型
        path = descriptor.path[0]
        if path == "geo_data":
            self.geo_data = reader.read_all()
        elif path == "coords_data":
            self.coords_data = reader.read_all()
        
        # 检查是否两个数据都已接收,执行计算
        if self.geo_data is not None and self.coords_data is not None:
            self._run_calculation()

    def _run_calculation(self):
        # 内存计算逻辑
        print("开始计算...")
        # 示例:关联Geo数据和坐标数据的逻辑
        # ...

if __name__ == "__main__":
    server = CustomFlightServer("grpc://localhost:50051")
    print("Server starting on port 50051...")
    server.serve()

方案三:用Arrow Struct类型封装两个数据集

将两个数据集封装到一个Arrow Struct类型的字段中,作为单个表发送,服务器接收后提取Struct字段中的两个子表。

客户端代码示例

import pyarrow as pa
import pandas as pd
import geopandas as gpd
from pyarrow.flight import FlightClient, FlightDescriptor

# 构造测试数据
geo_df = gpd.GeoDataFrame({'name': ['A', 'B'], 'geometry': gpd.points_from_xy([1,2], [3,4])})
coords_df = pd.DataFrame({'x': [10,20], 'y': [30,40]})

# 转换为Arrow RecordBatch
geo_batch = pa.RecordBatch.from_pandas(geo_df)
coords_batch = pa.RecordBatch.from_pandas(coords_df)

# 构造Struct类型的字段
struct_type = pa.struct([
    ('geo_data', geo_batch.schema),
    ('coords_data', coords_batch.schema)
])
# 创建包含单个Struct值的RecordBatch
batch = pa.RecordBatch.from_arrays(
    [pa.array([{'geo_data': geo_batch.to_pylist()[0], 'coords_data': coords_batch.to_pylist()[0]},
               {'geo_data': geo_batch.to_pylist()[1], 'coords_data': coords_batch.to_pylist()[1]}], type=struct_type)],
    names=['combined']
)
table = pa.Table.from_batches([batch])

# 发送到服务器
client = FlightClient("grpc://localhost:50051")
descriptor = FlightDescriptor.for_path("struct_combined")
writer, _ = client.do_put(descriptor, table.schema)
writer.write_table(table)
writer.close()

服务器代码示例

import pyarrow as pa
from pyarrow.flight import FlightServerBase, FlightDescriptor

class CustomFlightServer(FlightServerBase):
    def __init__(self, location):
        super().__init__(location)
        self.geo_data = None
        self.coords_data = None

    def do_put(self, context, descriptor, reader, writer):
        table = reader.read_all()
        # 提取Struct字段中的数据
        geo_arrays = table['combined'].field('geo_data').flatten()
        coords_arrays = table['combined'].field('coords_data').flatten()
        
        # 重建原始表
        self.geo_data = pa.Table.from_arrays(geo_arrays, schema=geo_arrays.type.schema)
        self.coords_data = pa.Table.from_arrays(coords_arrays, schema=coords_arrays.type.schema)
        
        # 执行计算
        self._run_calculation()

    def _run_calculation(self):
        print("Geo数据Schema:", self.geo_data.schema)
        print("坐标数据Schema:", self.coords_data.schema)

if __name__ == "__main__":
    server = CustomFlightServer("grpc://localhost:50051")
    print("Server starting on port 50051...")
    server.serve()

内容的提问来源于stack exchange,提问作者Daí

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 19:20:08