利用 Spring Boot 整合 ES
Elasticsearch(簡稱 ES),是一個全文搜索引擎,同時可以作爲 NoSQL 數據庫,存儲任意格式的文檔和數據,也可以用於大數據的分析與統計。
ES是 Apache 開源的產品,其主要具有以下特點:
- 以 Lucene 爲底層進行封裝,爲用戶提供了一套簡單、易用、風格一致的 RESTful 風格的 API 接口;
- 它以一種分佈式的搜索引擎架構爲用戶提供服務,可以很容易的擴展到上百個節點,甚至更多,使系統具備高可用、高併發等特性;
- 支持 PB 級別數據查詢,其主要用於大數據的查詢、搜索、統計分析等。
通常用來操作 ES 的客戶端有如下幾種:
- TransportClient
- JestClient
- Spring Data Elasticsearch
- HttpClient
其中 HttpClient 主要是利用 ES 的原生 API 對其進行操作,在開發中不是太靈活,因此通常情況下不會選擇其對 ES 進行操作。
利用 TransportClient、Spring Data Elasticsearch 對 ES 操作很方便。但隨着 ES 版本的變更,相關的 API 也在不斷的調整,因此有 ES 服務端版本變更之後,客戶端的代碼也要隨之進行重新編寫。
JestClient 對 ES 進行了封裝,填補了 ES 在 HTTP Rest 接口客戶端上的空白,它適用於 ES 2.0 以上的版本,無需因爲 ES 服務端版本更改而對代碼進行修改。本文我們將重要講解 JestClient 客戶端對 ES 的操作。
利用 JestClient 作爲客戶端對 ES 進行操作
該操作過程主要包括9步,接下來我們一一做下講解。
1. 在 pom 文件中添加依賴,代碼如下:
<dependency>
<groupId>io.searchbox</groupId>
<artifactId>jest</artifactId>
<version>5.3.3</version>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>6.3.0</version>
</dependency>
2. 在 application.yml 配置文件中添加 ES 連接配置信息,代碼如下:
spring:
elasticsearch:
jest:
url: http://******:9200
username: ***
password: *****
readTimeout: 20000
connectionTimeout: 20000
3. 讀取配置信息:
@Configuration
@ConfigurationProperties(prefix = "spring.elasticsearch.jest")
public class EsClientConfiguration {
/**
* ES連接url
*/
private String url;
/**
* ES連接用戶名
*/
private String username;
/**
* ES連接用密碼
*/
private String password;
/**
* ES 讀取超時時間
*/
private Integer readTimeout;
/**
* ES連接超時時間
*/
private Integer connectionTimeout;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getReadTimeout() {
return readTimeout;
}
public void setReadTimeout(Integer readTimeout) {
this.readTimeout = readTimeout;
}
public Integer getConnectionTimeout() {
return connectionTimeout;
}
public void setConnectionTimeout(Integer connectionTimeout) {
this.connectionTimeout = connectionTimeout;
}
}
4. 添加獲取 JestClient 實例工具類:
@Component
public class JestClientUtil {
@Autowired
private EsClientConfiguration esClientConfig;
private JestClient jestClient = null;
public JestClient createJestClient() {
if (jestClient == null) {
synchronized (this) {
if (jestClient == null) {
JestClientFactory factory = new JestClientFactory();
factory.setHttpClientConfig(new HttpClientConfig
//設置連接es server url地址
.Builder(esClientConfig.getUrl())
//設置連接es用戶名
.defaultCredentials(esClientConfig.getUsername()
//設置連接es密碼
esClientConfig.getPassword())
//開啓多線程模式
.multiThreaded(true)
//設置連接es最大超時時間
.connTimeout(esClientConfig.getConnectionTimeout())
//設置從es讀取數據最大時間
.readTimeout(esClientConfig.getReadTimeout())
.build());
jestClient = factory.getObject();
}
}
}
return jestClient;
}
}
5. 新建持久層 StudentRepository 接口:
public interface StudentRepository {
/**
* 添加學生
*
* @param student
*/
void addStudent(Student student);
/**
* 批量添加學生
*
* @param students
*/
void batchAddStudent(List<Student> students);
/**
* 根據學生信息查詢學生信息
*
* @param studentName
*/
List<Student> queryStudentByName(String studentName);
/**
* 創建索引
*/
public void createIndex();
}
6. 新建持久層實現類 StudentRepositoryImpl:
@Repository("studentDao")
public class StudentRepositoryImpl implements StudentRepository {
//es 索引名稱
private static final String ES_INDEX_NAME = "student_index";
//es type名稱
private static final String ES_TYPE_NAME = "student_type";
@Autowired
private JestClientUtil jestClientUtil;
//向索引中添加學生信息
@Override
public void addStudent(Student student) {
Index index = new Index.Builder(student).index(this.ES_INDEX_NAME).
type(this.ES_TYPE_NAME).build();
try {
//獲取jestClient實例並向索引插入學生信息
JestResult jestResult = jestClientUtil.createJestClient().execute(index);
System.out.println(jestResult.isSucceeded());
} catch (Exception e) {
e.printStackTrace();
}
}
//批量添加學生信息
@Override
public void batchAddStudent(List<Student> students) {
if (!CollectionUtils.isEmpty(students)) {
try {
Bulk.Builder bulk = new Bulk.Builder().defaultIndex(this.ES_INDEX_NAME).
defaultType(this.ES_TYPE_NAME);
//將學生列表信息循環假如bulk桶中
for (Student student : students) {
Index index = new Index.Builder(student).build();
bulk.addAction(index);
}
//獲取jestClient實例並向index中插入學生信息
jestClientUtil.createJestClient().execute(bulk.build());
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
//根據學生姓名查詢學生信息
@Override
public List<Student> queryStudentByName(String studentName) {
//實例化SearchSourceBuilder對象
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//組裝index 查詢條件
searchSourceBuilder.query(QueryBuilders.matchQuery("name", studentName));
//利用SearchSourceBuilder對象構建index查詢對象
Search search = new Search.Builder(searchSourceBuilder.toString())
.addIndex(this.ES_INDEX_NAME).addType(this.ES_TYPE_NAME).build();
try {
//獲取jestClient實例並向對index執行查詢語句
JestResult result = jestClientUtil.createJestClient().execute(search);
//獲取查詢結果
return result.getSourceAsObjectList(Student.class);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//創建es索引
@Override
public void createIndex() {
try {
jestClientUtil.createJestClient().execute(new CreateIndex.
Builder(this.ES_INDEX_NAME).build());
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
7. 新建服務層接口 StudentService 及其實現類 StudentServiceImpl:
public interface StudentService {
/**
* 添加學生信息
* @param student
* @return
*/
void addStudent(Student student);
/**
* 批量添加學生信息
* @param students
* @return
*/
void batchAddStudent(List<Student> students);
/**
* 根據學生姓名查詢學生列表信息
* @param studentName
* @return
*/
List<Student> queryStudentsByName(String studentName);
/**
* 創建索引
*/
public void createIndex();
}
//定義學生信息服務接口實現類
@Service("studentService")
public class StudentServiceImpl implements StudentService {
@Resource(name = "studentDao")
private StudentRepository studentDao;
//添加學生信息
@Override
public void addStudent(Student student) {
studentDao.addStudent(student);
}
//批量添加學生信息
@Override
public void batchAddStudent(List<Student> students) {
studentDao.batchAddStudent(students);
}
//根據學生姓名查詢學生信息
@Override
public List<Student> queryStudentsByName(String studentName) {
return studentDao.queryStudentByName(studentName);
}
//創建es索引
@Override
public void createIndex() {
studentDao.createIndex();
}
}
8. 新建控制層 EsClientController:
//控制器定義
@RequestMapping("/esClient")
@RestController
public class EsClientController {
@Autowired
private StudentService studentService;
//添加學生信息
@RequestMapping("/addStudent")
public String addStudent(String studentName, Integer age) {
Student student = new Student(UUID.randomUUID().toString(),
studentName, age, new Date());
studentService.addStudent(student);
return "success";
}
//批量添加學生信息
@RequestMapping("/batchAddStudent")
public String batchAddStudent() {
for (int i = 0; i < 100; i++) {
Student student = new Student(UUID.randomUUID().toString(),
"黃家駒" + i, i + 1, new Date());
studentService.addStudent(student);
}
return "success";
}
//根據學生姓名查詢學生信息
@RequestMapping("/queryStudentsWithName")
public List<Student> queryStudentsByName(String studentName) {
return studentService.queryStudentsByName(studentName);
}
//創建es索引
@RequestMapping("/createIndex")
public String queryStudentsByName() {
studentService.createIndex();
return "Success";
}
}
9. 啓動程序,利用 Postman 對新建索引,新增學生信息,查詢學生信息接口分別進行測試。
(1)創建索引。
(2)新增學生信息。
(3)根據姓名查詢學生信息。