elasticsearch是一款非常强大的开源搜索引擎,具备非常多强大功能,可以帮助我们从海量数据中快速找到需要的内容。
本项目数据库使用的是 MySql ,查询数据使用的是 ElasticSearch
本文章接 SpringBoot ElasticSearch 【SpringBoot系列16】
ES 中的数据查询基本步骤:
- 第一步,创建
SearchRequest
对象,指定索引库名 - 第二步,利用
request.source()
构建DSL,DSL中可以包含查询、分页、排序、高亮等 - 第三步,利用client.search()发送请求,得到响应
- 第四步 解析数据
@SpringBootTest
@RunWith(SpringRunner.class)
@Slf4j
public class ESDocumentTests {
@Resource
RestHighLevelClient restHighLevelClient;
@Test
void testMatchAll() throws IOException {
// 1.准备Request
SearchRequest request = new SearchRequest("order");
// 2.准备DSL
request.source()
.query(QueryBuilders.matchAllQuery());
// 3.发送请求
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 4.解析响应
handleResponse(response);
}
private void handleResponse(SearchResponse response) {
// 4.解析响应
SearchHits searchHits = response.getHits();
// 4.1.获取总条数
long total = searchHits.getTotalHits().value;
log.info("共搜索到" + total + "条数据");
// 4.2.文档数组
SearchHit[] hits = searchHits.getHits();
// 4.3.遍历
for (SearchHit hit : hits) {
// 获取文档source
String json = hit.getSourceAsString();
// 反序列化
Order order = JSON.parseObject(json, Order.class);
log.info("查询到数据 {}",order);
}
}
}
1 精确查询
上述查询中,QueryBuilders.matchAllQuery() 就是查询条件,在这里没有设置任何筛选条件,所以默认返回前10条数据。
request.source()
.query(QueryBuilders.matchAllQuery());
如果要实现精确查询,需要构建查询条件:
@Test
public void testBool() throws IOException {
// 1.准备Request
SearchRequest request = new SearchRequest("order");
// 2.准备DSL
// 2.1.准备BooleanQuery
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
// 2.2.添加term
boolQuery.must(QueryBuilders.termQuery("goodsName", "手机"));
// 2.3.添加range
boolQuery.filter(QueryBuilders.rangeQuery("goodsPrice").lte(250));
//排序
request.source().query(boolQuery);
// 3.发送请求
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 4.解析响应
handleResponse(response);
}
核心就是这里的条件
- term:词条精确匹配
- range:范围查询
// 2.2.添加term
boolQuery.must(QueryBuilders.termQuery("goodsName", "手机"));
// 2.3.添加range
boolQuery.filter(QueryBuilders.rangeQuery("goodsPrice").lte(250));
2 查询结果排序与分页
elasticsearch 在集群模式下,查询TOP1000的数据,例如我集群有5个节点,就必须先查询出每个节点的TOP1000,汇总结果后,重新排名,重新截取TOP1000。
当查询分页深度较大时,汇总数据过多,对内存和CPU会产生非常大的压力,因此elasticsearch会禁止from+ size 超过10000的请求。
@Test
public void testPageAndSort() throws IOException {
// 页码,每页大小
int page = 1, size = 5;
// 1.准备Request
SearchRequest request = new SearchRequest("order");
// 2.准备DSL
// 2.1.query
request.source().query(QueryBuilders.matchAllQuery());
// 2.2.排序 sort
request.source().sort("price", SortOrder.ASC);
// 2.3.分页 from、size
request.source().from((page - 1) * size).size(5);
// 3.发送请求
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 4.解析响应
handleResponse(response);
}
核心代码就是
- sort 排序
- from 分页
// 2.2.排序 sort
request.source().sort("price", SortOrder.ASC);
// 2.3.分页 from、size
request.source().from((page - 1) * size).size(5);
3 本项目实现的 订单分页查询
@Api(tags = "订单模块")
@RestController()
@RequestMapping("/orders")
@Slf4j
public class OrderController {
@Autowired
private OrderService orderService;
/**
* 查询用户所有的订单
*/
@PostMapping("/list")
public PageResult listFromList(@RequestHeader Long userId,
@RequestBody RequestParams params) {
PageResult pageResult = orderService.listFromList(userId,params);
return pageResult;
}
}
PageResult 是分页信息类
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class PageResult {
/**
* 当前页码
*/
private int pageNum;
/**
* 每页数量
*/
private int pageSize;
/**
* 记录总数
*/
private long totalSize;
/**
* 页码总数
*/
private int totalPages;
/**
* 数据模型
*/
private List<?> content;
public PageResult(long total, List<Order> orderList) {
this.content = orderList;
this.totalSize = total;
}
}
RequestParams 是查询条件 ,包括了分页信息以及订单的状态
@Data
@AllArgsConstructor
public class RequestParams implements Serializable {
Integer page;
Integer pageSize;
Integer statues;
}
最后就是实现订单的分页查询
@Resource
RestHighLevelClient restHighLevelClient;
/**
* 分页查询用户的订单
*
* @param userId
* @param params
* @return
*/
@Override
public PageResult listFromList(Long userId, RequestParams params) {
try {
// 1.准备Request
SearchRequest request = new SearchRequest("order");
// 2.准备DSL
// 1.构建BooleanQuery
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
//查询对应用户的
boolQuery.must(QueryBuilders.matchQuery("userId", userId));
//订单状态
if (params.getStatues() != null && params.getStatues()>=0) {
boolQuery.filter(QueryBuilders.termQuery("status", params.getStatues()));
}
// 分页
int page = params.getPage();
int size = params.getPageSize();
request.source().from((page - 1) * size).size(size);
// 3.发送请求
SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
// 4.解析响应
return handleResponse(response);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
// 结果解析
private PageResult handleResponse(SearchResponse response) {
// 4.解析响应
SearchHits searchHits = response.getHits();
// 4.1.获取总条数
long total = searchHits.getTotalHits().value;
// 4.2.文档数组
SearchHit[] hits = searchHits.getHits();
// 4.3.遍历
List<Order> hotels = new ArrayList<>();
for (SearchHit hit : hits) {
// 获取文档source
String json = hit.getSourceAsString();
// 反序列化
Order hotelDoc = JSON.parseObject(json, Order.class);
// 放入集合
hotels.add(hotelDoc);
}
// 4.4.封装返回
return new PageResult(total, hotels);
}
4 订单的其他操作
ES 中查询订单详情
@Override
public Order getOrderDetailFromEs(Long orderId) {
// 创建获取请求对象
GetRequest getRequest = new GetRequest("order", "83");
try {
GetResponse response = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
if(response.isExists()){
log.info("查询到详情 {}",response.getSourceAsString());
Order hotelDoc = JSON.parseObject(response.getSourceAsString(), Order.class);
return hotelDoc;
}else{
log.error("未消查询到详情");
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return null;
}
ES 中修改订单状态
/**
* 更新ES中订单的状态
* @param statues
*/
public void updateOrderStatues(Long orderId,Integer statues) {
// 设置商品更新信息
Order goods = new Order();
goods.setStatus(statues);
// 将对象转为json
String data = JSON.toJSONString(goods);
// 创建索引请求对象
UpdateRequest updateRequest = new UpdateRequest("order", orderId.toString());
// 设置更新文档内容
updateRequest.doc(data, XContentType.JSON);
// 执行更新文档
UpdateResponse response = null;
try {
response = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
} catch (IOException e) {
throw new RuntimeException(e);
}
log.info("更新状态:{}", response.status());
}
ES 中新增一条订单数据
/**
* 下单成功的时候 把数据保存到ES中
* @param order
*/
private void saveOrderToEs(Order order){
// 将对象转为json
String data = JSON.toJSONString(order);
// 创建索引请求对象
// 参数一 索引库名 参数二文档名称
IndexRequest indexRequest = new IndexRequest("order").id(order.getId() + "");
// 准备JSON文档
indexRequest.source(data, XContentType.JSON);
// 执行增加文档
IndexResponse response = null;
try {
response = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
log.info("创建状态:{}", response.status());
} catch (IOException e) {
throw new RuntimeException(e);
}
}