Minimum configuration, Maximum ingest
You have an Elasticsearch cluster. Have you ever...
- had to write your own custom client, just to ingest your documents?
- wanted to load a
.csvfiles over 100MB into Elasticsearch? - needed a quick way to re-load the same
.ndjsonacross environments? - wished for an easy way to convert and index thousands of
.docx,.pdfor other documents?
Your answer is espipe. Easily stream documents from files or standard input into Elasticsearch. With on-the-fly document-to-markdown conversion now powered by anydoc.
No authentication? Just run:
espipe docs.ndjson http://localhost:9200/new_indexAnd you're done. Yes, it is that simple!
Install with homebrew:
brew install VimCommando/tools/espipeRun the published container image:
docker run --rm vimcommando/espipe --helpInstall the published release with Cargo (compliles from source):
cargo install espipeClone repo and build latest main branch:
git clone https://github.com/VimCommando/espipe
cargo install --path espipe/espipe reads records from:
- NDJSON, JSON, and CSV files, with gzip support for NDJSON and CSV
- JSON arrays or objects selected by
--split - local Markdown, text, YAML, JSONL, and Toon files
- local PDF, Word, PowerPoint, Excel, OpenDocument, RTF, and EPUB files
- local file lists and recursive subdirectory globs
- NDJSON from standard input
It writes records to:
- Elasticsearch
_bulk - a local
.ndjsonor.ndjson.gzfile - standard output
The only required configuration (if you have security on your cluster) is authentication. Use the URI scheme to specify what authentication to use.
If you're using the Elastic CLI? Use any .elasticrc.yml in a dot-context format .context.service::
# current context, just use `.es` or `.elasticsearch`
espipe docs.ndjson .elasticsearch:/new_index
# `.es` service for the 'prod' context
espipe docs.ndjson .prod.es:/new_indexJust define environment variables (or a .env file), and use the env: scheme
ELASTIC_ES_URL=http://localhost:9200 \
ELASTIC_ES_API_KEY=1234ABCD.... \
espipe docs.ndjson env:/new_indexDefine my-cluster in the ~/.espipe/hosts.yml file:
espipe docs.ndjson my-cluster:/new_indexSee more in the authentication docs.
espipe [OPTIONS] <INPUT>... <OUTPUT>The main option groups are:
- input:
--content,--split - local discovery:
--generate-id,--symlinks,--hidden - Elasticsearch writes:
--action,--batch-size,--max-requests,--uncompressed - cluster setup:
--apikey,--username,--password,--insecure,--pipeline,--template
Run espipe --help for all flags and accepted values.
Pass one or more inputs followed by one output. Local paths can also use file:// URIs; the same format rules apply to both forms.
-- Reads JSON lines fromstdin.dir/file.ext- Reads a supported local data file.dir/file.ext.gz- Stream data from supported compressed files.'dir/**/*.ext'Recursively finds and converts each one to a file document.https://host.co/file.json- Reads from a remote file or endpoint (supportsContent-Typeor file extension)
See more in the input docs.
-- Writes JSON lines tostdout.dir/file.ndjson- Writes JSON lines to a local file.dir/output.ndjson.gz- Writes gzip-compressed JSON lines to a local file.https://host:9200/index-name- Sends documents to Elasticsearch using the_bulkAPI.known-host:/index-name- Resolvesknown-hostfrom a local hosts file and sends to the named index.env:/index-name- Writes to the cluster URL and API key from environment variables or.envfile..es:/index-name- Writes to the Elasticsearch service from the current Elastic CLI context..context.es:/index-name- Writes to the Elasticsearch service from the named Elastic CLI context.
When writing to Elasticsearch, the output path must include an index name.
See more in the output docs.
espipe docs.ndjson http://localhost:9200/my-indexespipe games.json http://localhost:9200/games --split /
espipe response.json output.ndjson --split /hits/cat docs.ndjson | espipe - http://localhost:9200/my-indexProgressively load an .ndjson, line-by-line as its written, piped from tail -f, to the current Elastic CLI context:
tail -n 0 -f docs.ndjson | espipe --batch-size 1 - .es:/new_indexespipe '**/*.pdf' http://localhost:9200/documents
espipe '**/*.pdf' '**/*.docx' '**/*.xlsx' output.ndjsonespipe users.csv.gz output.ndjson.gz
espipe docs.ndjson.gz http://localhost:9200/my-indexespipe docs.ndjson https://example.com:9200/my-index \
--username elastic \
--password changeme
espipe docs.ndjson https://example.com:9200/my-index \
--apikey "base64-encoded-api-key"espipe docs.ndjson http://localhost:9200/my-index \
--batch-size 1000 \
--max-requests 4Input:
{"_id":"1","message":"hello"}
{"_id":"2","message":"world"}
Command:
espipe docs.ndjson http://localhost:9200/my-index --action updateespipe writes diagnostics to standard error:
- invalid CLI argument combinations are rejected by
clap - invalid authentication combinations fail at startup
- invalid input or output targets fail at startup
- Elasticsearch transport failures during send or close terminate the process
429bulk responses are retried automatically- bulk item failures are logged, but successful items in the same batch are still counted
Malformed NDJSON or CSV may stop ingestion without a dedicated non-zero parsing exit code because parsing errors and end-of-input share the same loop boundary.
Multi-source conversion uses up to eight workers, bounded by available parallelism and source count. Results are emitted as conversions finish, so one slow file does not hold back the rest. Bulk requests run concurrently and can saturate a local or small remote cluster; lower --batch-size or --max-requests when needed.
Set LOG_LEVEL to inspect request and ingestion behavior:
LOG_LEVEL=debug espipe docs.ndjson http://localhost:9200/my-indexUseful checks:
- verify the target index name is present in the output URI
- verify CSV files have a header row
- verify NDJSON files contain one complete JSON object per line
- verify update/upsert inputs include string
_idvalues or have generated IDs enabled for eligible local file documents - verify known-host entries live in
~/.espipe/hosts.ymlor$ESPIPE_HOSTS - verify context outputs use
.es:/indexor.context.es:/index, and that the selected context defines an Elasticsearch service - verify
ELASTIC_CLI_CONFIG_FILEpoints to a readable JSON or YAML Elastic CLI config when overriding home discovery