Elasticsearch Learning to Rank: storing features and models inside the index
Plugin to integrate Learning to Rank (aka machine learning for better relevance) with Elasticsearch
At a glance
- What is it?
- The o19s plugin turns Elasticsearch into a host for feature templates, logged feature scores and trained ranking models. It is a relevance engineering tool, not a general machine learning platform, and its version coupling to Elasticsearch is the first thing to check.
- Who is it for?
- Adopt it if your team already runs Elasticsearch, can pin the plugin release to your exact Elasticsearch version, and has judgments or click data to train on. Do not adopt it if you need a ranking model that runs outside the cluster or you cannot restart nodes.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 91 days ago.
- What is it written in?
- Mainly Java, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The relevance problem this plugin puts inside Elasticsearch
Default scoring in Elasticsearch is a fixed formula over term statistics. When two documents differ in ways that formula does not capture, you usually patch it with boosts and function scores, and the query string grows until nobody can explain why a document ranked where it did. The plugin takes a different route: it lets you define named features as query templates, store them in the cluster, and then rank with a model trained on those features instead of hand-tuned weights. The audience is search relevance engineers, the people who own ranking quality and already know their analyzers and query DSL. The README names Wikimedia Foundation and Snagajob as users, and credits contributions from Wikimedia, Snagajob, Bonsai and Yelp, which tells you the intended scale is a production search team, not a single developer experimenting. It is also not a replacement for your retrieval step. Features are built from Elasticsearch queries, so a document that the first pass never returns cannot be rescued by the model.
Feature templates, logging, and stored models
The README lists four capabilities. You store features, described as Elasticsearch query templates, in Elasticsearch itself. You log feature scores to build a training set for offline model development. You store ranking models, specifically linear, xgboost or ranklib models, in the cluster. And you rank search results with a stored model. The data flow that follows from that list is worth stating plainly because it explains the operational shape of the tool. A feature is a named query template with parameters, so the same template can be reused across queries. Feature logging runs those templates against live queries and records the scores, which gives you a matrix of document-by-feature values that you export and join with judgments. Training happens outside Elasticsearch, in whatever tooling you prefer for linear, xgboost or ranklib models. The resulting model is uploaded back into the cluster, and at query time the plugin evaluates the stored model over the feature scores computed for the current candidate set. The important consequence: the model is data in the index, so deploying a new ranking model is a model upload rather than a plugin rebuild or a node restart.
Installing the zip that matches your Elasticsearch version
Installation is an Elasticsearch plugin install against a prebuilt release zip. The README gives this example, with the instruction to substitute the version matching your Elasticsearch: `./bin/elasticsearch-plugin install https://github.com/o19s/elasticsearch-learning-to-rank/releases/download/v1.5.4-es7.11.2/ltr-plugin-v1.5.4-es7.11.2.zip`. It notes that you should expect to confirm security exceptions, and that passing `-b` to `elasticsearch-plugin` installs without that prompt. If Elasticsearch is already running, the README says to restart it. The version string in the artifact name, `v1.5.4-es7.11.2`, is the contract: plugin version first, Elasticsearch version second. The release list follows the same pattern, with v1.5.13 built for es9.3.5, es9.3.2 and es9.2.4. If no zip exists for your version, the README points to building locally with `./gradlew clean check` and installing the resulting `build/distributions/ltr-<LTR-VER>-es<ES-VER>.zip` via a `file:///` URL. The README also states the project's support policy: it aims at `*.*.1` releases of Elasticsearch, and asks for a PR if you need dot-oh compatibility or an unsupported version. That policy is the practical constraint on upgrade cadence.
The version treadmill is the real cost of ownership
Because the plugin is loaded into the Elasticsearch process, it is tied to the Elasticsearch version it was built against. The release history shows the maintenance pattern: three releases in the v1.5.13 line, each named for a different Elasticsearch version, within roughly four months. That is a good sign for currency and a bad sign for anyone who upgrades Elasticsearch on a schedule the plugin does not follow. If your cluster runs a version with no prebuilt zip, your options are to build it yourself or file a request, and building means a Gradle toolchain that matches the target Elasticsearch. The README's own note about `*.*.1` support is the clearest statement of this boundary. There is also a known issues file in the repository, and the README directs readers to it for current issues and possible workarounds. Since that file is not reproduced here, treat it as required reading before you install rather than something to skim afterwards. The licence is Apache-2.0, which permits commercial use and modification, but the README does not state any support commitment, so paid support is not something the material promises. For legal questions about redistribution or modification, consult your own counsel.
When a model inside the cluster is the wrong shape
The plugin assumes your ranking signal can be expressed as Elasticsearch query templates. If your best features come from a separate system, such as user history stored outside Elasticsearch, a vector index, or a gradient boosted model that needs feature values the cluster cannot compute, you will spend your time plumbing rather than ranking. The logging path has the same assumption: it records scores from the templates you defined, so a feature you never templated never appears in the training set. There is also a candidate-set ceiling. Because features are Elasticsearch queries, the model reorders documents the query already matched. If your recall is poor, learning to rank will not fix it, and no amount of model tuning will surface a document that was never retrieved. Teams that need to blend signals from several systems, or that want to iterate on ranking without touching cluster configuration, will find the in-cluster model storage to be the constraint rather than the feature.
How this differs from reranking outside Elasticsearch
The obvious alternative is to retrieve with Elasticsearch and rerank in a service you control, using a model server that returns scores for a candidate list. The difference is where the features and the model live. With an external reranker, feature computation and model evaluation happen in your process, so you can pull values from any source and deploy a model without touching the cluster. With this plugin, features are query templates stored in Elasticsearch and models are stored in Elasticsearch, so evaluation happens inside the search process and the model is versioned alongside the index data. That buys you one round trip instead of two and removes a network hop from the ranking path, at the cost of coupling your ranking pipeline to the Elasticsearch release cycle. The README also points to Bloomberg's Learning to Rank work for Solr, which is the equivalent effort on a different engine; if your stack is Solr rather than Elasticsearch, that is the direction to look, and the Hello LTR repository the README mentions covers both engines with example notebooks.
Who should adopt it, and what to check first
This is a tool for teams with a working Elasticsearch deployment, a relevance problem that hand-tuned boosts have stopped solving, and a source of training data, whether judgments or logged clicks. It fits best when you can pin the plugin release to your Elasticsearch version and accept that the two move together. It fits badly if you cannot restart nodes, if your ranking features come from outside the cluster, or if your Elasticsearch version has no prebuilt zip and nobody on the team wants to own a Gradle build. Before installing, check the releases page for a zip whose `es` suffix matches your Elasticsearch exactly, and read KNOWN_ISSUES.md in the repository. The README's demo now lives in the separate Hello LTR repository, with an Elasticsearch notebook under `notebooks/elasticsearch/tmdb/`, so you can follow the end-to-end feature, log, train and rank cycle there before committing to the plugin in production.
Editorial conclusion
Adopt it if your team already runs Elasticsearch, can pin the plugin release to your exact Elasticsearch version, and has judgments or click data to train on. Do not adopt it if you need a ranking model that runs outside the cluster or you cannot restart nodes. Verify first that a prebuilt zip exists for your Elasticsearch version on the releases page, and read KNOWN_ISSUES.md before installing.
Community notes