(1). 概述
Spring Data Elasticsearch在Elasticsearch SDK的基础上,提供了更高级的封装,不过,因为Elasticsearch经常的变化,发现:Spring Data Elasticsearch的API也是经常变的,所以,所谓的架构前瞻性的设计有时是很难跟上变化的,特别是Spring这种做粘贴层的,既要抽出共性,又要考虑个性,还要定义规范.
在这里对Spring Data Elasticsearch进行一个简单的入门案例,原因是:Elasticsearch SDK自己要封装的还是有点多(比如:Mapping管理/分页管理).
(2). 项目结构
lixin-macbook:elasticsearch-demo lixin$ tree
.
├── pom.xml
├── src
│ └── main
│ ├── java
│ │ └── help
│ │ └── lixin
│ │ └── demo
│ │ ├── DemoApplication.java
│ │ ├── controller
│ │ │ └── BookController.java
│ │ ├── dao
│ │ │ └── BookRepository.java
│ │ └── model
│ │ └── Book.java
│ └── resources
│ └── application.yml
└── target
(3). application.yml
spring:
data:
elasticsearch:
# 更多参数请参考这个类:
# org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchProperties
# es的集群名称
cluster-name: docker-cluster
# es的集群机器列表
cluster-nodes: 127.0.0.1:9200
(4). Book
package help.lixin.demo.model;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
@Document(indexName = "books")
public class Book {
@Id
private String id;
@Field(type = FieldType.Text)
private String name;
@Field(type = FieldType.Text)
private String summary;
@Field(type = FieldType.Integer)
private Integer price;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSummary() {
return summary;
}
public void setSummary(String summary) {
this.summary = summary;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
}
(5). BookRepository
package help.lixin.demo.dao;
import help.lixin.demo.model.Book;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import java.util.List;
public interface BookRepository extends ElasticsearchRepository<Book, String> {
List<Book> findByNameAndPrice(String name, Integer price);
}
(6). BookController
package help.lixin.demo.controller;
import help.lixin.demo.dao.BookRepository;
import help.lixin.demo.model.Book;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.*;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.Criteria;
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.stream.Collectors;
@RestController
public class BookController {
private ElasticsearchOperations elasticsearchOperations;
private BookRepository bookRepository;
public BookController(ElasticsearchOperations elasticsearchOperations, BookRepository bookRepository) {
this.elasticsearchOperations = elasticsearchOperations;
this.bookRepository = bookRepository;
}
/**
* @return
*/
@GetMapping("/mapping")
public String index() {
IndexOperations indexOperations = elasticsearchOperations.indexOps(Book.class);
indexOperations.createMapping(Book.class);
indexOperations.putMapping(Book.class);
return "SUCCESS";
}
/**
* curl -X POST -H "Accept: application/json" -H "Content-type: application/json" -d '{ "id":"1" ,"name":"hello","summary":"test","price":80 }' 'http://127.0.0.1:8080/book'
* curl -X POST -H "Accept: application/json" -H "Content-type: application/json" -d '{ "id":"2" ,"name":"world","summary":"test2","price":90 }' 'http://127.0.0.1:8080/book'
* curl -X POST -H "Accept: application/json" -H "Content-type: application/json" -d '{ "id":"3" ,"name":"hello","summary":"test","price":60 }' 'http://127.0.0.1:8080/book'
* curl -X POST -H "Accept: application/json" -H "Content-type: application/json" -d '{ "id":"4" ,"name":"hello","summary":"test","price":70 }' 'http://127.0.0.1:8080/book'
*
* @param book
* @return
*/
@PostMapping("/book")
public String save(@RequestBody Book book) {
Book bookTemp = elasticsearchOperations.save(book);
return bookTemp.getId();
}
/**
* curl -X GET http://localhost:8080/book/1
*
* @param id
* @return
*/
@GetMapping("/book/{id}")
public Book findById(@PathVariable("id") String id) {
Book book = elasticsearchOperations.get(id, Book.class, IndexCoordinates.of("books"));
return book;
}
/**
* curl -X GET 'http://localhost:8080/query/hello'
*
* @param name
* @return
*/
@GetMapping("/query/{name}")
public List<Book> query(@PathVariable("name") String name) {
List<Book> result = bookRepository.findByNameAndPrice(name, 80);
return result;
}
/**
* curl -X GET 'http://localhost:8080/search/hello'
*
* @param name
* @return
*/
@GetMapping("/search/{name}")
public List<Book> search(@PathVariable("name") String name) {
// Criteria criteria = new Criteria("name").is("hello").and("price").greaterThan(30);
Criteria criteria = new Criteria("name").is(name);
Query criteriaQuery = new CriteriaQuery(criteria);
SearchHits<Book> search = elasticsearchOperations.search(criteriaQuery, Book.class);
List<Book> list = search.getSearchHits().stream().map(item -> item.getContent()).collect(Collectors.toList());
return list;
}
/**
* curl http://localhost:8080/page/hello
*
* @param name
* @return
*/
@GetMapping("/page/{name}")
public Page<Book> page(@PathVariable("name") String name) {
Criteria criteria = new Criteria("name").is(name);
Query criteriaQuery = new CriteriaQuery(criteria);
SearchHits<Book> searchHits = elasticsearchOperations.search(criteriaQuery, Book.class);
SearchPage<Book> searchPage = SearchHitSupport.searchPageFor(searchHits, Pageable.ofSize(1));
Page<Book> page = (Page<Book>) SearchHitSupport.unwrapSearchHits(searchPage);
// 总页数
int totalPages = page.getTotalPages();
// 总记录数
long totalElements = page.getTotalElements();
// 每页显示多少条
int size = page.getSize();
return page;
}
}
(7). 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>help.lixin.elastic.search</groupId>
<artifactId>elastic-search-parent</artifactId>
<packaging>jar</packaging>
<version>1.0.0-SNAPSHOT</version>
<name>elastic-search-parent</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<mybatis-plus-boot-starter.version>3.4.2</mybatis-plus-boot-starter.version>
<spring-cloud.version>2021.0.0</spring-cloud.version>
<spring-boot-dependencies.version>2.6.1</spring-boot-dependencies.version>
<spring-cloud-netflix.version>3.1.0</spring-cloud-netflix.version>
<spring-cloud-alibaba-dependencies>2021.1</spring-cloud-alibaba-dependencies>
<!-- <spring-cloud.version>Hoxton.RELEASE</spring-cloud.version>-->
<!-- <spring-boot-dependencies.version>2.2.5.RELEASE</spring-boot-dependencies.version>-->
<!-- <spring-cloud-netflix.version>2.2.0.RELEASE</spring-cloud-netflix.version>-->
<!-- <spring-cloud-alibaba-dependencies>2.2.0.RELEASE</spring-cloud-alibaba-dependencies>-->
<swagger-annotations.version>1.5.13</swagger-annotations.version>
<gerp-common.version>1.0.0-SNAPSHOT</gerp-common.version>
<org.mapstruct>1.4.2.Final</org.mapstruct>
<xxl-job-integration.version>1.0.0-SNAPSHOT</xxl-job-integration.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot-dependencies.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>${spring-cloud-netflix.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba-dependencies}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<!-- 引入ribbon
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
-->
<!-- 引入openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- 引入nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
(8). 总结
总体来说:Spring Data Elasticsearch在Elasticsearch的SDK上进行了一层封装,相对来说操作比较容易,但是,感觉分页还是比较繁琐的.