快速入门
返回结果直接把json风格的结果封装为SearchReponse对象返回
public class HotelSearchTest {
private RestHighLevelClient client;
@Test
void testMatchAll() throws IOException {
//1.准备request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSl
request.source().query(QueryBuilders.matchAllQuery());
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
System.out.println(response);
}
//执行前初始化
@BeforeEach
void setUp(){
this.client=new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://xxx.xxx.xxx.xxx:9200")
//HttpHost.create("http://xxx.xxx.xxx.xxx:9200") 集群时添加更多的地址
));
}
//销毁
@AfterEach
void tearDown() throws IOException {
this.client.close();
}
}
响应结果解析
@Test
void testMatchAll() throws IOException {
//1.准备request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSl
request.source().query(QueryBuilders.matchAllQuery());
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//4.解析响应
SearchHits searchHits = response.getHits();
//4.1获取总条数
long total = searchHits.getTotalHits().value;
System.out.println("共搜索到"+total+"条数据");
//4.2文档数组
SearchHit[] hits = searchHits.getHits();
//4.3遍历
for (SearchHit hit : hits) {
//获取文档source
String json = hit.getSourceAsString();
//反序列化
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
System.out.println("hotelDoc="+hotelDoc);
}
}
默认只返回前10条数据
在.source()中query,排序,分页,高亮等功能
QueryBuildes中准备了所有查询,match,match_all,boolean等
match、term、range、bool查询
全文检索查询
@Test
void testMatch() throws IOException {
//1.准备request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSl
request.source().query(QueryBuilders.matchQuery("all","如家"));
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//4.解析响应
SearchHits searchHits = response.getHits();
//4.1获取总条数
long total = searchHits.getTotalHits().value;
System.out.println("共搜索到"+total+"条数据");
//4.2文档数组
SearchHit[] hits = searchHits.getHits();
//4.3遍历
for (SearchHit hit : hits) {
//获取文档source
String json = hit.getSourceAsString();
//反序列化
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
System.out.println("hotelDoc="+hotelDoc);
}
}
对比match和match_all,不同的地方只有一点点,这里直接抽取4往后的公共部分,使用ctrl+alt+m抽取
public class HotelSearchTest {
private RestHighLevelClient client;
@Test
void testMatchAll() throws IOException {
//1.准备request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSl
request.source().query(QueryBuilders.matchAllQuery());
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
handleResponse(response);
}
@Test
void testMatch() throws IOException {
//1.准备request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSl
request.source().query(QueryBuilders.matchQuery("all","如家"));
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
handleResponse(response);
}
private static void handleResponse(SearchResponse response) {
//4.解析响应
SearchHits searchHits = response.getHits();
//4.1获取总条数
long total = searchHits.getTotalHits().value;
System.out.println("共搜索到"+total+"条数据");
//4.2文档数组
SearchHit[] hits = searchHits.getHits();
//4.3遍历
for (SearchHit hit : hits) {
//获取文档source
String json = hit.getSourceAsString();
//反序列化
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
System.out.println("hotelDoc="+hotelDoc);
}
}
//执行前初始化
@BeforeEach
void setUp(){
this.client=new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://xxx.xxx.xxx.xxx:9200")
//HttpHost.create("http://xxx.xxx.xxx.xxx:9200") 集群时添加更多的地址
));
}
//销毁
@AfterEach
void tearDown() throws IOException {
this.client.close();
}
}
精确查询
一个boolean查询里面包含了term查询和 range查询
@Test
void testBool() throws IOException {
//1.准备request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSl
//2.1准备BooleanQuery
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
//2.2添加term
boolQuery.must(QueryBuilders.termQuery("city","上海"));
//2.3添加range
boolQuery.filter(QueryBuilders.rangeQuery("price").lte(250));
request.source().query(boolQuery);
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
handleResponse(response);
}
排序和分页
@Test
void testPageAndSort() throws IOException {
//前端传来页码,每页大小
int page=1,size=5;
//1.准备request
SearchRequest request = new SearchRequest("hotel");
//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 = client.search(request, RequestOptions.DEFAULT);
handleResponse(response);
}
高亮
构建
@Test
void testHighlight() throws IOException {
//1.准备request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSl
//2.1准备query
request.source().query(QueryBuilders.matchQuery("all","如家"));
//2.2高亮
request.source().highlighter(new HighlightBuilder().field("name").requireFieldMatch(false));
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//4.解析响应
handleResponse(response);
}
解析
逐层解析json结果
@Test
void testHighlight() throws IOException {
//1.准备request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSl
//2.1准备query
request.source().query(QueryBuilders.matchQuery("all","如家"));
//2.2高亮
request.source().highlighter(new HighlightBuilder().field("name").requireFieldMatch(false));
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//4.解析响应
handleResponse(response);
}
private static void handleResponse(SearchResponse response) {
//4.解析响应
SearchHits searchHits = response.getHits();
//4.1获取总条数
long total = searchHits.getTotalHits().value;
System.out.println("共搜索到"+total+"条数据");
//4.2文档数组
SearchHit[] hits = searchHits.getHits();
//4.3遍历
for (SearchHit hit : hits) {
//获取文档source
String json = hit.getSourceAsString();
//反序列化
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
//获取高亮结果
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
if(!CollectionUtils.isEmpty(highlightFields)) //判断map是否为空的工具类
{
//根据名字获取高亮结果
HighlightField highlightField = highlightFields.get("name");
if(highlightField!=null){
//获取高亮值
String name = highlightField.getFragments()[0].string();
//覆盖非高亮结果
hotelDoc.setName(name);
}
}
System.out.println("hotelDoc="+hotelDoc);
}
}
黑马旅游案例——酒店搜索和分页
定义实体类
用于接收前端传来的参数
@Data
public class RequestParams {
private String key;
private Integer page;
private Integer size;
private String sortBy;
}
Controller层中
返回值定义
@Data
public class PageResult {
private Long total;
private List<HotelDoc> hotels;
public PageResult() {
}
public PageResult(Long total, List<HotelDoc> hotels) {
this.total = total;
this.hotels = hotels;
}
}
在启动类中定义一个Bean
@MapperScan("cn.itcast.hotel.mapper")
@SpringBootApplication
public class HotelDemoApplication {
public static void main(String[] args) {
SpringApplication.run(HotelDemoApplication.class, args);
}
@Bean
public RestHighLevelClient client(){
return new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://xxx.xxx.xxx.xxx:9200")
//HttpHost.create("http://xxx.xxx.xxx.xxx:9200") 集群时添加更多的地址
));
}
}
@RestController
@RequestMapping("hotel")
public class HotelController {
@Autowired
private IHotelService hotelService;
/**
* 搜索和分页
* @param requestParams
* @return
*/
@PostMapping("/list")
public PageResult search(@RequestBody RequestParams requestParams){
return hotelService.search(requestParams);
}
}
Service层中
public interface IHotelService extends IService<Hotel> {
PageResult search(RequestParams requestParams);
}
@Service
public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {
@Autowired
private RestHighLevelClient client;
@Override
public PageResult search(RequestParams requestParams) {
try {
//1.准备request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSl
//2.1query
String key= requestParams.getKey();
if(key==null||"".equals(key)){ //没有查询内容时直接查询全部
request.source().query(QueryBuilders.matchAllQuery());
}else {
request.source().query(QueryBuilders.matchQuery("all", key));
}
//2.2分页
int page=requestParams.getPage();
int size=requestParams.getSize();
request.source().from((page-1)*size).size(size);
//3.发送请求
SearchResponse response= client.search(request, RequestOptions.DEFAULT);
//4.解析响应
handleResponse(response);
return null;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private PageResult handleResponse(SearchResponse response) {
//4.解析响应
SearchHits searchHits = response.getHits();
//4.1获取总条数
long total = searchHits.getTotalHits().value;
System.out.println("共搜索到"+total+"条数据");
//4.2文档数组
SearchHit[] hits = searchHits.getHits();
//4.3遍历
List<HotelDoc> hotels=new ArrayList<>();
for (SearchHit hit : hits) {
//获取文档source
String json = hit.getSourceAsString();
//反序列化
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
hotels.add(hotelDoc);
}
return new PageResult(total,hotels);
}
}
成功搜索
黑马旅游案例——条件过滤
修改DTO
@Data
public class RequestParams {
private String key;
private Integer page;
private Integer size;
private String sortBy;
private String brand;
private String starName;
private String city;
private Integer minPrice;
private Integer maxPrice;
}
Service层中
修改如下,加了多条件过滤,并抽取出去
@Override
public PageResult search(RequestParams requestParams) {
try {
//1.准备request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSl
//2.1query
buildBasicQuery(requestParams, request);
//2.2分页
int page=requestParams.getPage();
int size=requestParams.getSize();
request.source().from((page-1)*size).size(size);
//3.发送请求
SearchResponse response= client.search(request, RequestOptions.DEFAULT);
//4.解析响应
return handleResponse(response);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static void buildBasicQuery(RequestParams requestParams, SearchRequest request) {
//构建BooleanQuery
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
//关键字搜索
String key= requestParams.getKey();
if(key==null||"".equals(key)){ //没有查询内容时直接查询全部
boolQuery.must(QueryBuilders.matchAllQuery());
}else {
boolQuery.must(QueryBuilders.matchQuery("all", key));
}
//城市条件
if(requestParams.getCity()!=null&&!requestParams.getCity().equals("")){
boolQuery.filter(QueryBuilders.termQuery("city", requestParams.getCity()));
}
//品牌条件
if(requestParams.getBrand()!=null&&!requestParams.getBrand().equals("")){
boolQuery.filter(QueryBuilders.termQuery("brand", requestParams.getBrand()));
}
//星级条件
if(requestParams.getStarName()!=null&&!requestParams.getStarName().equals("")){
boolQuery.filter(QueryBuilders.termQuery("starName", requestParams.getStarName()));
}
//价格条件
if(requestParams.getMinPrice()!=null&& requestParams.getMaxPrice()!=null){
boolQuery.filter(QueryBuilders.rangeQuery("price")
.gte(requestParams.getMinPrice())
.lte(requestParams.getMaxPrice()));
}
request.source().query(boolQuery);
}
黑马旅游案例——我附近的酒店
距离排序
DTO修改
@Data
public class RequestParams {
private String key;
private Integer page;
private Integer size;
private String sortBy;
private String brand;
private String starName;
private String city;
private Integer minPrice;
private Integer maxPrice;
private String location;
}
Service中
修改如下
新增2.3部分
@Override
public PageResult search(RequestParams requestParams) {
try {
//1.准备request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSl
//2.1query
buildBasicQuery(requestParams, request);
//2.2分页
int page=requestParams.getPage();
int size=requestParams.getSize();
request.source().from((page-1)*size).size(size);
//2.3排序
String location = requestParams.getLocation();
if(location!=null&&!location.equals("")){
request.source().sort(SortBuilders
.geoDistanceSort("location",new GeoPoint(location))
.order(SortOrder.ASC)
.unit(DistanceUnit.KILOMETERS)
);
}
//3.发送请求
SearchResponse response= client.search(request, RequestOptions.DEFAULT);
//4.解析响应
return handleResponse(response);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
DTO修改
@Data
@NoArgsConstructor
public class HotelDoc {
private Long id;
private String name;
private String address;
private Integer price;
private Integer score;
private String brand;
private String city;
private String starName;
private String business;
private String location;
private String pic;
private Object distance;
public HotelDoc(Hotel hotel) {
this.id = hotel.getId();
this.name = hotel.getName();
this.address = hotel.getAddress();
this.price = hotel.getPrice();
this.score = hotel.getScore();
this.brand = hotel.getBrand();
this.city = hotel.getCity();
this.starName = hotel.getStarName();
this.business = hotel.getBusiness();
this.location = hotel.getLatitude() + ", " + hotel.getLongitude();
this.pic = hotel.getPic();
}
}
Service修改
private PageResult handleResponse(SearchResponse response) {
//4.解析响应
SearchHits searchHits = response.getHits();
//4.1获取总条数
long total = searchHits.getTotalHits().value;
System.out.println("共搜索到"+total+"条数据");
//4.2文档数组
SearchHit[] hits = searchHits.getHits();
//4.3遍历
List<HotelDoc> hotels=new ArrayList<>();
for (SearchHit hit : hits) {
//获取文档source
String json = hit.getSourceAsString();
//反序列化
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
//获取排序值
Object[] sortValues = hit.getSortValues();
if(sortValues.length>0){
Object sortValue = sortValues[0];
hotelDoc.setDistance(sortValue);
}
hotels.add(hotelDoc);
}
return new PageResult(total,hotels);
}
这里应该成功显示距离附近酒店以及距离了,但是我的电脑获取不到位置。
黑马旅游案例——广告置顶
DTO修改
在HotelDoc中添加一个新字段
private Boolean isAD;
ES数据修改
Service层修改
private static void buildBasicQuery(RequestParams requestParams, SearchRequest request) {
//1.构建BooleanQuery
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
//关键字搜索
String key= requestParams.getKey();
if(key==null||"".equals(key)){ //没有查询内容时直接查询全部
boolQuery.must(QueryBuilders.matchAllQuery());
}else {
boolQuery.must(QueryBuilders.matchQuery("all", key));
}
//城市条件
if(requestParams.getCity()!=null&&!requestParams.getCity().equals("")){
boolQuery.filter(QueryBuilders.termQuery("city", requestParams.getCity()));
}
//品牌条件
if(requestParams.getBrand()!=null&&!requestParams.getBrand().equals("")){
boolQuery.filter(QueryBuilders.termQuery("brand", requestParams.getBrand()));
}
//星级条件
if(requestParams.getStarName()!=null&&!requestParams.getStarName().equals("")){
boolQuery.filter(QueryBuilders.termQuery("starName", requestParams.getStarName()));
}
//价格条件
if(requestParams.getMinPrice()!=null&& requestParams.getMaxPrice()!=null){
boolQuery.filter(QueryBuilders.rangeQuery("price")
.gte(requestParams.getMinPrice())
.lte(requestParams.getMaxPrice()));
}
//2.算分控制
FunctionScoreQueryBuilder functionScoreQueryBuilder =
QueryBuilders.functionScoreQuery(
//原始查询,相关性算分的查询
boolQuery,
//function score的数组
new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
//其中的一个function score 元素
new FunctionScoreQueryBuilder.FilterFunctionBuilder(
//过滤条件
QueryBuilders.termQuery("isAD",true),
//算分函数
ScoreFunctionBuilders.weightFactorFunction(10)
)
});
request.source().query(functionScoreQueryBuilder);
}
最终查询时就可以看见置顶的广告了