跳到内容

元数据

ArcticDB 允许您在符号和版本旁存储任意二进制 blob。

下面的示例展示了写入和读取元数据的基本示例(在本例中是一个 Python 字典)

import arcticdb as adb
# This example assumes the below variables (host, bucket, access, secret) are validly set
ac = adb.Arctic(f"s3://{HOST}:{BUCKET}?access={ACCESS}&secret={SECRET})
library = "my_library"

if library not in ac.list_libraries():
    ac.create_library(library)

library = ac[library]

metadata = {
    "This": "is",
    "a": "Python",
    "Dictionary": "!"
}

lib.write("meta", data=pd.DataFrame(), metadata=metadata)  # or write_metadata can be used - will still create a new version, but doesn't require `data` to be passed in

assert lib.read("meta").metadata == metadata
assert lib.read_metadata("meta").metadata == metadata  # Same as read, but doesn't return data from storage

符号的新版本不会“继承”先前版本的元数据。每次创建符号的新版本时,都需要显式指定元数据。

lib.write("new_sym", data=pd.DataFrame(), metadata=metadata)
lib.write("new_sym", data=pd.DataFrame())

assert lib.read("new_sym").metadata is None
assert lib.read("new_sym", as_of=0).metadata == metadata

序列化格式

我们根据可能的情况使用 msgpack 对元数据进行序列化。我们支持内置的 msgpack 类型以及

  • Pandas 时间戳 pd.Timestamp
  • Python datetime datetime.datetime
  • Python timedelta datetime.timedelta

支持的 msgpack 结构文档可在此处获取:here。数组和映射分别对应于 Python 列表和字典。

当元数据的 msgpack 序列化因不支持的类型而失败时,我们会回退到使用 pickling 来处理元数据。Pickling 可能存在严重缺点,因为客户端使用不同版本的库可能无法解封用另一组库版本写入的数据。

因此,当元数据被 pickled 时,我们会记录一条警告。您可以通过将环境变量 ARCTICDB_PickledMetadata_loglevel_str 设置为 DEBUG 来禁用此警告。日志消息看起来像

Pickling metadata - may not be readable by other clients

元数据的大小可能高达 4GB。

实用示例 - 使用元数据跟踪供应商时间线

元数据的一个常见用途是存储供应商提供的数据日期以及版本。例如,假设我们正在处理三个文件 - data-2004-01-01.csvdata-2004-01-02.csvdata-2004-01-03.csv。每个文件名都包含一个日期,我们希望能够将其与 ArcticDB 中的版本信息一起存储。

我们可以使用以下代码来实现:

import glob
import datetime
import arcticdb as adb

# This example assumes the below variables (host, bucket, access, secret) are validly set
ac = adb.Arctic(f"s3://{HOST}:{BUCKET}?access={ACCESS}&secret={SECRET})
library = "my_library"

if library not in ac.list_libraries():
    ac.create_library(library)

library = ac[library]

file_names = glob.glob('*.csv')  # returns ['data-2004-01-01.csv', 'data-2004-01-02.csv', 'data-2004-01-03.csv']

for i, name in enumerate(file_names):
    data = pd.read_csv('name')
    date = datetime.datetime.strptime(name[5:][:-4], '%Y-%m-%d')

    if i == 0:
        lib.write("symbol", data, metadata={"vendor_date": date})
    else:
        lib.append("symbol", data, metadata={"vendor_date": date})

现在,我们将使用此方法按照供应商提供的时间线读取数据——也就是说,我们将检索数据,就像我们在生成每个文件的那一天写入数据一样。我们将读取符号所有版本的所有元数据条目,并选择相对于给定日期(在本例中是 2004-01-02)而言最新的日期。

# Continuing from the previous code snippet
metadata = [
    (v["version"], lib.read_metadata("symbol", as_of=v["version"]).metadata.get("vendor_date"))
    for v in lib.list_versions("symbol")
]
sorted_metadata = sorted(metadata, key=lambda x: x[1])

version_to_read_index = bisect_right([x[1] for x in sorted_metadata], datetime.datetime(2004, 1, 2))
lib.read("symbol", as_of=sorted_metadata[version_to_read_index - 1][0])

请注意,如果数据写入多个符号,则可以使用 ArcticDB 快照来实现相同的结果。