文章目錄
- Spring Data Elasticsearch
- 案例說明
- 創建專案
- application.yml 配置
- Student 物體類
- @Document 注解
- @Id 注解
- @Field 注解
- 文本型別 text 和 keyword
- analyzer 指定分詞器
- 通過 ElasticsearchRepository 實作 CRUD 操作
- Repository 方法命名規范
- StudentRepository
- 業務類 StudentService
- 在 Elasticsearch 中創建 students 索引
- 測驗學生資料的 CRUD 操作
- 使用 Criteria 構建查詢
- StudentSearcher
- 修改 StudentService
- 在測驗類中添加測驗方法
Spring Data Elasticsearch
https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#reference
Spring Data Elasticsearch 是 Elasticsearch 搜索引擎開發的解決方案,它提供:
模板物件,用于存盤、搜索、排序檔案和構建聚合的高級API,
例如,Repository 使開發者能夠通過定義具有自定義方法名稱的介面來表達查詢,
案例說明
在 Elasticsearch 中存盤學生資料,并對學生資料進行搜索測驗,
資料結構:
| 學號 | 姓名 | 性別 | 出生日期 |
|---|---|---|---|
| 27 | 張三 | 男 | 2020-12-4 |
案例測驗以下資料操作:
- 創建 students 索引和映射
- C - 創建學生資料
- R - 訪問學生資料
- U - 修改學生資料
- D - 洗掉學生資料
- 使用 Repository 和 Criteria 搜索學生資料
創建專案
-
新建工程


-
新建 springboot module,添加 spring data elasticsearch 依賴




