一、SpringBoot集成ES
- 添加maven依赖,加入核心包spring-boot-starter-data-elasticsearch,注意需要排除elasticsearch-rest-high-level-client并指定其核心版本和安装的ES版本一致
<?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.4.4</version>
<relativePath/>
</parent>
<groupId>com.codecoord</groupId>
<artifactId>springboot-elasticsearch</artifactId>
<version>1.0</version>
<name>springboot-elasticsearch</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>
<exclusions>
<exclusion>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.8.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.74</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
spring:
elasticsearch:
rest:
uris: http://127.0.0.1:9200
二、ElasticsearchRestTemplate
- ElasticsearchRestTemplate提供操作ES的模板类
- 新建SpringBoot实体类,用于操作基础文档
- @Document(indexName = "springboot", shards = 1, replicas = 1)
- 配置索引名称、分片数、副本数,项目启动时将会自动创建索引
- @Id
- @Field(type = FieldType.Keyword)
- @Field(type = FieldType.Text)
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
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;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Document(indexName = "springboot", shards = 1, replicas = 1)
public class SpringBoot {
@Id
private Long id;
@Field(type = FieldType.Keyword)
private String name;
@Field(type = FieldType.Text)
private String createTime;
@Override
public String toString() {
return JSONObject.toJSONString(this);
}
}
public enum FieldType {
Auto,
Text,
Keyword,
Long,
Integer,
Short,
Byte,
Double,
Float,
Half_Float,
Scaled_Float,
Date,
Date_Nanos,
Boolean,
Binary,
Integer_Range,
Float_Range,
Long_Range,
Double_Range,
Date_Range,
Ip_Range,
Object,
Nested,
Ip,
TokenCount,
Percolator,
Flattened,
Search_As_You_Type,
Rank_Feature,
Rank_Features
}
- 创建打印工具类,用于美化json输出
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
public class PrintUtil {
public static void prettyPrint(Object resource) {
System.out.println(JSONObject.toJSONString(resource, SerializerFeature.PrettyFormat));
}
}
- 模板类使用示例
import com.codecoord.springboot.elasticsearch.domain.SpringBoot;
import com.codecoord.springboot.elasticsearch.util.PrintUtil;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Resource;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.MatchPhraseQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.index.query.TermsQueryBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.metrics.StatsAggregationBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.HighlightQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
@SpringBootTest(classes = SpringbootElasticsearchApplication.class)
class ElasticsearchRestTemplateApplicationTests {
private static final IndexCoordinates INDEX = IndexCoordinates.of("springboot");
@Resource
private ElasticsearchRestTemplate elasticsearchRestTemplate;
@Test
void creteIndex() {
boolean success = elasticsearchRestTemplate.indexOps(INDEX).create();
System.out.println("success = " + success);
}
@Test
void deleteIndex() {
boolean success = elasticsearchRestTemplate.indexOps(INDEX).delete();
System.out.println("success = " + success);
}
@Test
void createDocument() {
SpringBoot springBoot = new SpringBoot(1L, "SpringBoot001", LocalDateTime.now().toString());
SpringBoot springboot = elasticsearchRestTemplate.save(springBoot, INDEX);
System.out.println("springboot = " + springboot);
}
@Test
void createDocumentBatch() {
List<SpringBoot> springBoots = new ArrayList<>();
for (int i = 0; i < 10; i++) {
SpringBoot springBoot = new SpringBoot(i + 1L, "SpringBoot00" + (i + 1), LocalDateTime.now().toString());
springBoots.add(springBoot);
}
Iterable<SpringBoot> save = elasticsearchRestTemplate.save(springBoots, INDEX);
System.out.println(save);
}
@Test
void queryDocument() {
SpringBoot springboot = elasticsearchRestTemplate.get("1", SpringBoot.class, INDEX);
System.out.println("springboot = " + springboot);
}
@Test
void deleteDocument() {
String springboot = elasticsearchRestTemplate.delete("1", INDEX);
System.out.println("springboot = " + springboot);
}
@Test
void advanceQueryDocumentMatchAll() {
MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
NativeSearchQuery searchQuery = new NativeSearchQuery(matchAllQueryBuilder);
SearchHits<SpringBoot> searchHits = elasticsearchRestTemplate.search(searchQuery, SpringBoot.class, INDEX);
PrintUtil.prettyPrint(searchHits);
}
@Test
void advanceQueryDocumentMatch() {
MatchQueryBuilder queryBuilder = QueryBuilders.matchQuery("name", "SpringBoot001");
NativeSearchQuery searchQuery = new NativeSearchQuery(queryBuilder);
SearchHits<SpringBoot> searchHits = elasticsearchRestTemplate.search(searchQuery, SpringBoot.class, INDEX);
PrintUtil.prettyPrint(searchHits);
}
@Test
void advanceQueryDocumentMatchPhrase() {
MatchPhraseQueryBuilder queryBuilder = QueryBuilders.matchPhraseQuery("name", "SpringBoot001");
NativeSearchQuery searchQuery = new NativeSearchQuery(queryBuilder);
SearchHits<SpringBoot> searchHits = elasticsearchRestTemplate.search(searchQuery, SpringBoot.class, INDEX);
PrintUtil.prettyPrint(searchHits);
}
@Test
void advanceQueryDocumentMultiMatch() {
MultiMatchQueryBuilder queryBuilder = QueryBuilders.multiMatchQuery("SpringBoot001", "name");
NativeSearchQuery searchQuery = new NativeSearchQuery(queryBuilder);
SearchHits<SpringBoot> searchHits = elasticsearchRestTemplate.search(searchQuery, SpringBoot.class, INDEX);
PrintUtil.prettyPrint(searchHits);
}
@Test
void advanceQueryDocumentTerm() {
TermQueryBuilder queryBuilder = QueryBuilders.termQuery("id", "1");
NativeSearchQuery searchQuery = new NativeSearchQuery(queryBuilder);
SearchHits<SpringBoot> searchHits = elasticsearchRestTemplate.search(searchQuery, SpringBoot.class, INDEX);
PrintUtil.prettyPrint(searchHits);
}
@Test
void advanceQueryDocumentTerms() {
TermsQueryBuilder queryBuilder = QueryBuilders.termsQuery("id", "1", "2");
NativeSearchQuery searchQuery = new NativeSearchQuery(queryBuilder);
SearchHits<SpringBoot> searchHits = elasticsearchRestTemplate.search(searchQuery, SpringBoot.class, INDEX);
PrintUtil.prettyPrint(searchHits);
}
@Test
void advanceQueryDocumentPage() {
MatchAllQueryBuilder queryBuilder = QueryBuilders.matchAllQuery();
NativeSearchQuery searchQuery = new NativeSearchQuery(queryBuilder);
searchQuery.setPageable(PageRequest.of(0, 2, Sort.by(Order.asc("id"))));
SearchHits<SpringBoot> searchHits = elasticsearchRestTemplate.search(searchQuery, SpringBoot.class, INDEX);
PrintUtil.prettyPrint(searchHits);
}
@Test
void advanceQueryDocumentBool() {
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
queryBuilder.must(QueryBuilders.matchQuery("id", 1L));
queryBuilder.mustNot(QueryBuilders.matchQuery("name", "SpringBoot002"));
queryBuilder.should(QueryBuilders.matchQuery("name", "SpringBoot006"));
NativeSearchQuery searchQuery = new NativeSearchQuery(queryBuilder);
SearchHits<SpringBoot> searchHits = elasticsearchRestTemplate.search(searchQuery, SpringBoot.class, INDEX);
PrintUtil.prettyPrint(searchHits);
}
@Test
void advanceQueryDocumentAggregation() {
MatchAllQueryBuilder queryBuilder = QueryBuilders.matchAllQuery();
NativeSearchQuery searchQuery = new NativeSearchQuery(queryBuilder);
StatsAggregationBuilder builder = AggregationBuilders.stats("aggs_group");
builder.field("id");
searchQuery.addAggregation(builder);
SearchHits<SpringBoot> searchHits = elasticsearchRestTemplate.search(searchQuery, SpringBoot.class, INDEX);
PrintUtil.prettyPrint(searchHits);
}
@Test
void advanceQueryDocumentHighlight() {
MatchQueryBuilder queryBuilder = QueryBuilders.matchQuery("name", "SpringBoot001");
NativeSearchQuery searchQuery = new NativeSearchQuery(queryBuilder);
HighlightBuilder highlightQueryBuilder = new HighlightBuilder();
highlightQueryBuilder.preTags("<em>");
highlightQueryBuilder.postTags("</em>");
highlightQueryBuilder.field("name");
searchQuery.setHighlightQuery(new HighlightQuery(highlightQueryBuilder));
SearchHits<SpringBoot> searchHits = elasticsearchRestTemplate.search(searchQuery, SpringBoot.class, INDEX);
PrintUtil.prettyPrint(searchHits);
}
}
三、ElasticsearchRepository
- ElasticsearchRepository封装了常用的增删改查操作,但是不支持复杂查询、删除没有返回值,无法确定是否成功删除
- ElasticsearchRepository需要创建接口作为实现接口
import com.codecoord.springboot.elasticsearch.domain.Product;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ProductDao extends ElasticsearchRepository<Product, Long> {
}
- 创建Product,用于操作文档
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
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;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Document(indexName = "product", shards = 1, replicas = 1)
public class Product {
@Id
private Long id;
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String title;
@Field(type = FieldType.Keyword)
private String category;
@Field(type = FieldType.Double)
private Double price;
@Field(type = FieldType.Keyword, index = false)
private String images;
@Override
public String toString() {
return JSONObject.toJSONString(this);
}
}
- 仓库类使用示例
import com.alibaba.fastjson.JSONObject;
import com.codecoord.springboot.elasticsearch.dao.ProductDao;
import com.codecoord.springboot.elasticsearch.domain.Product;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import javax.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Order;
@SpringBootTest(classes = SpringbootElasticsearchApplication.class)
class ElasticsearchRepositoryApplicationTests {
@Resource
private ProductDao productDao;
@Test
void createDocument() {
Product product = new Product(1L, "HUAWEI Mate30", "华为", 4999D, "http://www.codecoord.com/favicon.ico");
Product save = productDao.save(product);
System.out.println(save);
}
@Test
void createDocumentBatch() {
List<Product> productList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
productList.add(new Product(i + 1L, "HUAWEI Mate30", "华为", 3999D, String.valueOf(i)));
}
Iterable<Product> products = productDao.saveAll(productList);
System.out.println(products);
}
@Test
void queryDocument() {
Optional<Product> product = productDao.findById(1L);
System.out.println(product);
printLine();
List<Long> ids = Arrays.asList(1L, 2L);
Iterable<Product> products = productDao.findAllById(ids);
System.out.println(products);
printLine();
Iterable<Product> sortProduct = productDao.findAll(Sort.by(Order.desc("id")));
System.out.println(sortProduct);
printLine();
Page<Product> productPage = productDao.findAll(PageRequest.of(0, 3, Sort.by(Order.asc("id"))));
System.out.println(JSONObject.toJSONString(productPage));
}
@Test
void countDocument() {
long count = productDao.count();
System.out.println("count = " + count);
printLine();
boolean exists = productDao.existsById(1L);
System.out.println("exists = " + exists);
}
@Test
void updateDocument() {
Product product = new Product(1L, "HUAWEI Mate30", "华为", 4999D, "更新");
Product save = productDao.save(product);
System.out.println(save);
}
@Test
void deleteDocument() {
productDao.deleteById(1L);
}
private void printLine() {
System.out.println("-------------------------------");
}
}