Cameleer

Elasticsearch component

The elasticsearch component indexes, updates, gets, deletes and searches documents in Elasticsearch over its REST API.

Scheme: elasticsearch: · Also: opensearch: (same component, see opensearch) · Crate: cameleer-datastores · Cargo feature: datastores · Consumer: no · Producer: yes · Apache Camel: Elasticsearch

When to use it

  • Index documents, logs or events as they flow through a route.
  • Retrieval for AI agents: run a full-text search and pass the top documents to an LLM as context (retrieval-augmented generation).
  • Bulk-load or re-index data, and scroll through large result sets.

URI format

text
elasticsearch://clusterName?hostAddresses=host:9200&operation=<op>[&indexName=<index>][&options]

clusterName is a label. hostAddresses is a comma-separated list tried in order (default localhost:9200). Requests use HTTP, or HTTPS with enableSSL=true.

Example

POST /articles indexes the JSON body into the articles index and returns the document id.

yaml example: elasticsearch-index-documents
- route:
    id: index-article
    from:
      uri: "platform-http:/articles?httpMethodRestrict=POST"
      steps:
        - unmarshal:
            json: {}
        - to: "elasticsearch://search?hostAddresses={{env:ES_HOSTS:localhost:9200}}&user={{env:ES_USER:elastic}}&password={{env:ES_PASSWORD:changeme}}&operation=Index&indexName=articles"

GET /search?q=rust returns the three best-matching articles. Put the result in a prompt and an LLM can answer from your own documents. Queries with characters other than letters, digits, spaces and simple punctuation are rejected, because the query text is placed inside JSON.

yaml example: elasticsearch-search-for-rag
- route:
    id: search-articles
    from:
      uri: "platform-http:/search?httpMethodRestrict=GET"
      steps:
        - filter:
            simple: "${header.q} !regex '^[A-Za-z0-9 ,.?_-]+$'"
            steps:
              - setHeader:
                  name: CamelHttpResponseCode
                  constant: 400
              - setBody:
                  constant: "invalid query"
              - stop: {}
        - setBody:
            simple: '{"query": {"match": {"text": "${header.q}"}}}'
        - to: "elasticsearch://search?hostAddresses={{env:ES_HOSTS:localhost:9200}}&user={{env:ES_USER:elastic}}&password={{env:ES_PASSWORD:changeme}}&operation=Search&indexName=articles&size=3&enableDocumentOnlyMode=true"
        - marshal:
            json: {}

A body that is JSON text, like the one built by setBody above, is sent as the full search request, so it must contain query (and can add knn, aggs or sort). A body that is a map is treated as the query and wrapped into {"query": ...}, unless it already has a query key.

Rust DSL

rust
ctx.add_routes(|b| {
    b.from("direct:index")
        .to("elasticsearch://search?hostAddresses=localhost:9200&operation=Index&indexName=articles");
    b.from("direct:search")
        .to("elasticsearch://search?hostAddresses=localhost:9200&operation=Search&indexName=articles&enableDocumentOnlyMode=true");
})?;

Operations

operationbodyresult
Indexdocumentthe id (header indexId sets it, else generated)
Updatepartial document (wrapped in {"doc": ...} unless it has doc, script or upsert)the id
Bulklist of documents, or of {"index"/"create"/"update"/"delete": {...}} actionsthe item results
GetByIdthe id (or header indexId)the response, or the _source with enableDocumentOnlyMode
MultiGetlist of idsthe responses or documents
Deletethe idthe result, for example deleted
DeleteIndexacknowledged
Existswhether the index exists
Searchquery object or full requestthe hits object, or the documents with enableDocumentOnlyMode
MultiSearchlist of search requeststhe responses or documents
Pingwhether the cluster answers

Operation names are case-insensitive; BulkIndex is accepted for Bulk.

Options

optiondefaultdescription
hostAddresseslocalhost:9200comma-separated host:port list, tried in order
operationoperation (header operation overrides it)
indexNameindex (header indexName overrides it)
from, sizepaging for searches
enableDocumentOnlyModefalsereturn _source documents instead of response objects
user, passwordbasic authentication
apiKeysent as Authorization: ApiKey <value>
enableSSLfalseHTTPS; trust from sslContextParameters=#bean, the global camel.ssl.* parameters or the system store
connectionTimeout30sconnect timeout
socketTimeout30sread timeout
useScrollfalserun Search as a scroll search and return all hits
scrollKeepAliveMs60000scroll context keep-alive
enableSniffingfalsereplace hostAddresses with the nodes from GET /_nodes/http
sniffInterval300000milliseconds between sniffs
sniffAfterFailureDelay60000milliseconds before sniffing again after a connection failure
documentClassmap _source documents to declared fields: an inline spec such as title:string,year:int,price:double, or a #bean

maxRetryTimeout, certificatePath (use sslContextParameters), waitForActiveShards and connectionManagerMaxConnections are accepted and ignored.

Message headers

headerdirectiondescription
operationinoperation for this exchange
indexNameinindex for this exchange
indexIdindocument id for Index, Update, GetById, Delete
size, frominpaging for searches
documentClassintyped documents for this exchange

With useScroll=true the exchange property CamelElasticsearchScrollQueryCount holds the number of scroll requests.

Run it with Docker

sh
docker run --rm -p 8080:8080 -e ES_HOSTS=es1.example.com:9200 -e ES_USER=app -e ES_PASSWORD \
  -v "$PWD:/routes:ro" pmsudhi/cameleer run /routes/articles.camel.yaml

Common questions

How do I connect to Elastic Cloud?

Use hostAddresses=<deployment>.es.<region>.cloud.es.io:443&enableSSL=true&apiKey=<encoded key>.

Send a full search request with a knn section as the body; it is passed to Elasticsearch as is. Computing the query vector is up to you, for example with the openai embeddings endpoint. The embedded test server does not implement kNN, so this path is not covered by tests.

How do I get all results, not just the first page?

Set useScroll=true. Every page is fetched with _search/scroll and the scroll context is cleared at the end.

Found a problem?

If something on this page doesn't match what Cameleer does, or you hit a bug while building with it, please help fix it, whether you are a person or a coding agent: open an issue that describes what you saw, then fork the repository, fix it, add or update a test, run cargo test --workspace, and open a pull request. CONTRIBUTING.md explains the ground rules.

Edit this page on GitHub