專案的 pom.xml 檔案如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.tedu</groupId>
<artifactId>es-springboot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>es-springboot</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml 配置
logging.level.tracer=TRACE 作用是在控制臺中顯示底層的查詢日志
spring:
elasticsearch:
rest:
uris: http://192.168.64.181:9200
logging:
level:
tracer: TRACE
Student 物體類
package cn.tedu.esspringboot.es;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.DateFormat;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
@Document(indexName = "students",shards = 3,replicas = 2)
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
@Id
private Long id;
@Field(analyzer = "ngram",type = FieldType.Text)
private String name;
@Field(type = FieldType.Keyword)
private Character gender;
@Field(type= FieldType.Date,format = DateFormat.custom,pattern = "yyyy-M-d")
private String birthDate;
}
@Document 注解
@Documnet注解對索引的引數進行設定,
上面代碼中,把 students 索引的分片數設定為3,副本數設定為2,
@Id 注解
在 Elasticsearch 中創建檔案時,使用 @Id 注解的欄位作為檔案的 _id 值
@Field 注解
通過 @Field 注解設定欄位的資料型別和其他屬性,
文本型別 text 和 keyword
text 型別會進行分詞,
keyword 不會分詞,
analyzer 指定分詞器
通過 analyzer 設定可以指定分詞器,例如 ik_smart、ik_max_word 等,
我們這個例子中,對學生姓名欄位使用的分詞器是 ngram 分詞器,其分詞效果如下面例子所示:
| 字串 | 分詞結果 |
|---|---|
| 劉德華 | 劉 劉德 劉德華 德 德華 華 |
通過 ElasticsearchRepository 實作 CRUD 操作
Spring Data 的 Repository 介面提供了一種宣告式的資料操作規范,無序撰寫任何代碼,只需遵循 Spring Data 的方法定義規范即可完成資料的 CRUD 操作,
ElasticsearchRepository 繼承自 Repository,其中已經預定義了基本的 CURD 方法,我們可以通過繼承 ElasticsearchRepository,添加自定義的資料操作方法,
Repository 方法命名規范
自定義資料操作方法需要遵循 Repository 規范,示例如下:
| 關鍵詞 | 方法名 | es查詢 |
|---|---|---|
| And | findByNameAndPrice | { “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “?”, “fields” : [ “name” ] } }, { “query_string” : { “query” : “?”, “fields” : [ “price” ] } } ] } }} |
| Or | findByNameOrPrice | { “query” : { “bool” : { “should” : [ { “query_string” : { “query” : “?”, “fields” : [ “name” ] } }, { “query_string” : { “query” : “?”, “fields” : [ “price” ] } } ] } }} |
| Is | findByName | { “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “?”, “fields” : [ “name” ] } } ] } }} |
| Not | findByNameNot | { “query” : { “bool” : { “must_not” : [ { “query_string” : { “query” : “?”, “fields” : [ “name” ] } } ] } }} |
| Between | findByPriceBetween | { “query” : { “bool” : { “must” : [ {“range” : {“price” : {“from” : ?, “to” : ?, “include_lower” : true, “include_upper” : true } } } ] } }} |
| LessThan | findByPriceLessThan | { “query” : { “bool” : { “must” : [ {“range” : {“price” : {“from” : null, “to” : ?, “include_lower” : true, “include_upper” : false } } } ] } }} |
| LessThanEqual | findByPriceLessThanEqual | { “query” : { “bool” : { “must” : [ {“range” : {“price” : {“from” : null, “to” : ?, “include_lower” : true, “include_upper” : true } } } ] } }} |
| GreaterThan | findByPriceGreaterThan | { “query” : { “bool” : { “must” : [ {“range” : {“price” : {“from” : ?, “to” : null, “include_lower” : false, “include_upper” : true } } } ] } }} |
| GreaterThanEqual | findByPriceGreaterThan | { “query” : { “bool” : { “must” : [ {“range” : {“price” : {“from” : ?, “to” : null, “include_lower” : true, “include_upper” : true } } } ] } }} |
| Before | findByPriceBefore | { “query” : { “bool” : { “must” : [ {“range” : {“price” : {“from” : null, “to” : ?, “include_lower” : true, “include_upper” : true } } } ] } }} |
| After | findByPriceAfter | { “query” : { “bool” : { “must” : [ {“range” : {“price” : {“from” : ?, “to” : null, “include_lower” : true, “include_upper” : true } } } ] } }} |
| Like | findByNameLike | { “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “?*”, “fields” : [ “name” ] }, “analyze_wildcard”: true } ] } }} |
| StartingWith | findByNameStartingWith | { “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “?*”, “fields” : [ “name” ] }, “analyze_wildcard”: true } ] } }} |
| EndingWith | findByNameEndingWith | { “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “*?”, “fields” : [ “name” ] }, “analyze_wildcard”: true } ] } }} |
| Contains/Containing | findByNameContaining | { “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “?”, “fields” : [ “name” ] }, “analyze_wildcard”: true } ] } }} |
| In (when annotated as FieldType.Keyword) | findByNameIn(Collectionnames) | { “query” : { “bool” : { “must” : [ {“bool” : {“must” : [ {“terms” : {“name” : ["?","?"]}} ] } } ] } }} |
| In | findByNameIn(Collectionnames) | { “query”: {“bool”: {“must”: [{“query_string”:{“query”: “”?" “?”", “fields”: [“name”]}}]}}} |
| NotIn (when annotated as FieldType.Keyword) | findByNameNotIn(Collectionnames) | { “query” : { “bool” : { “must” : [ {“bool” : {“must_not” : [ {“terms” : {“name” : ["?","?"]}} ] } } ] } }} |
| NotIn | findByNameNotIn(Collectionnames) | {“query”: {“bool”: {“must”: [{“query_string”: {“query”: “NOT(”?" “?”)", “fields”: [“name”]}}]}}} |
| Near | findByStoreNear | Not Supported Yet ! |
| True | findByAvailableTrue | { “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “true”, “fields” : [ “available” ] } } ] } }} |
| False | findByAvailableFalse | { “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “false”, “fields” : [ “available” ] } } ] } }} |
| OrderBy | findByAvailableTrueOrderByNameDesc | { “query” : { “bool” : { “must” : [ { “query_string” : { “query” : “true”, “fields” : [ “available” ] } } ] } }, “sort”:[{“name”:{“order”:“desc”}}] } |
StudentRepository
package cn.tedu.esspringboot.es;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import java.util.List;
public interface StudentRepository extends ElasticsearchRepository<Student, Long> {
List<Student> findByName(String name);
List<Student> findByNameOrBirthDate(String name, String birthDate);
}
業務類 StudentService
package cn.tedu.esspringboot.es;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class StudentService {
@Autowired
private StudentRepository studentRepo;
public void save(Student student) {
studentRepo.save(student);
}
public void delete(Long id) {
studentRepo.deleteById(id);
}
public void update(Student student) {
save(student);
}
public List<Student> findByName(String name) {
return studentRepo.findByName(name);
}
public List<Student> findByNameOrBirthDate(String name, String birthDate) {
return studentRepo.findByNameOrBirthDate(name, birthDate);
}
}
在 Elasticsearch 中創建 students 索引
在開始運行測驗之前,在 Elasticsearch 中先創建 students 索引:
PUT /students
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 2,
"index.max_ngram_diff":30,
"analysis": {
"analyzer": {
"ngram_analyzer": {
"tokenizer": "ngram_tokenizer"
}
},
"tokenizer": {
"ngram_tokenizer": {
"type": "ngram",
"min_gram": 1,
"max_gram": 30,
"token_chars": [
"letter",
"digit"
]
}
}
}
},
"mappings": {
"properties": {
"id": {
"type": "long"
},
"name": {
"type": "text",
"analyzer": "ngram_analyzer"
},
"gender": {
"type": "keyword"
},
"birthDate": {
"type": "date",
"format": "yyyy-MM-dd"
}
}
}
}
測驗學生資料的 CRUD 操作
添加測驗類,對學生資料進行 CRUD 測驗
package cn.tedu.esspringboot;
import cn.tedu.esspringboot.es.Student;
import cn.tedu.esspringboot.es.StudentService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
public class Test1 {
@Autowired
private StudentService studentService;
@Test
public void test1() {
studentService.save(new Student(998L,"張三",'男',"2020-12-04"));
}
@Test
public void test2() {
studentService.update(new Student(1L,"李四",'女',"2020-12-04"));
}
@Test
public void test3() {
List<Student> stu = studentService.findByName("四");
System.out.println(stu);
}
@Test
public void test4() throws Exception {
List<Student> stu;
stu = studentService.findByNameOrBirthDate("四", "1999-09-09");
System.out.println(stu);
stu = studentService.findByNameOrBirthDate("SFSDFS", "2020-12-04");
System.out.println(stu);
}
}
依次運行每個測驗方法,并使用 head 觀察測驗結果

