查询的基本步骤:
1)创建SearchRequest对象
2)准备Request.source(),QueryBuilders来构建查询条件,传入Request.source()的query()方法
3)发送请求,得到结果
4)解析结果
void testMatchAll() throws IOException {
//准备请求
SearchRequest request = new SearchRequest("hotel");
//准备DSL
request.source().query(QueryBuilders.matchAllQuery());
//发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//解析响应
SearchHits searchHits=response.getHits();
//获取总条数
long total = searchHits.getTotalHits().value;
System.out.println("一共搜索到"+total);
SearchHit[] hits = searchHits.getHits();
for (SearchHit hit : hits) {
String json = hit.getSourceAsString();
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
System.out.println(hotelDoc);
}
}
步骤:1)定义实体类,接收前端请求
2)定义controller接口,接收前端页面请求,调用IHotelService的search方法
3)定义IHotelService中的search方法,利用match查询实现根据关键字搜索酒店信息
从网络的请求来看,前端会传给后端四个数据,分别是key、page、size、sortBy
因此我们定义的实体类如下,用来接收前端参数。
@Data
public class RequestParams {
private String key;
private Integer page;
private Integer size;
private String sortBy;
}
接下来定义接口,请求方式是POST,请求路径是/hotel/list,请求参数是我们刚刚定义的对象,RequestParams,由于我们要实现分页的效果,因此返回值是PageRequest对象,包含两个属性分别是Long total和List
@Data
@AllArgsConstructor
@NoArgsConstructor
public class RequestParams {
private String key;
private Integer page;
private Integer size;
private String sortBy;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PageResult {
private Long total;
private List hotels;
}
第二步就是定义controller接口了,由于我们之后要用到RestHighLevelClient对象因此我们先写个配置类,一开始就注入client对象在容器中(也可以在启动类写,就是不优雅就对了)。
@Configuration
public class ClientConfig {
@Bean
public RestHighLevelClient client(){
return new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://192.168.31.137:9200")
));
}
}
controller层
@RestController
@RequestMapping("/hotel")
public class HotelController {
@Autowired
private IHotelService hotelService;
@PostMapping("/list")
public PageResult search(@RequestBody RequestParams params) throws IOException {
return hotelService.search(params);
}
}
service层
@Slf4j
@Service
public class HotelService extends ServiceImpl implements IHotelService {
@Autowired
private RestHighLevelClient client;
@Override
public PageResult search(RequestParams params) throws IOException {
//准备请求
SearchRequest request = new SearchRequest("hotel");
//准备DSL
String key =params.getKey();
if(key==null||"".equals(key)){
request.source().query(QueryBuilders.matchAllQuery());
}else {
request.source().query(QueryBuilders.matchQuery("all",key));
}
int page= params.getPage();
int size=params.getSize();
request.source().from((page-1)*size).size(size);
//发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
PageResult pageResult = handleResponse(response);
return pageResult;
}
public PageResult handleResponse(SearchResponse response) {
//解析响应
SearchHits searchHits = response.getHits();
//获取总条数
long total = searchHits.getTotalHits().value;
SearchHit[] hits = searchHits.getHits();
List hotels=new ArrayList<>();
for (SearchHit hit : hits) {
String json = hit.getSourceAsString();
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
hotels.add(hotelDoc);
}
return new PageResult(total,hotels);
}
}
这里有个小问题就是,访问网址时,只有本主机访问才能在前端返回正确的数据,如果使用局域网的其他电脑只要不是本主机就前端就无法正常返回数据。
步骤:1)修改RequestParams类,添加对应的属性
2)修改search方法的实现,在关键字搜索时,如果以上参数存在则对其做过滤
@Override
public PageResult search(RequestParams params) throws IOException {
//准备请求
SearchRequest request = new SearchRequest("hotel");
//准备DSL
String key =params.getKey();
BoolQueryBuilder boolQuery=QueryBuilders.boolQuery();
if(key==null||"".equals(key)){
boolQuery.must(QueryBuilders.matchAllQuery());
}else {
boolQuery.must(QueryBuilders.matchQuery("all",key));
}
if(params.getCity()!=null&&!"".equals(params.getCity())){
boolQuery.filter(QueryBuilders.termQuery("city",params.getCity()));
}
if(params.getBrand()!=null&&!"".equals(params.getBrand())){
boolQuery.filter(QueryBuilders.termQuery("brand",params.getBrand()));
}
if(params.getStarName()!=null&&!"".equals(params.getStarName())){
boolQuery.filter(QueryBuilders.termQuery("starName",params.getStarName()));
}
if(params.getMinPrice()!=null&¶ms.getMaxPrice()!=null){
boolQuery.filter(QueryBuilders.rangeQuery("price").gt(params.getMinPrice()).lt(params.getMaxPrice()));
}
request.source().query(boolQuery);
int page= params.getPage();
int size=params.getSize();
request.source().from((page-1)*size).size(size);
//发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
PageResult pageResult = handleResponse(response);
return pageResult;
}
前端页面点击定位后,会将你所在的位置发送到后端,按照接收到的位置按距离进行升序排序。
步骤:1)修改RequestParams参数,添加location字段
2)修改search方法,如果location有值,添加根据geo_distance排序功能
String location=params.getLocation();
if(location!=null&&!"".equals(location)){
request.source().sort(SortBuilders
.geoDistanceSort("location",new GeoPoint(location))
.order(SortOrder.ASC)
.unit(DistanceUnit.KILOMETERS)
);
}
为了让前端页面显示举例,需要对查询到的结果进行处理,将距离添加到hotelDoc对象中,因此也要为该对象添加一个distance属性。
private Object distance;
//解析es查询的结果
Object[] sortValues = hit.getSortValues();
if(sortValues.length>0){
hotelDoc.setDistance(sortValues[0]);
}
hotels.add(hotelDoc);
步骤:1)给HotelDoc类添加isAD字段,Boolean类型
2)挑选几个你喜欢的酒店,给它的文档数据添加isAD字段,值为true
3)修改search方法,添加function score功能,给isAD值为true的酒店增加权重
FunctionScoreQueryBuilder functionScoreQuery=QueryBuilders.functionScoreQuery(boolQuery,
new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
new FunctionScoreQueryBuilder.FilterFunctionBuilder(
QueryBuilders.termQuery("isAd",true),
ScoreFunctionBuilders.weightFactorFunction(10)
)
}
);
request.source().query(functionScoreQuery);