Release Overview
This release marks a significant collaboration between INFINI Labs and the Dromara open source community. The Easy-Es framwork now supports Easysearch, a domestically-developed search engine, representing a major step forward in the localization of search technology infrastructure.
Key resources:
- Source Repository: https://gitee.com/dromara/easy-es/tree/easy-es4easySearch/
- Maven Dependency: https://mvnrepository.com/artifact/org.dromara.easy-es/easy-es-boot-starter/2.1.0-easysearch
Why Integrate with Easysearch?
As organizations increasingly prioritize domestically-controlled technology solutions, the demand for compliant infrastructure has grown substantially. Easysearch provides compelling advantages:
- Full Domestic Ownership: Completely self-developed with no licensing concerns, meeting national procurement requirements
- Minimal Resource Footprint: Lower memory and CPU usage compared to traditional engines, with faster startup times
- Impressive Performance: Optimized query execution suitable for most production workloads
- Elasticsearch Compatibility: Near-complete API compatibility enables straightforward migrations with minimal friction
Framework Features
Easy-Es delivers substantial improvements in developer productivity:
- Reduced Boilerplate: Typical operations require 50-80% less code than native client calls.
// Query execution with minimal configuration
List<Document> docs = documentMapper.selectList(
EsWrappers.lambdaQuery(Document.class).eq(Document::getTitle, "example")
);
- Automated Index Management: The framework handles index lifecycle operations including creation, updates, and data migration with zero downtime.
- SQL Compatibility: Familiar SQL patterns work for search queries—supporting and, or, like, in operators.
- Type-Safe Field Access: Lambda expressions prevent field name typos and enhance IDE support.
- Spring Boot Integration: Auto-configuration and actuator endpoints integrate seamlessly with standard Spring Boot applications.
- Advanced Query Support: Nested queries, aggregations, range filters, and highlighting are all supported through a cleen API.
- Cluster-Ready: Built-in support for distributed deployments with high availability and horizontal scaling.
- Production-Validated: Extensive real-world usage across Chinese enterprises with active community support.
Getting Started
Dependency Configuration
Maven Projects
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<spring-boot.version>2.7.0</spring-boot.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.dromara.easy-es</groupId>
<artifactId>easy-es-boot-starter</artifactId>
<version>2.1.0-easysearch</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Gradle Projects
plugins {
id 'java'
id 'org.springframework.boot' version '2.7.0'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
}
group = 'com.example'
version = '1.0.0'
sourceCompatibility = '11'
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
implementation 'org.dromara.easy-es:easy-es-boot-starter:2.1.0-easysearch'
implementation 'org.springframework.boot:spring-boot-starter-web'
}
Application Configuration
Update your application.yml to match you're Easysearch deployment:
easy-es:
enable: true
address: localhost:9200
schema: https
username: admin
password: your_secure_password
keep-alive-millis: 18000
global-config:
i-kun-mode: true
process-index-mode: smoothly
async-process-index-blocking: true
print-dsl: false
db-config:
map-underscore-to-camel-case: true
index-prefix: prod_
id-type: customize
field-strategy: not_empty
refresh-policy: immediate
enable-track-total-hits: true
Entity Definition
package com.example.search.entity;
import lombok.Data;
import lombok.experimental.Accessors;
import org.dromara.easyes.annotation.HighLight;
import org.dromara.easyes.annotation.IndexField;
import org.dromara.easyes.annotation.IndexId;
import org.dromara.easyes.annotation.IndexName;
import org.dromara.easyes.annotation.Settings;
import org.dromara.easyes.annotation.rely.Analyzer;
import org.dromara.easyes.annotation.rely.FieldStrategy;
import org.dromara.easyes.annotation.rely.FieldType;
import org.dromara.easyes.annotation.rely.IdType;
import java.time.LocalDateTime;
/**
* Search document model
*/
@Data
@Accessors(chain = true)
@Settings(shardsNum = 3, replicasNum = 2)
@IndexName(value = "articles", keepGlobalPrefix = true)
public class Article {
@IndexId(type = IdType.CUSTOMIZE)
private String id;
private String title;
@HighLight(mappingField = "highlightedContent")
@IndexField(fieldType = FieldType.TEXT, analyzer = Analyzer.IK_SMART)
private String content;
@IndexField(strategy = FieldStrategy.NOT_EMPTY)
private String author;
@IndexField(fieldType = FieldType.DATE, dateFormat = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime publishDate;
private String highlightedContent;
private Integer viewCount;
@IndexField(fieldType = FieldType.GEO_POINT)
private String geoLocation;
}
Mapper Interface
package com.example.search.mapper;
import org.dromara.easyes.core.kernel.BaseEsMapper;
import com.example.search.entity.Article;
public interface ArticleMapper extends BaseEsMapper<Article> {
}
Application Entry Point
package com.example.search;
import org.dromara.easyes.spring.annotation.EsMapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EsMapperScan("com.example.search.mapper")
public class SearchApplication {
public static void main(String[] args) {
SpringApplication.run(SearchApplication.class, args);
}
}
Service Implementation
package com.example.search.controller;
import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper;
import com.example.search.entity.Article;
import com.example.search.mapper.ArticleMapper;
import org.easysearch.action.search.SearchResponse;
import org.easysearch.search.aggregations.Aggregations;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
@RestController
public class ArticleController {
@Resource
private ArticleMapper articleMapper;
@GetMapping("/create")
public int createSampleData() {
int total = 0;
for (int i = 1; i <= 5; i++) {
Article article = new Article();
article.setId(String.valueOf(i));
article.setTitle("Sample Article " + i);
article.setContent("Content body " + i);
article.setAuthor("Author " + i);
article.setPublishDate(LocalDateTime.now());
article.setViewCount(i * 100);
total += articleMapper.insert(article);
}
return total;
}
@GetMapping("/findByTitle")
public List<Article> findByTitle(@RequestParam String title) {
LambdaEsQueryWrapper<Article> wrapper = new LambdaEsQueryWrapper<>();
wrapper.eq(Article::getTitle, title);
return articleMapper.selectList(wrapper);
}
@GetMapping("/search")
public List<Article> search(@RequestParam String keyword) {
LambdaEsQueryWrapper<Article> wrapper = new LambdaEsQueryWrapper<>();
wrapper.match(Article::getContent, keyword);
return articleMapper.selectList(wrapper);
}
@GetMapping("/all")
public List<Article> findAll() {
LambdaEsQueryWrapper<Article> wrapper = new LambdaEsQueryWrapper<>();
return articleMapper.selectList(wrapper);
}
@GetMapping("/stats")
public Aggregations getStatistics() {
LambdaEsQueryWrapper<Article> wrapper = new LambdaEsQueryWrapper<>();
wrapper.groupBy(Article::getPublishDate)
.max(Article::getViewCount)
.min(Article::getViewCount);
SearchResponse response = articleMapper.search(wrapper);
return response.getAggregations();
}
@GetMapping("/sqlQuery")
public String executeSqlQuery(@RequestParam(required = false) String title) {
String sql;
if (title != null && !title.isEmpty()) {
sql = String.format("SELECT * FROM prod_articles WHERE title = '%s'", title);
} else {
sql = "SELECT * FROM prod_articles LIMIT 10";
}
return articleMapper.executeSQL(sql);
}
}
Testing the Integration
Once the application is running, verify functionality with these endpoints:
# Initialize sample documents
curl http://localhost:8080/create
# Retrieve all documents
curl http://localhost:8080/all
# Find by exact title match
curl "http://localhost:8080/findByTitle?title=Sample Article 1"
# Full-text search
curl "http://localhost:8080/search?keyword=Content"
# SQL-style query
curl "http://localhost:8080/sqlQuery?title=Sample Article 2"
# Aggregation statistics
curl http://localhost:8080/stats
Additional Resources
- Easy-Es Official Site: https://easy-es.cn
- Gitee Mirror: https://gitee.com/dromara/easy-es
- GitHub Mirror: https://github.com/dromara/easy-es
- Easysearch Product Page: https://infinilabs.cn/products/easysearch