Skip to content

feat: Add Apache Lance as a new accepted sink format #249

Description

@malon64

Summary

Add Apache Lance as a new accepted sink format alongside delta, iceberg, and parquet.

Motivation

Lance is a modern columnar format designed for ML and analytical workloads, built Arrow-first from the ground up. It features versioned datasets (snapshots), native vector index support, and compatibility with S3/GCS/ADLS — making it a relevant target for data platforms that feed ML pipelines or vector search engines.

Technical Feasibility

The lance Rust crate is production-ready and integrates naturally with the existing Floe stack:

  • Arrow-native: Dataset::write() accepts RecordBatch directly — the existing Arrow conversion layer in Floe is immediately reusable.
  • Versioned snapshots: Lance has a snapshot model similar to Iceberg, meaning Append and Overwrite semantics map cleanly.
  • Cloud storage: Native support for S3, GCS, and ADLS via object_store — consistent with Floe's Target enum.
  • No Target enum changes needed: Lance datasets are directory-based (like Delta), so SinkTarget.path maps directly.

Integration complexity is low — the pattern mirrors the existing Iceberg adapter.

Proposed Implementation

1. New adapter

Create crates/floe-core/src/io/write/lance.rs implementing AcceptedSinkAdapter:

use lance::dataset::{Dataset, WriteMode, WriteParams};

struct LanceAcceptedAdapter;

impl AcceptedSinkAdapter for LanceAcceptedAdapter {
    fn write_accepted(&self, target, df, mode, ...) -> FloeResult<AcceptedWriteOutput> {
        let batch = dataframe_to_record_batch(df)?;
        let params = WriteParams {
            mode: match mode {
                WriteMode::Append => lance::dataset::WriteMode::Append,
                WriteMode::Overwrite => lance::dataset::WriteMode::Overwrite,
                _ => return Err(...),
            },
            ..Default::default()
        };
        Dataset::write(stream_of(batch), &uri, Some(params)).await?;
    }
}

2. Dispatch registration

// io/format.rs
"lance" => Ok(io::write::lance::lance_accepted_adapter()),

3. User config

sink:
  accepted:
    format: lance
    path: s3://my-bucket/warehouse/my_dataset.lance

Write Modes

Mode Support
append ✅ Native (WriteMode::Append)
overwrite ✅ Native (WriteMode::Overwrite)
merge_scd1 ❌ Out of scope (no row-level update API yet)
merge_scd2 ❌ Out of scope

Out of Scope (for now)

  • Vector index creation post-write
  • SCD merge operations
  • Lance compaction / dataset optimization hooks

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions