添加新后端

问:如何向 odo 图中添加新节点?

扩展函数

我们通过为每种新类型实现几个函数来扩展 Odo

  • discover - 返回对象的 DataShape
  • convert - 将数据转换为新类型
  • append - 将数据追加到现有数据源
  • resource - 通过字符串 URI 标识数据

我们通过编写用类型装饰的新小型函数来扩展这些功能。Odo 将会识别它们,将其整合到网络中,并在适当时候使用它们。

发现

Discover 返回对象的 DataShape。DataShape 是形状和数据类型的一种潜在嵌套组合。它有助于我们在迁移数据本身时一致地迁移元数据。这使我们即使在通过可能存在损耗的格式进行转换时也能得到正确的数据类型。

示例

>>> discover([1, 2, 3])
dshape("3 * int32")

>>> import numpy as np
>>> x = np.empty(shape=(3, 5), dtype=[('name', 'O'), ('balance', 'f8')])
>>> discover(x)
dshape("3 * 5 * {name: string, balance: float64}")

扩展

我们从 datashape 库导入 discover 并用一个类型来扩展它。

from datashape import discover, from_numpy

@discover(pd.DataFrame)
def discover_dataframe(df, **kwargs):
    shape = (len(df),)
    dtype = df.values.dtype
    return from_numpy(shape, dtype)

在这个简单的例子中,我们依赖于 datashape 中的便捷函数,从 numpy 形状和数据类型构造 datashape。对于更复杂的情况(例如数据库),可能需要手动构造 datashape。

转换

Convert 将您的数据复制到具有不同类型的新对象中。

示例

>>> x = np.arange(5)
>>> x
array([0, 1, 2, 3, 4])

>>> convert(list, x)
[0, 1, 2, 3, 4]

>>> import pandas as pd
>>> convert(pd.Series, x)
0    0
1    1
2    2
3    3
4    4
dtype: int64

扩展

odo 导入 convert 并用两种类型注册它,一种用于目标,一种用于源。

from odo import convert

@convert.register(list, np.ndarray)
def array_to_list(x, **kwargs):
    return x.tolist()

@convert.register(pd.Series, np.ndarray)
def array_to_series(x, **kwargs):
    return pd.Series(x)

追加

Append 将您的数据复制到现有数据集中。

示例

>>> x = np.arange(5)
>>> x
array([0, 1, 2, 3, 4])

>>> L = [10, 20, 30]
>>> _ = append(L, x)
>>> L
[10, 20, 30, 0, 1, 2, 3, 4]

扩展

odo 导入 append 并用两种类型注册它,一种用于目标,一种用于源。通常我们教 odo 如何从一种首选类型进行追加,然后对所有其他类型使用 convert。

from odo import append

@append.register(list, list)
def append_list_to_list(tgt, src, **kwargs):
    tgt.extend(src)
    return tgt

@append.register(list, object)  # anything else
def append_anything_to_list(tgt, src, **kwargs):
    source_as_list = convert(list, src, **kwargs)
    return append(tgt, source_as_list, **kwargs)

资源

Resource 根据与正则表达式匹配的字符串 URI 创建对象。

示例

>>> resource('myfile.hdf5')
<HDF5 file "myfile.hdf5" (mode r+)>

>>> resource('myfile.hdf5::/data', dshape='10 * 10 * int32')
<HDF5 dataset "data": shape (10, 10), type "<i4">

它返回的对象分别是 h5py.Fileh5py.Dataset。在第二种情况下,resource 发现数据集不存在,因此创建了它。

扩展

我们从 odo 导入 resource 并用正则表达式注册它。

from odo import resource

import h5py

@resource.register('.*\.hdf5')
def resource(uri, **kwargs):
    return h5py.File(uri)

一般注意事项

我们将顶级调用中所有关键字参数传递给 odo 所有函数。这允许特殊关键字参数传递到正确的位置,例如 delimiter=';' 在与 CSV 文件交互时会传递到 pd.read_csv 调用,但这也意味着您编写的所有函数都必须预料并处理不需要的关键字参数。这通常需要您进行一些过滤。

尽管我们所有的四个抽象函数都有一个 .register 方法,但它们的运作方式大相径庭。Convert 由 networkx 和路径查找管理,appenddiscovermultipledispatch 管理,而 resource 由正则表达式管理。

示例很有用。您可能需要查看一些 odo 简单后端源代码以获取帮助。