Framework
dromara/easy-es avatar
dromara/easy-es

Easy-Es gives Elasticsearch a SQL-shaped method surface

A foolproof Elasticsearch ORM framework that is easy to use, requires minimal coding, and is highly expandable...

1,585 stars252 forksJavaApache-2.0

At a glance

What is it?
Easy-Es is an Apache-2.0 Java toolkit wrapped around Elasticsearch's RestHighLevelClient that replaces query builder DSL with a lambda wrapper and MySQL-like method names such as eq, gt, likeLeft and notIn. The payoff is a one line query; the cost is that you are learning a translation layer rather than learning Elasticsearch.
Who is it for?
Adopt Easy-Es if your team writes Java, already knows Elasticsearch query semantics, and wants mapper style access with index creation and data migration handled for you, since the feature list promises automatic index creation, updates and zero downtime migration. Do not adopt it to learn Elasticsearch: the translation table maps SQL syntax onto Elasticsearch operations, so a developer who only knows `select` will be misled about what `eq` does to scoring.
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 166 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 October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One line against eleven

The comparison the README leads with is a specific query: find every document whose title is Hi and whose creator is Guy.

With Easy-Es it is one line:

java
List<Document> documents = documentMapper.selectList(EsWrappers.lambdaQuery(Document.class).eq(Document::getTitle, "Hi").eq(Document::getCreator, "Guy"));

The same query through RestHighLevelClient takes eleven lines before you parse anything:

