ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

Lance 性能调优完全指南:日志、线程、内存与索引优化的实战手册

Lance 性能调优完全指南:日志、线程、内存与索引优化的实战手册 Lance 性能调优完全指南日志、线程、内存与索引优化的实战手册【免费下载链接】lanceOpen Lakehouse Format for Multimodal AI. Convert from Parquet in 2 lines of code for 100x faster random access, vector index, and data versioning. Compatible with Pandas, DuckDB, Polars, Pyarrow, and PyTorch with more integrations coming..项目地址: https://gitcode.com/GitHub_Trending/la/lanceLance 是一个面向多模态 AI 的开源湖仓格式Lakehouse Format在随机访问、向量索引与数据版本管理上做了大量性能优化。本文是 Lance Performance Guide 的深度展开版围绕日志与可观测性、线程模型、内存缓存、云存储限流、分片设计与索引内存模型六大主题给出可直接落地的调优参数、配置示例与源码级原理。读完本文你将能够快速定位 Lance 应用的性能瓶颈I/O、CPU、缓存命中率、限流抖动根据数据集规模与存储介质正确设置LANCE_IO_THREADS、LANCE_CPU_THREADS、io_buffer_size、batch_size等关键参数并为写密集场景设计合理的分片粒度与冲突规避策略。日志与可观测性用环境变量掌控 Lance 的运行时行为Lance 内部使用 Rust 的logcrate 输出日志。在 Rust 客户端中你需要自行配置日志订阅器logging subscriber而 Pythonpylance与 Java 客户端默认配置了输出到 stderr 的日志订阅器。Python 客户端的日志初始化逻辑位于 python/src/lib.rs 的init_logging函数其env_logger构建过程python/src/lib.rs完整读取了以下五个环境变量环境变量作用取值说明LANCE_LOG按日志级别与 target 过滤日志语法遵循env_logger规范例如warn、debug、lance::events::object_store::throttleinfoLANCE_TRACING控制 tracing 追踪事件的过滤级别默认infotrace/debug/info/warn/errorLANCE_LOG_STYLE是否在日志中使用颜色auto默认、always、neverLANCE_LOG_TS_PRECISION日志时间戳精度ns、us、ms、sLANCE_LOG_FILE将 Rust 日志重定向到指定文件而非 stderr文件路径创建失败时回退到 stderr几点实用建议LANCE_LOG取代了旧的RUST_LOG。它既可以整体过滤也可以按 target 精细过滤。例如只开启存储限流事件而不放大其他日志LANCE_LOGwarn,lance::events::object_store::throttleinfo。LANCE_TRACING用于诊断性能问题。关键追踪事件默认在info级别发出但debug级别下还有更多 span 与事件排查吞吐、延迟问题时建议临时调低。LANCE_LOG_FILE的实现细节从源码可见python/src/lib.rs设置后会尝试创建文件的父目录若因权限等原因创建失败会打印提示并回退到 stderr不会导致程序崩溃。注意它是追加append模式打开。无效的LANCE_LOG_TS_PRECISION取值会在日志系统初始化前打印一条提示并回退到默认精度可参考 python/src/lib.rs。Python 侧还有一个细节LANCE_LOG的级别会同时映射到 Pythonlogging模块。在 python/python/lance/log.py 中Rust 的trace级别被映射为 Python 的DEBUG因为 Python 没有 trace未带的过滤条目中的第一个级别会被用作 Python logger 的级别。Trace Events六大追踪事件类别与性能诊断除了普通日志Lance 还用tracing输出结构化追踪事件。在 pylance 中这些事件以日志消息形式发出且统一挂在lance::events::前缀下便于与普通日志记录区分过滤Rust 客户端则可用tracingcrate 订阅。六大事件类别如下。文件审计事件File Audit在重要文件被创建或删除时发出事件参数描述lance::file_auditmodeI/O 操作模式create、delete、delete_unverifiedlance::file_audittype受影响文件类型manifest、data file、index file、deletion file数据集事件Dataset Events数据集被加载、写入、提交、删除、压缩compaction或清理cleanup时发出事件参数描述lance::dataset_eventsevent数据集事件类型loading、writing、committed、deleting 等lance::dataset_eventsuri数据集 URIlance::dataset_eventsmode写入模式lance::dataset_eventsoperation已提交事务的操作类型lance::dataset_eventspredicate删除谓词lance::dataset_eventscolumns被移除的列对象存储限流事件Object Store Throttle当 Lance 观测到云存储的限流响应并主动降速或重试时发出事件参数描述lance::object_store::throttleprevious_rateAIMD 调整前的请求速率lance::object_store::throttlenew_rateAIMD 调整后的请求速率lance::object_store::throttleattempt重试次数用于重试调试事件lance::object_store::throttleerror底层对象存储的限流错误在 pylance 中可通过LANCE_LOGwarn,lance::events::object_store::throttleinfo只打开这类事件观察存储侧是否在频繁限流。I/O 事件I/O Events执行重要 I/O 操作时发出尤其与索引相关。注意当索引命中内存缓存时不会发出这些事件——缓存利用率直接影响性能因此这类事件就是为排查缓存使用情况设计的事件参数描述lance::io_eventstypeI/O 操作类型open_scalar_index、open_vector_index、load_vector_part、load_scalar_part执行事件Execution Events执行计划运行完成后发出用于调试查询性能事件参数描述lance::executiontype执行事件类型当前仅有 plan_runlance::executionoutput_rows计划输出的行数lance::executioniops计划执行的 I/O 操作次数lance::executionbytes_read计划读取的字节数lance::executionindices_loaded计划加载的索引数量lance::executionparts_loaded计划加载的索引分区数lance::executionindex_comparisons各索引内部执行的比较次数其中parts_loaded在后文讨论 BTree、Bitmap 索引的磁盘加载行为时还会反复用到它直接告诉你一次查询从磁盘加载了多少页/多少 bitmap是判断缓存命中率的直接指标。线程模型IO 线程池与计算线程池Lance 被设计为线程安全且高性能API 默认支持并发调用多表可跨线程共享同一张表上的操作可并行执行但部分操作会产生冲突详见 事务冲突解决。绝大多数操作会使用两个线程池并行工作IO 线程池负责磁盘数据的读写。默认线程数取决于对象存储类型——本地存储默认 8 线程云存储默认 64 线程。这个默认值偏保守在部分云厂商上可能需要 128 甚至 256 线程才能打满网络带宽。通过LANCE_IO_THREADS覆盖。增加 IO 线程数时通常也应同步调大io_buffer_size见内存章节。计算线程池负责数据计算。默认线程数为机器核数可用LANCE_CPU_THREADS覆盖。这在单机运行多个 Lance 进程例如配合 Ray 等分布式框架时很常见。需要特别强调的是解码decode是计算密集型操作。即便某个工作负载看起来是 I/O 密集比如全表扫描解码仍可能消耗大量计算线程想要达到峰值性能不能把 CPU 线程压得太低。相关参数在扫描器的实现中也有体现例如 rust/lance/src/dataset/scanner.rs 中的fragment_readahead控制同时调度读取的 fragment 数量。内存需求与缓存调优Lance 设计上注重内存效率操作以流式方式从磁盘读取不需要把整个数据集载入内存。但以下组件可能占用大量内存需要针对性调优。元数据缓存Metadata CacheLance 用 LRU 缓存加速操作按字节计容量默认 1 GiB缓存内容包括文件元数据、数据集 manifest 等。缓存默认不跨表共享。追求性能时应当创建单张表并在整个应用内共享或者创建单个 session并在打开表时指定该 session。Python API 中可通过dataset.open_table(..., metadata_cache_size_bytes...)调整大小。缓存键常由多字段复合而成且所有键都作用域限定到数据集 URI具体条目如下条目键缓存内容Dataset Manifests数据集 URI、版本、etag数据集 manifestTransactions数据集 URI、版本数据集事务Deletion Files数据集 URI、fragment_id、版本、id、file_typefragment 的删除向量Row Id Mask数据集 URI、版本数据集的行 ID 序列Row Id Index数据集 URI、版本数据集的行 ID 索引Row Id Sequence数据集 URI、fragment_id、row_id_metafragment 的行 ID 序列Index Metadata数据集 URI、版本数据集的索引元数据Index Details¹数据集 URI、索引 uuid单个索引的详情File Global Meta数据集 URI、文件路径文件的全局元数据File Column Meta数据集 URI、文件路径、列索引列的搜索缓存¹ 仅对极老版本、未将索引详情写入 manifest 的索引生效。索引缓存Index Cache索引缓存用于加速查询把向量索引与标量索引进内存按字节计容量的 LRU 缓存默认 6 GiB。在 Python 中通过创建LanceDataset时的index_cache_size_bytes参数配置可通过dataset.session().size_bytes()查看当前大小。注意index_cache_size按条目数计自 0.30.0 起已废弃新代码请使用按字节计的index_cache_size_bytes。Python 绑定中的弃用处理可见 python/python/lance/dataset.py。与元数据缓存一样索引缓存默认不跨表共享最佳实践仍是共享单表或单 session。扫描数据Scanning Data的内存模型向量检索、全文检索通常返回数据量不大内存占用不高但扫描scan可能消耗大量内存。扫描是流式操作但必须能容纳正在扫描的数据。内存占用主要由io_buffer_size与batch_size决定每个 IO 线程需要足以缓冲一页page数据的内存。当前页面通常为 8~32 MB经验法则是每个 IO 线程预留约 32 MB。默认io_buffer_size为 2 GB足以缓冲 64 页。增加 IO 线程数时应同步调大io_buffer_size。计算线程并行解码。解码数据量由batch_size与行大小决定每个 CPU 线程需能容纳一个 batch 的内存。batch 交付给应用后 Lance 不再跟踪因此如果关心内存应用侧也要避免累积 batch例如频繁调用to_table或在内存中收集全部 batch。默认batch_size为 8192 行。纯标量数据建议保持 batch 约 1 MB计算线程内存占用很小但处理大行数据时需要调小batch_size。例如 1024 维 float32 向量嵌入8192 行就是 32 MB 数据若分散到 16 个 CPU 线程每次扫描需要 512 MB 计算内存——此时改用每批 1024 行更合适。远程扫描远程对象存储调优有序数据集扫描仍然会重叠多个 fragment 的 I/O。scan_in_orderTrue只控制 batch 的返回顺序并不会让 fragment 读取变成串行——这就是数据集扫描比单 fragment 扫描发出更多并发请求的原因。以下参数分别控制扫描的不同环节fragment_readahead限制同时调度读取的 fragment 数量。设为1可匹配 fragment 级 I/O 模式存储连接还有富余带宽时再调大。LANCE_IO_THREADS限制进程级并发存储请求。云存储默认 64这是为同区域高带宽访问设计的跨区域或公网访问时可能过于激进。io_buffer_size限制缓冲 I/O 字节数解码跟不上时提供背压backpressure。batch_readahead限制并发 batch 解码数量不控制存储区间请求的大小。带宽受限的远程连接建议从保守参数起步再向上调LANCE_IO_THREADS8 python scan.pyscanner dataset.scanner( fragment_readahead1, batch_readahead2, io_buffer_size64 * 1024 * 1024, ) for batch in scanner.to_batches(): process(batch)一个容易误解的点Lance 从存储读取的是编码后的页面所以调小batch_size只会改变返回与解码的 batch 大小不一定会缩小首次区间请求——第一个 batch 可能需要为每个选中的列各加载一个编码页。综上一次扫描的内存上界约为(2 * io_buffer_size) (batch_size * num_compute_threads)字节。另外io_buffer_size是软限制当前实现无法读取小于一页的数据因此内存使用略微超出该上界是正常的不一定是 bug。云存储限流AIMD Rate LimiterS3、GCS、Azure 等云对象存储会被自动包裹一个AIMDAdditive Increase / Multiplicative Decrease加性增乘性减速率限制器存储返回限流错误HTTP 429/503时请求速率乘性下降持续成功时速率加性上升应用于所有操作读、写、删、list取代旧的LANCE_PROCESS_IO_THREADS_LIMIT进程级上限本地与内存存储不受限流。该实现位于 rust/lance-io/src/object_store/throttle.rs读写删列四类操作各有一套独立的 AIMD 控制器与令牌桶避免读突发饿死写操作限流错误通过is_throttle_error判定基于错误消息启发式匹配 429/503、slowdown、rate limit 等特征并按max_retries次随机退避重试。AIMD 可通过存储选项storage options或环境变量调优存储选项优先级高于环境变量设置项存储选项键环境变量默认值初始速率lance_aimd_initial_rateLANCE_AIMD_INITIAL_RATE2000最小速率lance_aimd_min_rateLANCE_AIMD_MIN_RATE1最大速率lance_aimd_max_rateLANCE_AIMD_MAX_RATE5000下降因子lance_aimd_decrease_factorLANCE_AIMD_DECREASE_FACTOR0.5加性增量lance_aimd_additive_incrementLANCE_AIMD_ADDITIVE_INCREMENT300突发容量lance_aimd_burst_capacityLANCE_AIMD_BURST_CAPACITY100源码中的完整配置还包括重试次数与退避范围lance_aimd_max_retries默认 3、lance_aimd_min_backoff_ms默认 100、lance_aimd_max_backoff_ms默认 300解析逻辑见AimdThrottleConfig::from_storage_optionsrust/lance-io/src/object_store/throttle.rs。这些默认值经过平衡适用于大多数场景。例如 S3 通常能达到约 5000 req/s按这些参数约 10 秒即可爬升到上限。Fragment 分片大小设计Lance 表由 manifest 追踪的 fragment 集合构成。分片大小需要在两类工作之间权衡manifest 级操作的代价随 fragment数量增长。每次数据集变更追加、元数据更新、schema 变更、压缩等都会重写 manifestfragment 越多每次写入越慢读取也付出类似的前置代价——打开数据集、列出 fragment、规划扫描、解析数据集级事务冲突都要遍历 manifest。fragment 级操作的代价随 fragment大小增长包括对命中 fragment 的扫描、压缩、更新、删除与merge_insert其冲突检测也在 fragment 级进行。因此更少更大的 fragment 让 manifest 级操作变快但每个 fragment 级操作更重且多写入方指向同一 fragment 时冲突概率更高更多更小的 fragment 则相反。实操建议默认每 fragment 100 万行在 ~10 亿行以内表现良好超出后可以上调到约每 fragment 1 亿行不过实践中 fragment 数量很少成为瓶颈每表数万个 fragment 通常没问题单个 fragment 要远低于对象存储的单对象大小上限S3 上限 5 TB且存储服务在该值之前就可能出问题。每 fragment 10 GB~100 GB 是合理上限区间1 TB 是硬性天花板若并发执行大量 update、delete 或merge_insert应倾向于更多 fragment——冲突检测按 fragment 进行fragment 过少会导致过多重试。冲突处理与 Fragment Reuse IndexFRILance 使用乐观并发控制支持同表并发操作。发生冲突时一方必须重试重试虽是自动的但会重复已完成的工作、损害吞吐。常见冲突源并发压缩与索引构建——两者都要修改同一批索引影响相同 fragment 的更新操作——两者都要重写相同的数据文件。各操作间的冲突关系详见 事务冲突解决。压缩是最昂贵的写操作之一它重写数据文件并且默认会重映射所有索引以反映新的行地址。压缩与索引构建并发时经常冲突导致压缩失败重试反复失败会让表布局随时间劣化。Fragment Reuse IndexFRI通过让压缩跳过索引重映射步骤解决该问题压缩时记录一份「旧 fragment 行地址 → 新地址」的映射索引加载进缓存时再应用 FRI 完成地址翻译。这会带来微小的索引加载开销但索引缓存命中后不影响查询性能。解耦之后压缩与索引构建不再冲突对「持续摄入数据同时维护索引」的表尤其有价值。启用方式Pythondataset.optimize.compact_files(defer_index_remapTrue)Rust 调用方可通过Dataset::frag_reuse_index()为已加载的数据集版本打开 FRI无 FRI 时返回None。返回的索引暴露原始重映射物理行地址要么未映射、要么被记录的压缩删除、要么映射到保留映射链最后到达的地址。注意两种结果都不会针对已加载 manifest 做校验——未映射的地址可能因历史被裁剪而在某次压缩中移动过映射目标也可能随后被删除。因此需要完整翻译的调用方必须自行校验覆盖范围与目标。相关实现与清理逻辑可见 rust/lance/src/dataset/index/frag_reuse.rs索引格式与使用模式详见 Fragment Reuse Index 规范。索引的内存、存储与性能权衡不同类型的索引在训练与搜索阶段对计算和内存的需求差异很大下面按类型逐一说明。BTree 索引BTree 是两级结构兼顾「全量驻留内存的昂贵结构」与「无法高效搜索的昂贵磁盘结构」擅长范围查询与有序访问。训练通过对外部排序external sort排序列将总内存控制在合理范围。更新 BTree 索引不需要重排序整列新值单独排序后与既有有序值线性归并。存储本质上是列的排序副本占用与列本身相当但每个值额外需要 4 字节存行 ID外加一个约为列大小 0.001% 的小型查找结构。内存训练期会激进地溢写磁盘spill总内存占用较低搜索时索引按页加载进索引缓存每页 4096 个值。性能排序阶段最昂贵时间复杂度 O(n log n)。超大规模下排序可能成为瓶颈可能需要分布式排序Lance 目前没有内置能力相关功能开发中如果条件允许随数据增长分部分训练索引可能比一次性全量训练更高效。缓存行为索引完全驻留缓存时搜索时间与命中查询的行数线性相关未完全驻留时搜索时间取决于需要从磁盘加载的页数与存储速度——parts_loaded指标会告诉你一次查询从磁盘加载了多少页。Bitmap 索引Bitmap 索引是倒排查找表为列中每个可能的值存一个 bitmap以 Roaring Bitmap 压缩序列化。训练先把列累积到「值 → 行 ID 向量」的哈希表中再把每个值序列化为 bitmap 写入文件。存储难以精确计算但大体随列中唯一值数量增长——每个值需要一个 bitmap而「一个大 bitmap 容纳所有行」的压缩效率远高于「多个只含少量行的小 bitmap」。内存训练期需要至少每行 8 字节唯一值很多时哈希表的键还要额外占用内存大规模高基数训练可能非常吃内存。搜索时 bitmap 按个加载进 session 缓存大小取决于命中的行数。性能完全驻留缓存时搜索时间与查询所需值的数量线性相关等值查询或极小范围查询非常快大范围查询目前极慢应改用 BTree。未完全驻留时parts_loaded指标可反映从磁盘加载了多少个 bitmap。向量索引IVF_PQ、IVF_HNSW_SQ 等向量索引分多阶段构建各阶段内存需求差异巨大。IVF 训练阶段IVF倒排文件阶段用 KMeans 将向量聚类到分区。训练前把数据集的一个样本载入内存样本大小由下式决定training_data num_partitions * sample_rate * dimension * sizeof(data_type)默认sample_rate为 256。例如 1024 个分区、768 维 float32 向量、默认采样率1024 * 256 * 768 * 4 bytes 768 MiB除训练数据外每次 KMeans 迭代还会分配与训练向量数成比例的成员关系与距离向量每向量 8 字节质心本身需num_partitions * dimension * sizeof(data_type)字节。实践中训练数据占主导这些额外分配相对很小。若数据集行数少于num_partitions * sample_rate则用整个数据集训练。量化器训练阶段IVF 训练后量化器PQ、SQ 等被训练来压缩向量。此阶段可能采样部分数据但采样量与量化器属性和向量维度相关而非数据集大小因此通常只占很少 RAM。Shuffling重排阶段最后阶段扫描整个向量列逐个转换向量分配 IVF 分区并量化把结果流式写入各分区的磁盘文件——不累积在内存中。输入扫描默认使用 2 GiB I/O 预读缓冲区可用LANCE_DEFAULT_IO_BUFFER_SIZE配置每次读取 8192 行 batch进入的 batch 并行转换同时在途 batch 数为num_cpus - 2可用LANCE_CPU_THREADS配置。每个 batch 按分区 ID 排序后各切片直接写入对应分区文件。此阶段在途内存约为io_readahead_buffer num_cpu_threads * batch_size * (raw_vector_size transformed_vector_size)每个分区有一个文件写入器约 8 MiB 累积缓冲区。实际上单个分区不会累积那么多数据最大累积量约等于分区最终大小即num_rows * (num_sub_vectors 8) bytes每行额外 8 字节存行 ID。例如 1 亿行、1536 维向量96 个子向量的最大累积约 10 GB。向量索引存储需求磁盘上向量索引 IVF 质心 量化向量。质心需num_partitions * dimension * sizeof(data_type)字节通常很小——1 万个分区、768 维 float32 仅 30 MiB。量化向量构成索引主体。每行存储一个量化码加 8 字节行 ID具体大小取决于量化器PQ乘积量化每个子向量量化成 1 字节每行需num_sub_vectors 8字节。例如 1 亿行、96 个子向量100M * (96 8) ~9.7 GiB。SQ标量量化每个维度独立量化成 1 字节每行需dimension 8字节。SQ 比 PQ 保留更多信息但更占空间。例如 1 亿行、768 维100M * (768 8) ~72.3 GiB。RQRaBitQ新索引默认每维 5 bit。每种位宽都存储 1 bit 符号码加三个 4 字节修正因子多位索引还以 64 维补齐的块存储剩余位并多两个 4 字节修正因子。计入 8 字节行 ID每行近似1-bitdimension / 8 20字节多位dimension / 8 round_up(dimension, 64) * (num_bits - 1) / 8 28字节。例如默认 5-bit、1 亿行、768 维100M * (768 / 8 768 * 4 / 8 28) ~47.3 GiB。5-bit 默认值保留更多信息支撑Normal与Accurate搜索模式的高保真距离估计代价是构建期更多的量化工作与索引 I/O、更大的索引体积。Fast搜索模式即使索引存了多位也只使用 1-bit 符号码。显式设置num_bits1可最小化索引体积与构建 I/O同样的 1 亿行示例约 10.8 GiB但搜索无法使用多位距离估计召回率可能下降。AMX 加速x86_64在 Linux x86_64 且 CPU 支持 AMX-FP16Intel Granite Rapids / Xeon 6 及更新时用dot距离索引的float16向量列会使用 AMX tile 指令——前提是构建机器的 clang 16 或 gcc 13 能编译该内核。无需手动启用Lance 运行时检查 CPU其他环境自动回退到原实现。加速路径还有形状门槛低于这些规模时 tile 一趟的开销大于收益内核会拒绝执行条件原因float16向量 dot距离内核为 fp16 专用其他类型与度量保持原路径dimension 32一次 tile 遍历覆盖 32 维更短向量会全部退化为标量清理num_centroids 32GEMM 按 32 步进质心循环无部分 tile 路径不满足条件的行为与现在完全一致小数据集或低维列沿用原实现。当上述条件全部满足时索引构建算法也会改变——逐个比较所有向量与所有质心变得可负担分区分配由「质心上做图搜索近似」变为精确分配召回率提升且分区分配结果与旧构建不同。设置LANCE_DISABLE_AMX1可在不重新编译的情况下关闭 AMX 路径——用于 A/B 测量或恢复旧行为。注意由于它同时把分区分配退回近似路径用它构建的索引与不用它构建的索引并不等价应比较召回率而不只是构建时间。总结从诊断到调优的实践路径将以上内容串成一条可执行的排障流程先观测设置LANCE_LOG/LANCE_TRACING通过lance::events::*追踪事件观察 throttle 抖动、索引页加载parts_loaded、计划执行开销iops、bytes_read判断瓶颈在存储限流、缓存未命中还是计算再调并发远程存储优先调整LANCE_IO_THREADS与fragment_readahead多进程共享机器时用LANCE_CPU_THREADS限制计算线程注意解码是计算密集型后控内存按2 * io_buffer_size batch_size * num_compute_threads估算扫描内存大行数据调小batch_size调大 IO 线程时同步调大io_buffer_size共享单表或单 session 让元数据缓存与索引缓存跨操作复用最后做架构取舍按数据规模设计 fragment 粒度默认 100 万行/fragment、上限 100 GB/fragment写密集场景用defer_index_remapTrue规避压缩与建索引的冲突并按查询模式在 BTree大范围/有序与 Bitmap等值/小范围之间选择同时按 PQ/SQ/RQ 的存储公式估算向量索引体积。每个参数背后的实现都可以在仓库中进一步追查日志初始化见 python/src/lib.rsAIMD 限流器见 rust/lance-io/src/object_store/throttle.rsFRI 见 rust/lance/src/dataset/index/frag_reuse.rs 与 FRI 规范扫描器参数见 rust/lance/src/dataset/scanner.rs。结合本文的公式与默认值你可以在任何数据规模下做出有理有据的调优决策。【免费下载链接】lanceOpen Lakehouse Format for Multimodal AI. Convert from Parquet in 2 lines of code for 100x faster random access, vector index, and data versioning. Compatible with Pandas, DuckDB, Polars, Pyarrow, and PyTorch with more integrations coming..项目地址: https://gitcode.com/GitHub_Trending/la/lance创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表