内存中的绝配 ArcticDB ❤️ D-Tale

ArcticDB

2023年9月14日

0*i2JcN OwYRIcLHY8

自D-Tale最初版本发布以来,作为 Pandas 用户导航其 DataFrames 的一种方式,已经过去了近4年。期间新增了许多新功能,修复了大量错误。D-Tale 构造中一直存在争议的一点是它需要处理存储在内存中的 DataFrames。对于小型 DataFrame,这无疑是最好的解决方案,但用户习惯使用更大(数十亿行)和更宽(有时高达 40 万列)的 DataFrame。因此,显示这些维度的 DataFrame 变得十分笨拙。幸好,这个问题现在有了解决方案,那就是 ArcticDB

终于!终于有了导航你的 ArcticDB 数据库底层数据的解决方案。再一次,这个解决方案就是 D-Tale!

由 ArcticDB 支持的 D-Tale 使你能够探索远大于内存存储能力的数据集。当你向下滚动时,D-Tale 将按需分页载入所需的额外数据,这意味着数据不必同时全部存储在内存中。

入门指南

安装

运行

$ pip install dtale[arcticdb]

这将安装 D-Tale 和 ArcticDB。

设置本地数据库进行测试

import pandas as pd
import numpy as np
from datetime import datetime
from arcticdb import Arctic

uri = "lmdb:///tmp/dtale/arcticdb"
conn = Arctic(uri)
conn.create_library('lib1')
lib1 = conn['lib1']
lib1.write('symbol1', pd.DataFrame([
    {'col1': 1, 'col2': 1.1, 'col3': pd.Timestamp('20230101')}
]))
cols = ['COL_%d' % i for i in range(50)]
df = pd.DataFrame(np.random.randint(0, 50, size=(25, 50)), columns=cols)
df.index = pd.date_range(datetime(2000, 1, 1, 5), periods=25, freq="H")
lib1.write('symbol2', df)
lib1.write('symbol3', pd.DataFrame([
    {'col1': 2, 'col2': 2.2, 'col3': pd.Timestamp('20230102')}
]))
conn.create_library('lib2')
lib2 = conn['lib2']
N_COLS = 1000
N_ROWS = 20_000
cols = ['COL_%d' % i for i in range(N_COLS)]
big_df = pd.DataFrame(np.random.normal(loc=10.0, scale=2.5, size=(N_ROWS, N_COLS)), columns=cols)
big_df.index = pd.date_range(datetime(2000, 1, 1, 5), periods=N_ROWS, freq="H")
lib2.write('symbol4', big_df)
conn.create_library('lib3')
lib3 = conn['lib3']
lib3.write('symbol5', pd.DataFrame(
    {'col{}'.format(i): list(range(1000)) for i in range(105)}
))

启动 D-Tale 后端

import dtale.global_state as global_state
from dtale.app import build_app

uri = "lmdb:///tmp/dtale/arcticdb"
global_state.use_arcticdb_store(uri=uri)
app = build_app(reaper_on=False)
app.run(host="0.0.0.0", port=9207)

连接 D-Tale 并导航数据

>>> import dtale
>>> uri = "lmdb:///tmp/dtale/arcticdb"
>>> dtale.show_arcticdb(uri=uri, use_store=True)
<URL to access D-Tale UI>

use_store=True
强制 D-Tale 用于存储/读取/写入数据的机制使用 ArcticDB。这看起来微不足道,但它实际上极大地增强了 D-Tale 的基础设施。你现在可以读取任何大小的 DataFrame,而没有任何内存限制。D-Tale 只会读取需要在浏览器中显示的 DataFrame 的行/列,而不是将整个 DataFrame 加载到内存中。

导航

开始时,系统会提示你选择库 (library) 和符号 (symbol)。现在,我们暂时选择

lib1
&
symbol1
。选择后,你可以点击“加载”(Load)。

0*gZiW98X8gwDM2Y6o

你现在会看到标准的 D-Tale 网格,其中包含你符号中的数据。

0*S-aKwpdJhi80CqmC

你还会注意到屏幕顶部有一个条,显示你正在使用 ArcticDB,以及当前的 URI、库 (library) 和符号 (symbol)。点击该条会弹出一个窗口,你可以在其中选择不同的库 (library) 和符号 (symbol)。

0*5f90xJfSg8rjWsWJ

如果你的符号对应一个宽 DataFrame(超过 100 列),那么你还将有一个选项可以跳转到特定的列。默认情况下,对于任何超过 100 列的 DataFrame,第 100 列之后的任何列都将出于性能考虑而被隐藏。

0*i2JcN OwYRIcLHY8

需要一个专门用于跳转到特定列的弹窗,以便我们处理 DataFrame 包含超过 100 列的情况。浏览器渲染所有这些列会变得负担过重。更不用说,滚动到你正在寻找的列也会非常困难。所以现在你可以输入你要查找的列的名称并选择它。这将更新网格以显示该列的内容以及你之前锁定的任何列(默认情况下,索引列会被锁定)。

如果你确实想显示所有列,仍然可以使用“描述”(Describe) 弹窗并勾选所有列来完成。

0*hqjC6w-YURD0b0vi

现在你只会看到你锁定的列(在此示例中我们没有锁定任何列)和你选择跳转到的列。

0*uuw3LGZM-W1-QdbF

深入了解 ArcticDB

有关 ArcticDB 的更多信息,请参阅 文档网站。ArcticDB 的 LMDB 后端推荐用于本地测试,但对于实际工作负载,我们推荐使用 S3 后端。你只需将 D-Tale 指向一个由 S3 支持的 ArcticDB 实例,就可以浏览系统中各个进程正在写入的数据。

与原版 D-Tale 的功能差异

使用 ArcticDB 后端时,有些功能尚未实现。其中一些在将数据分页到浏览器时效果不佳(例如排序)。其中一些功能将在以后实现,基于 ArcticDB 的 QueryBuilder 接口构建。功能差异如下所示

  • 自定义过滤 — 能够指定自定义 pandas 查询

  • 列过滤 – 数值 — 范围过滤 (

    []

    ,

    ()

    ) 不再可用 – 字符串 — startswith(开头是)、endswith(结尾是)、contains(包含)、regex(正则表达式)、length(长度)和 case-sensitivity(区分大小写)

  • 排序

  • 编辑(此功能最终可能通过布尔配置属性提供)

  • 数据重塑器

  • DataFrame 函数

仍可用但仅适用于行数少于 100 万且列数少于等于 100 的 DataFrame 的功能

  • 唯一值计数

  • 异常值与异常值高亮显示

  • “描述”(Describe) 弹窗的许多初始详细信息

如果有任何你希望为 ArcticDB 添加回去的功能(不受 ArcticDB 本身控制),请在 D-Tale 仓库上提交 issue。

你随时可以回退到原版 D-Tale 实现,将整个 ArcticDB 符号加载到内存中,其过程已在上面的“连接 D-Tale”部分中说明。

为了解决这些问题,你可以将整个 ArcticDB 符号加载到内存中,而不是按照“连接 D-Tale”部分中的代码片段进行操作

>>> import dtale
>>> uri = "lmdb:///tmp/dtale/arcticdb"
# show one symbol,
>>> dtale.show_arcticdb(uri=uri, library="lib1", symbol="symbol1")
# alternative method to show one symbol
>>> lib = conn['lib1']
>>> df = lib.read('symbol1').data
>>> dtale.show(df)

如上所述,从 ArcticDB 分页加载数据具有明显的优势,因此仅在你遇到本文档中记录的“功能差异”之一时才遵循此替代方法。