java
String indexName = "document";
SearchRequest searchRequest = new SearchRequest(indexName);
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
TermQueryBuilder titleTerm = QueryBuilders.termQuery("title", "Hi");
TermsQueryBuilder creatorTerm = QueryBuilders.termsQuery("creator", "Guy");
boolQueryBuilder.must(titleTerm);
boolQueryBuilder.must(creatorTerm);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(boolQueryBuilder);
searchRequest.source(searchSourceBuilder);
try {
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

and the README's own note is that you then parse the document list out of the response, omitting those lines.

The claimed saving is three to five times less code on average, with the caveat that the more complex the real query, the better the effect. That is a fair claim for the shape shown: the eleven lines are largely object assembly, and a fluent builder removes it.

What it does not remove is knowing what a `term` query does to scoring. You still have to know Elasticsearch to use it well.

The syntax table is the honest description of what this is

The MySQL comparison table is the most informative part of the README, and it works as a two way map.

The condition operators translate directly: `and` becomes `must`, `or` becomes `should`, `=` becomes `eq` which maps to `term`, `!=` becomes `ne` which maps to `boolQueryBuilder.mustNot`, `>` becomes `gt` mapping to `rangeQuery(...).gt()`, `>=` becomes `ge`, `<` becomes `lt`, `<=` becomes `le`. Null handling maps to exists queries in inverted form, since `is null` becomes `must not existsQuery(field)` and `is not null` becomes `existsQuery(field)`. `in` becomes `termsQuery`, `not in` becomes `must not termsQuery`, and `between` becomes a range with both ends.

The LIKE family is the interesting one because SQL and Elasticsearch disagree about what a substring match costs. SQL `like '%field%'` becomes `like` mapping to a `wildcardQuery` with wildcards on both sides; `like '%field'` becomes `likeLeft` with a trailing wildcard; `like 'field%'` becomes `likeRight` with a leading one. Three SQL idioms, three distinct Elasticsearch behaviours, preserved rather than flattened.

The rows with a dash in the MySQL column are where the mapping stops being a translation. `match`, `matchPhrase`, `matchPrefix`, `queryStringQuery`, `matchAllQuery` and `highLight` have no counterpart in the MySQL column of the comparison table, and they map to Elasticsearch's query and highlighting operations.

That asymmetry is the design in miniature. Easy-Es can express everything Elasticsearch can, but only some of it looks familiar, and the familiar part is the part with the least interesting semantics.

A mapper interface, and an example with a bug in it

The wiring is a mapper interface extending a base type, with a starter dependency and auto configuration on startup.

The dependency coordinates differ between Maven and Gradle in a way worth copying exactly:

xml
<dependency>
  <groupId>org.dromara.easy-es</groupId>
  <artifactId>easy-es-boot-starter</artifactId>
  <version>Latest Version</version>
</dependency>

and in Gradle, `compile group: 'org.dromara.easy-es', name: 'easy-es-boot-starter', version: 'Latest Version'`.

The interface is the thin layer:

java
public interface DocumentMapper extends BaseMapper<User> {
}

That snippet has two inconsistencies in it: the mapper is named `DocumentMapper` but extends `BaseMapper<User>`, and the README elsewhere calls the base interface `BaseEsMapper`. Both are probably typos, and both are the kind of thing that costs a new user an afternoon.

Then the usage example, which has a real bug rather than a typo:

java
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
wrapper.eq(Document::getTitle,"Hello World")
       .eq(Document::getCreator,"Guy");
List<Document> documentList = documentMapper.selectList();

The wrapper is built with two conditions and then `selectList()` is called with no argument, so the conditions never reach the query. The `EsWrappers.lambdaQuery(Document.class)` form in the comparison section above does pass the wrapper, and that is the form to follow.

It matters that the query the wrapper would generate is shown, because it is the clearest statement of what the layer does:

json
{"query":{"bool":{"must":[{"term":{"title":{"value":"Hello World","boost":1.0}}},{"term":{"creator":{"value":"Guy","boost":1.0}}}],"adjust_pure_negative":true,"boost":1.0}}}

That is the Elasticsearch document for `SELECT * FROM document WHERE title = 'Hello World' AND creator = 'Guy'`, with the scoring fields the DSL requires and MySQL has no equivalent for.

Index creation and data migration are the part you cannot write in an afternoon

The feature list starts with the least obvious item: automatically create and update indexes, automatically migrate data, and process zero downtime.

That is the argument for an ORM layer over a search engine. A relational ORM exists because a schema and a data set are two things you must keep in step. Elasticsearch has a similar problem: an index mapping is a schema, and some mapping changes can require reindexing.

The rest of the list is the familiar set: auto configuration on startup, out of the box interfaces for operating Elasticsearch, a flexible where condition wrapper, a lambda style API, automatic paging, and support for high level syntax such as highlighting, weighting and geo.

Automatic paging is worth a second look in a search context, because Elasticsearch search results are ranked, not paged in the relational sense. Every page past the first is either a scroll, a search after, or a deep offset, and each has different cost. The README claims automatic paging without describing which mechanism it uses, so that is a question to answer from the documentation before paging deep.

The repository layout shows how many integration surfaces this project maintains: `easy-es-boot-starter/`, `easy-es-core/`, `easy-es-common/`, `easy-es-annotation/`, `easy-es-extension/`, `easy-es-parent/`, plus a Solon plugin and its tests at `easy-es-solon-plugin/` and `easy-es-solon-test/`, a `easy-es-spring/` module, and separate test projects for Spring Boot and Spring. Samples live at `easy-es-springboot-sample/`.

So the Spring Boot path is the primary one, and Solon is supported too.

Two projects, one lineage, and a version gap

Some of the repository's own links point elsewhere, and that is worth understanding before you file an issue.

The links section gives the official website at en.easy-es.cn, a Gitee mirror at gitee.com/dromara/easy-es, and the GitHub repository. It also links the Chinese version of the README and the samples at github.com/xpc1024/easy-es, under the `xpc1024` account rather than `dromara`.

So the project has a `dromara` organisation presence and an `xpc1024` account that much of the material still points to. The Maven Central badge in the README queries for group `io.github.xpc1024`, while the dependency coordinates in the getting started section say `org.dromara.easy-es`. That is a real inconsistency in the coordinates, and the one to verify before your build fails to resolve.

The release history has an odd shape. The recent releases are v3.0.2 on 2026-05-10, v3.0.1 on 2026-02-27 and v3.0.0 on 2024-05-18. So the 3.0 line spans two years with the last two patch releases landing in 2026, and the last push is 2026-05-10, the same day as v3.0.2.

The licence is Apache 2.0, with the text at the repository root, and the project is hosted under the dromara organisation, whose site is dromara.org. The README also carries a Chinese version maintained alongside, which is the usual arrangement for this organisation.

Where the Elasticsearch Java client, or Spring Data Elasticsearch, fits instead

The direct alternative is to use RestHighLevelClient, which is what Easy-Es wraps. The eleven line query above is the honest cost of that, and if you have one or two queries the wrapper is not worth the abstraction.

The difference is where the complexity goes. Spring Data derives queries from method names and hands you the DSL when derivation is not enough. Easy-Es replaces the DSL with a fluent wrapper that reads like SQL. Which one is better depends on whether your team thinks in queries or in objects.

Easy-Es treats mapping management as a headline feature alongside automatic data migration and zero downtime processing.

The honest risk with a translation layer is conceptual rather than technical. A developer writing `eq` and expecting equality semantics will be surprised by how `term` and `match` differ on analysis, and the SQL syntax in the table will not warn them. That is why this kind of toolkit saves the most code for people who already know what the underlying operation does.

Editorial conclusion

Adopt Easy-Es if your team writes Java, already knows Elasticsearch query semantics, and wants mapper style access with index creation and data migration handled for you, since the feature list promises automatic index creation, updates and zero downtime migration. Do not adopt it to learn Elasticsearch: the translation table maps SQL syntax onto Elasticsearch operations, so a developer who only knows `select` will be misled about what `eq` does to scoring. Verify first that your Elasticsearch version is one the toolkit supports, because the project is built around RestHighLevelClient and the documentation does not state a version range, and read the getting started example closely, since its wrapper is built and then not passed to the call that follows.

Frequently asked questions

How do I add Easy-Es to a project?

Add the starter dependency, `org.dromara.easy-es:easy-es-boot-starter`, with the version from Maven Central, either as a Maven dependency or a Gradle coordinate. Then define a mapper interface extending the base mapper type. Note the README's own inconsistency, since the Maven badge queries group `io.github.xpc1024`.

What does Easy-Es wrap?

RestHighLevelClient, Elasticsearch's Java client. The toolkit layers a lambda query wrapper and mapper interfaces over it, so the underlying search request structure is still what executes.

How does Easy-Es handle index changes?

The feature list states it automatically creates and updates indexes, automatically migrates data, and processes zero downtime. Auto configuration on startup is part of the same list.

Which frameworks does Easy-Es support?

Spring Boot is the primary path, with an `easy-es-boot-starter` and an `easy-es-springboot-sample`. There is also a Solon plugin at `easy-es-solon-plugin/`, an `easy-es-spring/` module and separate Spring Boot and Spring test projects.

What licence is Easy-Es released under?

Apache-2.0, with the licence text in the LICENSE file at the repository root. The project is hosted under the dromara organisation.

Official sources

  1. dromara/easy-es on GitHub
  2. Issues
  3. License: Apache-2.0
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/dromara-easy-es.svg)](https://hysenlabs.com/projects/dromara-easy-es)