使用 Criteria 構建查詢
Spring Data Elasticsearch 中,可以使用 SearchOperations 工具執行一些更復雜的查詢,這些查詢操作接收一個 Query 物件封裝的查詢操作,
Spring Data Elasticsearch 中的 Query 有三種:
- CriteriaQuery
- StringQuery
- NativeSearchQuery
多數情況下,CriteriaQuery 都可以滿足我們的查詢求,下面來看兩個 Criteria 查詢示例:
StudentSearcher
package cn.tedu.esspringboot.es;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.Criteria;
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
@Component
public class StudentSearcher {
@Autowired
private ElasticsearchOperations searchOperations;
public List<Student> searchByBirthDate(String birthDate) {
Criteria c = new Criteria("birthDate").is(birthDate);
return criteriaSearch(c);
}
public List<Student> searchByBirthDate(String ge, String le) {
Criteria c = new Criteria("birthDate").between(ge, le);
return criteriaSearch(c);
}
private List<Student> criteriaSearch(Criteria c) {
CriteriaQuery q = new CriteriaQuery(c);
SearchHits<Student> hits = searchOperations.search(q, Student.class);
List<Student> list = hits.stream().map(SearchHit::getContent).collect(Collectors.toList());
return list;
}
}
修改 StudentService
在 StudentService 中,呼叫 StudentSearcher,執行查詢:
package cn.tedu.esspringboot.es;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class StudentService {
@Autowired
private StudentRepository studentRepo;
@Autowired
private StudentSearcher studentSearcher;
public void save(Student student) {
studentRepo.save(student);
}
public void delete(Long id) {
studentRepo.deleteById(id);
}
public void update(Student student) {
save(student);
}
public List<Student> findByName(String name) {
return studentRepo.findByName(name);
}
public List<Student> findByNameOrBirthDate(String name, String birthDate) {
return studentRepo.findByNameOrBirthDate(name, birthDate);
}
public List<Student> findByBirthDate(String birthDate) {
return studentSearcher.searchByBirthDate(birthDate);
}
public List<Student> findByBirthDate(String ge, String le) {
return studentSearcher.searchByBirthDate(ge, le);
}
}
在測驗類中添加測驗方法
package cn.tedu.esspringboot;
import cn.tedu.esspringboot.es.Student;
import cn.tedu.esspringboot.es.StudentService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
public class Test1 {
@Autowired
private StudentService studentService;
@Test
public void test1() {
studentService.save(new Student(998L,"張三",'男',"2020-12-04"));
}
@Test
public void test2() {
studentService.update(new Student(1L,"李四",'女',"2020-12-04"));
}
@Test
public void test3() {
List<Student> stu = studentService.findByName("四");
System.out.println(stu);
}
@Test
public void test4() throws Exception {
List<Student> stu;
stu = studentService.findByNameOrBirthDate("四", "1999-09-09");
System.out.println(stu);
stu = studentService.findByNameOrBirthDate("SFSDFS", "2020-12-04");
System.out.println(stu);
}
@Test
public void test5() throws Exception {
List<Student> stu;
stu = studentService.findByBirthDate("2020-12-04");
System.out.println(stu);
}
@Test
public void test6() throws Exception {
List<Student> stu;
stu = studentService.findByBirthDate("2020-12-05", "2020-12-09");
System.out.println(stu);
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/237206.html
標籤:其他
上一篇:012 hadoop集群HA搭建
