ElasticSearchTemplate 依赖 spring-boot-starter-data-elasticsearch, 对于ES7不适用, 本案例演示是基于ElasticSerach-6.4.3 的
pom:
foodie-dev
com.imooc
1.0-SNAPSHOT
4.0.0
foodie-search
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-starter-data-elasticsearch
2.1.5.RELEASE
yml:
spring:
datasource: # 数据源的相关配置
type: com.zaxxer.hikari.HikariDataSource # 数据源类型:HikariCP
driver-class-name: com.mysql.jdbc.Driver # mysql驱动
url: jdbc:mysql://192.168.209.151:3306/foodie_shop_dev?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=true
username: root
password: root
data:
elasticsearch:
cluster-name: imooc-es-cluster # elasticsearch.yml 中配置集群名
cluster-nodes: 192.168.209.151:9300 # 集群节点, 注意开放给客户端的端口是 9300
与索引库的 mapping结构匹配的实体类:
package com.imooc.es.pojo;
import lombok.Data;
import lombok.ToString;
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;
/**
* Created by robbyzhan on 2020/1/24.
*/
@Document(indexName = "stu", type = "_doc") // 索引库名称和 type
@Data
@ToString
public class Stu {
@Id // 指定此字段和索引库id 一致(索引库id是索引为某条文档分配的 "主键")
private Long stuId;
@Field(store = true)
private String name;
@Field(store = true)
private Integer age;
@Field(store = true)
private Float money;
// 此字段类型为 keyword, 即需要输入完整 keyword, 才会找到对应文档
@Field(store = true, type = FieldType.Keyword)
private String sign;
@Field(store = true)
private String description;
}
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class ESTest {
@Autowired
private ElasticsearchTemplate esTemplate;
// 修改文档
@Test
public void updateStuDoc() {
// 使用 Map存储文档内容(ES的一个文档, 相当于Mysql 的一个记录)
Map sourceMap = new HashMap<>();
sourceMap.put("sign", "I am not super man");
sourceMap.put("money", 99.8f);
sourceMap.put("age", 33);
IndexRequest indexRequest = new IndexRequest();
indexRequest.source(sourceMap); // 文档内容封装在 map中
UpdateQuery updateQuery = new UpdateQueryBuilder() // 修改文档
.withClass(Stu.class) // 指定索引
.withId("1002") // 指定索引库 id
.withIndexRequest(indexRequest)
.build();
esTemplate.update(updateQuery);
}
// 获取文档信息
@Test
public void getStuDoc() {
GetQuery query = new GetQuery();
query.setId("1002"); // 指定查找的索引 id
Stu stu = esTemplate.queryForObject(query, Stu.class); // 把一个文档和实体类作映射
System.out.println(stu);
}
@Test
public void deleteStuDoc() { //删除指定文档
esTemplate.delete(Stu.class, "1002");
}
// 分页
@Test
public void searchStuDoc() {
Pageable pageable = PageRequest.of(0, 3); // 指定页码(0开始), 和每页文档数
SearchQuery query = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.matchQuery("description", "I'm")) // 附加查询条件(查询字段以及 keyword)
.withPageable(pageable) // 附加分页信息
.build();
// 执行分页查询
AggregatedPage pagedStu = esTemplate.queryForPage(query, Stu.class);
System.out.println("检索后的总分页数目为:" + pagedStu.getTotalPages());
// 获取分页数据
List stuList = pagedStu.getContent();
for (Stu s : stuList) {
System.out.println(s);
}
}
// 获取高亮数据
@Test
public void highlightStuDoc() {
String preTag = "";
String postTag = "";
Pageable pageable = PageRequest.of(0, 10);
SortBuilder sortBuilder = new FieldSortBuilder("money")
.order(SortOrder.ASC); // 设定 "money" 字段, 顺序排序
SortBuilder sortBuilderAge = new FieldSortBuilder("age")
.order(SortOrder.ASC); // 设定 "age" 字段, 顺序排序(因为"money"在前, 所以"money" 优先)
SearchQuery query = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.matchQuery("description", "a")) // 设定查询条件
.withHighlightFields(new HighlightBuilder.Field("description") // 设定高亮属性和格式
.preTags(preTag)
.postTags(postTag))
.withSort(sortBuilder) // 设定排序规则
.withSort(sortBuilderAge)
.withPageable(pageable) // 设置分页条件
.build();
AggregatedPage pagedStu = esTemplate.queryForPage(query, Stu.class, new SearchResultMapper() {
@Override
public AggregatedPage mapResults(SearchResponse response, Class clazz, Pageable pageable) {
List stuListHighlight = new ArrayList<>();
SearchHits hits = response.getHits(); // 获取命中文档
for (SearchHit h : hits) {
HighlightField highlightField = h.getHighlightFields().get("description");
// 获得高亮字段的文本
String description = highlightField.getFragments()[0].toString();
// 非高亮字段值, 从命中文档中获得
Object stuId = (Object)h.getSourceAsMap().get("stuId");
String name = (String)h.getSourceAsMap().get("name");
Integer age = (Integer)h.getSourceAsMap().get("age");
String sign = (String)h.getSourceAsMap().get("sign");
Object money = (Object)h.getSourceAsMap().get("money");
Stu stuHL = new Stu();
stuHL.setDescription(description);
stuHL.setStuId(Long.valueOf(stuId.toString()));
stuHL.setName(name);
stuHL.setAge(age);
stuHL.setSign(sign);
stuHL.setMoney(Float.valueOf(money.toString()));
stuListHighlight.add(stuHL);
}
if (stuListHighlight.size() > 0) {
return new AggregatedPageImpl<>((List)stuListHighlight);
}
return null;
}
});
System.out.println("检索后的总分页数目为:" + pagedStu.getTotalPages());
List stuList = pagedStu.getContent();
for (Stu s : stuList) {
System.out.println(s);
}
}
}
尤其需要注意的是, 设置高亮后, 如果不使用 SearchResponse, 获得命中文档, 是无法显示高亮的