持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情
SpringBoot中ElasticsearchRestTemplate的使用
环境: Java8 , SpringBoot 2.3.3.RELEASE, elasticsearch 7.6.2
准备
maven
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
yml
spring:
elasticsearch:
rest:
uris: 127.0.0.1:9200
启动类添加@EnableElasticsearchRepositories(basePackages = {"com.xx.elasticsearch.repository"}) 开启repositories功能
doc
@Data
@Builder
@Document(indexName = "user", replicas = 0)
public class User {
@Id
private Long id;
/**
* 昵称
*/
@MultiField(mainField = @Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart"),
otherFields = @InnerField(suffix = "keyword", type = FieldType.Keyword))
private String nickname;
/**
* 账号
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 邮箱
*/
private String email;
/**
* 头像
*/
private String portrait;
/**
* 地址
*/
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String address;
/**
* 个性签名
*/
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String signature;
/**
* 状态, 0 停用, 1启用
*/
@Field(type = FieldType.Integer)
private Integer status;
/**
* 过期时间
*/
private Long expire;
/**
* 创建时间
*/
private Long createTime;
/**
* 更新时间
*/
private Long updateTime;
}
Repository
public interface UserRepository extends ElasticsearchRepository<User, Long> {
}
测试使用
注入相关属性准备使用
@Autowired
private ElasticsearchRestTemplate elasticsearchTemplate;
@Autowired
private UserRepository userRepositories;
测试Repository方式操作文档
Repository操作有点类似于JPA
添加文档 执行下面的测试方法, 可以看到
@Test
void save() {
User user = User.builder()
.id(1L)
.nickname("小明")
.username("张三")
.password("e10adc3949ba59abbe56e057f20f883e")
.email("xiaoming@163.com")
.address("浙江杭州拱墅区")
.portrait("@666")
.signature("美妙的人生,在于能够迷上什么!")
.expire(4102415999L)
.createTime(1629500572L)
.updateTime(1629500637L)
.status(1)
.build();
userRepositories.save(user);
User user1 = User.builder()
.id(2L)
.nickname("小红")
.username("李四")
.password("e10adc3949ba59abbe56e057f20f883e")
.email("xiaohong@163.com")
.address("浙江杭州西湖区")
.portrait("@333")
.signature("弱小和无知不是生存的障碍, 傲慢才是!")
.expire(4102415999L)
.createTime(1629309372L)
.updateTime(1629440205L)
.status(1)
.build();
userRepositories.save(user1);
}
查询
@Test
void query() {
userRepositories.findAll().forEach(System.out::println);
}
删除
@Test
void delete() {
// userRepositories.deleteById(1L);
userRepositories.deleteAll();
}
ElasticsearchRestTemplate
添加
User user = User.builder()
.id(3L)
.nickname("小华")
.username("赵六")
.password("e10adc3949ba59abbe56e057f20f883e")
.email("xiaoming@163.com")
.address("浙江杭州拱墅区")
.portrait("@666")
.signature("美妙的人生,在于能够迷上什么!")
.expire(4102415999L)
.createTime(1629500572L)
.updateTime(1629500637L)
.status(1)
.build();
// 使用对象添加文档
// elasticsearchTemplate.save(user);
IndexQuery indexQuery = new IndexQuery();
indexQuery.setObject(user);
IndexQuery indexQuery1 = new IndexQuery();
user.setId(4L);
indexQuery1.setObject(user);
List<IndexQuery> indexQueries = new ArrayList<>();
indexQueries.add(indexQuery);
indexQueries.add(indexQuery1);
// 批量添加或更新文档
elasticsearchTemplate.bulkIndex(indexQueries, IndexCoordinates.of("user"));
// 批量更新数据
// List<UpdateQuery> updateQueries = new ArrayList<>();
// elasticsearchTemplate.bulkUpdate(updateQueries, IndexCoordinates.of("user"));
查询
@Test
void queryByTemplate() {
String queryColumn = "signature";
BoolQueryBuilder queryBuilder = new BoolQueryBuilder();
queryBuilder
.must(QueryBuilders.matchPhraseQuery(queryColumn, "弱小"))
// 过滤
// .filter()
;
// 高亮处理, 其实就是拼接<span/>标签, 浏览器会自动解析该标签
HighlightBuilder.Field highlightField = new HighlightBuilder.Field(queryColumn)
// 设置为red
.preTags("<span style=\"color:red\">")
.postTags("</span>");
Query query = new NativeSearchQueryBuilder()
.withQuery(queryBuilder)
// post_filter, 查询后过滤结果
// .withFilter(queryBuilder)
// 分页
.withPageable(PageRequest.of(0, 10))
// 返回字段
// .withFields()
// 排序
// .withSort()
// 聚合
// .addAggregation()
// 高亮
.withHighlightFields(highlightField)
.build();
SearchHits<User> search = elasticsearchTemplate.search(query, User.class);
if (search.getTotalHits() > 0) {
List<User> users = new ArrayList<>();
search.forEach(userSearchHit -> {
User user = userSearchHit.getContent();
Map<String, List<String>> highlightFields = userSearchHit.getHighlightFields();
if (highlightFields.size() > 0) {
// 将高亮的数据结果填充到响应数据中
List<String> strings = highlightFields.get(queryColumn);
if (CollUtil.isNotEmpty(strings)) {
user.setSignature(strings.get(0));
}
}
users.add(user);
});
users.forEach(System.out::println);
}
}
注意: 这里有个比较坑的点, 这个withFilter设置过滤, 我们当时在老的项目中有使用withFilter进行查询的, 发现执行查询的耗时很长,
然后断点跟踪到源码中发现了这个withFilter到org.springframework.data.elasticsearch.core.RequestFactory#searchRequest这里
被设置成了postFilter, 也就是先查询出结果, 然后再过滤, 分析我们的需求, 肯定是查询时就过滤