操作ElasticSearch的数据,有两种方式一种是 ElasticsearchRepository 接口,另一种是ElasticsearchTemplate接口
SpringData对ES的封装ElasticsearchRestTemplate类,可直接使用,此类在ElasticsearchRestTemplate基础上进行性一定程度的封装,使用起来更方便灵活,拓展性更强。ElasticsearchRepository可以被继承操作ES,是SpringBoot对ES的高度封装,操作最为方便,但牺牲了灵活性。
Spring boot 和Elasticsearch版本关系:
一、使用ElasticsearchRestTemplate类
1.引用Maven类库
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
2. 配置文件application.yml
spring:
elasticsearch:
rest:
uris: http://192.168.10.202:9200
connection-timeout: 1s
read-timeout: 1m
username: elastic
password: elastic
注意,如果es资源没有开启x-pack安全插件的话,可以不加username和password(因为默认是没有的)。
3.创建实体类(用于JSON文档对象的转换)
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
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;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
* @author Sinbad
* @description: 测试ES对象<br />
* @date 2022/8/26 17:12
*/
@Document(indexName = "mysql-test")
@Data
public class TestEsEntity {
@Id
Long id;
@Field(type = FieldType.Text, name = "addr")
String addr;
@Field(type = FieldType.Text, name = "name")
String name;
@Field(type = FieldType.Date, name = "birthday", pattern = "yyyy-MM-dd")
LocalDate birthday;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8",locale = "zh_CN")
@Field(type = FieldType.Date, name = "create_time", pattern = "yyyy-MM-dd HH:mm:ss",format =DateFormat.custom )
LocalDateTime createTime;
}
@Document注解:表示对应一个索引名相关的文档
@Data注解:lombok的,为类提供读写属性, 此外还提供了 equals()、hashCode()、toString() 方法
@Id 注解:表示文档的ID字段
@Field注解:文档字段的注解,对于日期含时间的字段,要写patten和format,不然会无法更新文档对象
@JsonFormat注解:将文档转换成JSON返回给前端时用到
注意日期类型字段不要用java.util.Date类型,要用java.time.LocalDate或java.time.LocalDateTime类型。
测试实例:
import com.hkyctech.commons.base.entity.JsonResult;
import com.hkyctech.tu.core.vo.TestEsEntity ;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Slf4j
@Service
public class ElasticSearchServiceImpl {
@Resource
ElasticsearchRestTemplate elasticsearchTemplate; //直接注入就可以用了
/***
* @description 查询全部数据
*/
public Object testSearchAll(){
Query query=elasticsearchTemplate.matchAllQuery();
return elasticsearchTemplate.search(query, TestEsEntity .class);
}
/***
* @description 精确查询地址字段
* @param keyword 搜索关键字
*/
public Object testSearchAddr(String keyword) {
NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
//查询条件
.withQuery(QueryBuilders.queryStringQuery(keyword).defaultField("addr"))
//分页
.withPageable(PageRequest.of(0, 10))
//高亮字段显示
.withHighlightFields(new HighlightBuilder.Field(keyword))
.build();
return elasticsearchTemplate.search(nativeSearchQuery, TestEsEntity .class);
}
/***
* @description 组合查询,查询关键词不分词,关系and
*/
public Object testComboSearchAnd(){
BoolQueryBuilder esQuery=QueryBuilders.boolQuery()
.must(QueryBuilders.termQuery("addr", "深圳"))
.must(QueryBuilders.termQuery("addr", "广东"));
NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
//查询条件
.withQuery(esQuery)
//分页
.withPageable(PageRequest.of(0, 10))
.build();
return elasticsearchTemplate.search(nativeSearchQuery, TestEsEntity .class);
}
/***
* @description 组合查询,查询关键词不分词,关系or
*/
public Object testComboSearchOr(){
BoolQueryBuilder esQuery=QueryBuilders.boolQuery()
.should(QueryBuilders.termQuery("addr", "深圳"))
.should(QueryBuilders.termQuery("addr", "广东"));
NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
//查询条件
.withQuery(esQuery)
//分页
.withPageable(PageRequest.of(0, 10))
.build();
return elasticsearchTemplate.search(nativeSearchQuery, TestEsEntity .class);
}
/***
* @description 索引或更新文档
* @param vo 文档对象
*/
public JsonResult testPutDocument(TestEsEntity vo){
try {
Object data = elasticsearchTemplate.save(vo);
return JsonResult.getSuccessResult(data,"更新成功");
}catch (Exception e){
// 看http请求响应日志其实操作成功了,但是会报解析出错,可能是spring的bug,这里拦截一下
String message=e.getMessage();
if(message.indexOf("response=HTTP/1.1 200 OK")>0 || message.indexOf("response=HTTP/1.1 201 Created")>0){
return JsonResult.getSuccessResult("更新成功");
}
return JsonResult.getFailResult(e.getStackTrace(),e.getMessage());
}
}
/***
* @description 删除文档
* @param id 文档ID
*/
public JsonResult deleteDocument(String id){
try {
elasticsearchTemplate.delete(id, TestEsEntity .class);
return JsonResult.getSuccessResult("删除成功");
}catch (Exception e){
String message=e.getMessage();
// 看http请求响应日志其实操作成功了,但是会报解析出错,可能是spring的bug,这里拦截一下
if(message.indexOf("response=HTTP/1.1 200 OK")>0 ){
return JsonResult.getSuccessResult("删除成功");
}
return JsonResult.getFailResult(e.getStackTrace(),e.getMessage());
}
}
}
二、使用ElasticsearchRepository 类
1.引用Maven类库
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
2. 配置文件application.yml
spring:
elasticsearch:
rest:
uris: http://192.168.10.202:9200
connection-timeout: 1s
read-timeout: 1m
username: elastic
password: elastic
3. ElasticsearchRepository接口的源码
package org.springframework.data.elasticsearch.repository;
import java.io.Serializable;
import org.elasticsearch.index.query.QueryBuilder;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.data.repository.NoRepositoryBean;
@NoRepositoryBean
public interface ElasticsearchRepository<T, ID extends Serializable> extends ElasticsearchCrudRepository<T, ID> {
<S extends T> S index(S entity);
Iterable<T> search(QueryBuilder query);
Page<T> search(QueryBuilder query, Pageable pageable);
Page<T> search(SearchQuery searchQuery);
Page<T> searchSimilar(T entity, String[] fields, Pageable pageable);
void refresh();
Class<T> getEntityClass();
}
CrudRepository 源码
package org.springframework.data.repository;
import java.util.Optional;
/**
* Interface for generic CRUD operations on a repository for a specific type.
*
* @author Oliver Gierke
* @author Eberhard Wolff
*/
@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {
/**
* Saves a given entity. Use the returned instance for further operations as the save operation might have changed the
* entity instance completely.
*
* @param entity must not be {@literal null}.
* @return the saved entity will never be {@literal null}.
*/
<S extends T> S save(S entity);
/**
* Saves all given entities.
*
* @param entities must not be {@literal null}.
* @return the saved entities will never be {@literal null}.
* @throws IllegalArgumentException in case the given entity is {@literal null}.
*/
<S extends T> Iterable<S> saveAll(Iterable<S> entities);
/**
* Retrieves an entity by its id.
*
* @param id must not be {@literal null}.
* @return the entity with the given id or {@literal Optional#empty()} if none found
* @throws IllegalArgumentException if {@code id} is {@literal null}.
*/
Optional<T> findById(ID id);
/**
* Returns whether an entity with the given id exists.
*
* @param id must not be {@literal null}.
* @return {@literal true} if an entity with the given id exists, {@literal false} otherwise.
* @throws IllegalArgumentException if {@code id} is {@literal null}.
*/
boolean existsById(ID id);
/**
* Returns all instances of the type.
*
* @return all entities
*/
Iterable<T> findAll();
/**
* Returns all instances of the type with the given IDs.
*
* @param ids
* @return
*/
Iterable<T> findAllById(Iterable<ID> ids);
/**
* Returns the number of entities available.
*
* @return the number of entities
*/
long count();
/**
* Deletes the entity with the given id.
*
* @param id must not be {@literal null}.
* @throws IllegalArgumentException in case the given {@code id} is {@literal null}
*/
void deleteById(ID id);
/**
* Deletes a given entity.
*
* @param entity
* @throws IllegalArgumentException in case the given entity is {@literal null}.
*/
void delete(T entity);
/**
* Deletes the given entities.
*
* @param entities
* @throws IllegalArgumentException in case the given {@link Iterable} is {@literal null}.
*/
void deleteAll(Iterable<? extends T> entities);
/**
* Deletes all entities managed by the repository.
*/
void deleteAll();
}
开发实例:
public interface LogRepository extends ElasticsearchRepository<Log, String> {
/**
* 定义一个方法查询:根据title查询es
*
* 原因: ElasticsearchRepository会分析方法名,参数对应es中的field(这就是灵活之处)
* @param title
*/
List<Log> findBySummary(String summary);
List<Log> findByTitle(String title);
/**
* 定义一个方法查询: 根据title,content查询es
*/
List<Log> findByTitleAndContent(String title, String content);
}
@PostMapping("save")
public void save(@Validated @RequestBody Log req){
Log dto = new Log();
dto.setTitle(req.getTitle());
dto.setSummary(req.getSummary());
dto.setContent(req.getContent());
dto.setCreateTime(new Date());
dto.setId(req.getId());
LogRepository.save(dto);
return ;
}
@PostMapping("testTitle")
public void testSearchTitle(@Validated @RequestBody Log req){
List<Log> searchResult = logRepository.findByTitle(req.getMobileType());
Iterator<Log> iterator = searchResult.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
System.out.println("sa");
return;
}
官网:Spring Data Elasticsearch - Reference Documentation