Is your feature request related to a problem? Please describe
OpenSearch's pull-based ingestion framework currently supports streaming sources (Kafka, Kinesis) and non-streaming/batch sources (Hive, object-store source plugin in #22556). However, most existing plugins require data to arrive as pre-formatted OpenSearch update messages, or support only a narrow set of file formats (e.g., Parquet). There is no native support for Apache Arrow, a popular columnar in-memory interchange format used across a lot of modern data ecosystems.
This RFC proposes adding Arrow as a supported ingestion format to unlock a wide range of data sources that already speak Arrow natively, including Lance, Parquet (which is already supported), Iceberg, Delta Lake etc.
Describe the solution you'd like
The solution consists of an IngestionConsumerPlugin implementation and a common interface for providing the source:
ArrowPlugin (IngestionConsumerPlugin): Registers ingestion type "ARROW" with OpenSearch's pull-based ingestion engine. It provides an ArrowConsumerFactory that creates per-shard consumers (ArrowShardConsumer). Each shard consumer:
- Accepts an
ArrowReader (the standard Apache Arrow Java interface for reading columnar record batches) from a DatasetSource
- Iterates over
VectorSchemaRoot batches, converting each row into an OpenSearch index operation (_id, _version, _op_type, _source)
- Handles mapping from Arrow types to opensearch index update message
- Performs shard routing
ArrowSource (extensible interface): Abstracts the data access layer. which essentially creates the ArrowReader and provide required informations such as ingestion lag information which only the source can provide.
This separation is deliberate. The Arrow conversion logic (format handling, type mapping, shard routing) is general-purpose and common across all sources. The data access layer, however, often involves organization-specific concerns: credential management, proprietary storage systems, custom authentication flows, or internal service discovery. By defining ArrowSource as a clean interface, organizations can implement private ArrowSource classes for their specific backends without forking the core plugin.
Related component
Indexing
Describe alternatives you've considered
In our case the source is Lance, so we have two options beyond the proposed plugin:
- Do an offline index build through Spark and port the index into Opensearch by using snapshot recovery. But the later part of this approach is a bit hacky and AFAIK opensearch does not have a good support for build index outside of cluster.
- External data pipeline feeding OpenSearch update API.** Instead of reading data from within the cluster, an external service (e.g., a Spark job, an Airflow DAG, or a custom microservice) could read the Arrow data source, convert rows to bulk index requests, and send them to OpenSearch's
_bulk API over HTTP. This is functionally equivalent to the proposed plugin but runs outside the cluster.
I think all 3 approaches (including the proposed plugin) provides different advantages in different cases, but eventually it is better to have options to be able to directly read from a arrow-compatible sources and build index within the cluster.
Additional context
No response
Is your feature request related to a problem? Please describe
OpenSearch's pull-based ingestion framework currently supports streaming sources (Kafka, Kinesis) and non-streaming/batch sources (Hive, object-store source plugin in #22556). However, most existing plugins require data to arrive as pre-formatted OpenSearch update messages, or support only a narrow set of file formats (e.g., Parquet). There is no native support for Apache Arrow, a popular columnar in-memory interchange format used across a lot of modern data ecosystems.
This RFC proposes adding Arrow as a supported ingestion format to unlock a wide range of data sources that already speak Arrow natively, including Lance, Parquet (which is already supported), Iceberg, Delta Lake etc.
Describe the solution you'd like
The solution consists of an IngestionConsumerPlugin implementation and a common interface for providing the source:
ArrowPlugin (
IngestionConsumerPlugin): Registers ingestion type"ARROW"with OpenSearch's pull-based ingestion engine. It provides anArrowConsumerFactorythat creates per-shard consumers (ArrowShardConsumer). Each shard consumer:ArrowReader(the standard Apache Arrow Java interface for reading columnar record batches) from aDatasetSourceVectorSchemaRootbatches, converting each row into an OpenSearch index operation (_id,_version,_op_type,_source)ArrowSource (extensible interface): Abstracts the data access layer. which essentially creates the
ArrowReaderand provide required informations such as ingestion lag information which only the source can provide.This separation is deliberate. The Arrow conversion logic (format handling, type mapping, shard routing) is general-purpose and common across all sources. The data access layer, however, often involves organization-specific concerns: credential management, proprietary storage systems, custom authentication flows, or internal service discovery. By defining
ArrowSourceas a clean interface, organizations can implement privateArrowSourceclasses for their specific backends without forking the core plugin.Related component
Indexing
Describe alternatives you've considered
In our case the source is Lance, so we have two options beyond the proposed plugin:
_bulkAPI over HTTP. This is functionally equivalent to the proposed plugin but runs outside the cluster.I think all 3 approaches (including the proposed plugin) provides different advantages in different cases, but eventually it is better to have options to be able to directly read from a arrow-compatible sources and build index within the cluster.
Additional context
No response