diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8f7e7ba --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea +/target +/src/test \ No newline at end of file diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml index 8b2b496..eb1de1b 100644 --- a/.idea/dataSources.xml +++ b/.idea/dataSources.xml @@ -15,5 +15,17 @@ $ProjectFileDir$ + + postgresql + true + org.postgresql.Driver + jdbc:postgresql://192.168.249.131:5432/postgres + + + + + + $ProjectFileDir$ + \ No newline at end of file diff --git a/.idea/git_toolbox_prj.xml b/.idea/git_toolbox_prj.xml new file mode 100644 index 0000000..02b915b --- /dev/null +++ b/.idea/git_toolbox_prj.xml @@ -0,0 +1,15 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml index abb532a..cf3be90 100644 --- a/.idea/jarRepositories.xml +++ b/.idea/jarRepositories.xml @@ -1,6 +1,11 @@ + + + + \ No newline at end of file diff --git a/src/main/java/cn/itcast/hotel/HotelDemoApplication.java b/src/main/java/cn/itcast/hotel/HotelDemoApplication.java index 518760e..6070f5b 100644 --- a/src/main/java/cn/itcast/hotel/HotelDemoApplication.java +++ b/src/main/java/cn/itcast/hotel/HotelDemoApplication.java @@ -1,13 +1,14 @@ package cn.itcast.hotel; -import com.baomidou.mybatisplus.annotation.DbType; -import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; -import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import org.apache.http.HttpHost; +import org.elasticsearch.client.RestClient; +import org.elasticsearch.client.RestHighLevelClient; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; + @MapperScan("cn.itcast.hotel.mapper") @SpringBootApplication public class HotelDemoApplication { @@ -16,4 +17,11 @@ public class HotelDemoApplication { SpringApplication.run(HotelDemoApplication.class, args); } + @Bean + public RestHighLevelClient restHighLevelClient() { + return new RestHighLevelClient(RestClient.builder( + HttpHost.create("http://192.168.249.131:9200") + )); + } + } diff --git a/src/main/java/cn/itcast/hotel/controller/HotelController.java b/src/main/java/cn/itcast/hotel/controller/HotelController.java new file mode 100644 index 0000000..3b7f553 --- /dev/null +++ b/src/main/java/cn/itcast/hotel/controller/HotelController.java @@ -0,0 +1,24 @@ +package cn.itcast.hotel.controller; + +import cn.itcast.hotel.pojo.PageResult; +import cn.itcast.hotel.pojo.RequestParams; +import cn.itcast.hotel.service.IHotelService; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +@RestController +@RequestMapping("/hotel") +public class HotelController { + + @Resource + private IHotelService hotelService; + + @PostMapping("/list") + public PageResult search(@RequestBody RequestParams requestParams) { + return hotelService.search(requestParams); + } +} diff --git a/src/main/java/cn/itcast/hotel/pojo/HotelDoc.java b/src/main/java/cn/itcast/hotel/pojo/HotelDoc.java index 4d393b9..1d84b38 100644 --- a/src/main/java/cn/itcast/hotel/pojo/HotelDoc.java +++ b/src/main/java/cn/itcast/hotel/pojo/HotelDoc.java @@ -17,6 +17,8 @@ public class HotelDoc { private String business; private String location; private String pic; + private Object distance; + private Boolean isAd; public HotelDoc(Hotel hotel) { this.id = hotel.getId(); diff --git a/src/main/java/cn/itcast/hotel/pojo/PageResult.java b/src/main/java/cn/itcast/hotel/pojo/PageResult.java new file mode 100644 index 0000000..9e3637a --- /dev/null +++ b/src/main/java/cn/itcast/hotel/pojo/PageResult.java @@ -0,0 +1,15 @@ +package cn.itcast.hotel.pojo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class PageResult { + private Long total; + private List hotelList; +} diff --git a/src/main/java/cn/itcast/hotel/pojo/RequestParams.java b/src/main/java/cn/itcast/hotel/pojo/RequestParams.java new file mode 100644 index 0000000..0c1932d --- /dev/null +++ b/src/main/java/cn/itcast/hotel/pojo/RequestParams.java @@ -0,0 +1,17 @@ +package cn.itcast.hotel.pojo; + +import lombok.Data; + +@Data +public class RequestParams { + private String key; + private Integer page; + private Integer size; + private String sortBy; + private String city; + private String brand; + private String starName; + private Integer minPrice; + private Integer maxPrice; + private String location; +} diff --git a/src/main/java/cn/itcast/hotel/service/IHotelService.java b/src/main/java/cn/itcast/hotel/service/IHotelService.java index d4ab356..297efe5 100644 --- a/src/main/java/cn/itcast/hotel/service/IHotelService.java +++ b/src/main/java/cn/itcast/hotel/service/IHotelService.java @@ -1,7 +1,10 @@ package cn.itcast.hotel.service; import cn.itcast.hotel.pojo.Hotel; +import cn.itcast.hotel.pojo.PageResult; +import cn.itcast.hotel.pojo.RequestParams; import com.baomidou.mybatisplus.extension.service.IService; public interface IHotelService extends IService { + PageResult search(RequestParams requestParams); } diff --git a/src/main/java/cn/itcast/hotel/service/impl/HotelService.java b/src/main/java/cn/itcast/hotel/service/impl/HotelService.java index 5a312ac..b035d8a 100644 --- a/src/main/java/cn/itcast/hotel/service/impl/HotelService.java +++ b/src/main/java/cn/itcast/hotel/service/impl/HotelService.java @@ -2,10 +2,96 @@ package cn.itcast.hotel.service.impl; import cn.itcast.hotel.mapper.HotelMapper; import cn.itcast.hotel.pojo.Hotel; +import cn.itcast.hotel.pojo.HotelDoc; +import cn.itcast.hotel.pojo.PageResult; +import cn.itcast.hotel.pojo.RequestParams; import cn.itcast.hotel.service.IHotelService; +import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.elasticsearch.action.search.SearchRequest; +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.client.RequestOptions; +import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.common.geo.GeoPoint; +import org.elasticsearch.common.unit.DistanceUnit; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.search.SearchHit; +import org.elasticsearch.search.sort.SortBuilders; +import org.elasticsearch.search.sort.SortOrder; import org.springframework.stereotype.Service; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; + +import javax.annotation.Resource; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; @Service public class HotelService extends ServiceImpl implements IHotelService { + + @Resource + private RestHighLevelClient client; + + @Override + public PageResult search(RequestParams params) { + SearchRequest request = new SearchRequest("hotel"); + BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); + + paramCheck(params, boolQuery); + + Integer page = params.getPage(); + Integer size = params.getSize(); + request.source().from((page - 1) * size).size(size); + if (StringUtils.isEmpty(params.getLocation())) { + request.source().sort(SortBuilders + .geoDistanceSort("location", new GeoPoint(params.getLocation())) + .order(SortOrder.ASC) + .unit(DistanceUnit.KILOMETERS) + ); + } + try { + SearchResponse response = client.search(request, RequestOptions.DEFAULT); + return handleResponse(response); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private void paramCheck(RequestParams params, BoolQueryBuilder boolQuery) { + if (StringUtils.isEmpty(params.getKey())) { + boolQuery.must(QueryBuilders.matchAllQuery()); + } else { + boolQuery.must(QueryBuilders.matchQuery("all", params.getKey())); + } + + if (StringUtils.isEmpty(params.getCity())) { + boolQuery.filter(QueryBuilders.termQuery("city", params.getCity())); + } + + if (StringUtils.isEmpty(params.getStarName())) { + boolQuery.filter(QueryBuilders.termQuery("city", params.getSize())); + } + + if (params.getMinPrice() != null && params.getMaxPrice() != null) { + boolQuery.filter(QueryBuilders.rangeQuery("price").gte(params.getMinPrice()).lte(params.getMaxPrice())); + } + } + + private PageResult handleResponse(SearchResponse response) throws IOException { + + SearchHit[] searchHits = response.getHits().getHits(); + long total = response.getHits().getTotalHits().value; + List hotelDocList = new ArrayList<>(); + for (SearchHit searchHit : searchHits) { + String source = searchHit.getSourceAsString(); + HotelDoc hotelDoc = JSON.parseObject(source, HotelDoc.class); + Object[] sortValues = searchHit.getSortValues(); + hotelDoc.setDistance(ObjectUtils.isEmpty(sortValues) ? null : sortValues[0]); + + hotelDocList.add(hotelDoc); + } + return new PageResult(total, hotelDocList); + } } diff --git a/src/test/java/cn/itcast/hotel/HotelDocumentTest.java b/src/test/java/cn/itcast/hotel/HotelDocumentTest.java index bf7f8e0..83e51be 100644 --- a/src/test/java/cn/itcast/hotel/HotelDocumentTest.java +++ b/src/test/java/cn/itcast/hotel/HotelDocumentTest.java @@ -21,7 +21,9 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import javax.annotation.Resource; import java.io.IOException; +import java.util.ArrayList; import java.util.List; @SpringBootTest @@ -29,84 +31,63 @@ class HotelDocumentTest { private RestHighLevelClient client; - @Autowired + @Resource private IHotelService hotelService; @Test void testAddDocument() throws IOException { - // 1.查询数据库hotel数据 - Hotel hotel = hotelService.getById(61083L); - // 2.转换为HotelDoc + Hotel hotel = hotelService.getById(56227L); HotelDoc hotelDoc = new HotelDoc(hotel); - // 3.转JSON - String json = JSON.toJSONString(hotelDoc); - - // 1.准备Request - IndexRequest request = new IndexRequest("hotel").id(hotelDoc.getId().toString()); - // 2.准备请求参数DSL,其实就是文档的JSON字符串 - request.source(json, XContentType.JSON); - // 3.发送请求 + IndexRequest request = new IndexRequest("hotel").id(hotel.getId().toString()); + request.source(JSON.toJSONString(hotelDoc), XContentType.JSON); + // 发送请求 client.index(request, RequestOptions.DEFAULT); } @Test - void testGetDocumentById() throws IOException { - // 1.准备Request // GET /hotel/_doc/{id} - GetRequest request = new GetRequest("hotel", "61083"); - // 2.发送请求 + void testGetDocument() throws IOException { + GetRequest request = new GetRequest("hotel", "56227"); GetResponse response = client.get(request, RequestOptions.DEFAULT); - // 3.解析响应结果 - String json = response.getSourceAsString(); - - HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class); - System.out.println("hotelDoc = " + hotelDoc); + String source = response.getSourceAsString(); + HotelDoc hotel = JSON.parseObject(source, HotelDoc.class); + System.out.println("hotel = " + hotel); } @Test - void testDeleteDocumentById() throws IOException { - // 1.准备Request // DELETE /hotel/_doc/{id} - DeleteRequest request = new DeleteRequest("hotel", "61083"); - // 2.发送请求 - client.delete(request, RequestOptions.DEFAULT); - } - - @Test - void testUpdateById() throws IOException { - // 1.准备Request - UpdateRequest request = new UpdateRequest("hotel", "61083"); - // 2.准备参数 - request.doc( - "price", "870" + void testUpdateDocument() throws IOException { + UpdateRequest updateRequest = new UpdateRequest("hotel", "56227"); + updateRequest.doc( + "price", "999", + "starName", "四钻" ); - // 3.发送请求 - client.update(request, RequestOptions.DEFAULT); + client.update(updateRequest, RequestOptions.DEFAULT); } @Test - void testBulkRequest() throws IOException { - // 查询所有的酒店数据 - List list = hotelService.list(); + void testDeleteDocument() throws IOException { + DeleteRequest deleteRequest = new DeleteRequest("hotel", "56227"); + client.delete(deleteRequest, RequestOptions.DEFAULT); + } - // 1.准备Request - BulkRequest request = new BulkRequest(); - // 2.准备参数 - for (Hotel hotel : list) { - // 2.1.转为HotelDoc + + @Test + void testBulkDocument() throws IOException { + BulkRequest bulkRequest = new BulkRequest(); + List hotelList = hotelService.list(); + for (Hotel hotel : hotelList) { HotelDoc hotelDoc = new HotelDoc(hotel); - // 2.2.转json - String json = JSON.toJSONString(hotelDoc); - // 2.3.添加请求 - request.add(new IndexRequest("hotel").id(hotel.getId().toString()).source(json, XContentType.JSON)); + bulkRequest.add(new IndexRequest("hotel") + .id(hotelDoc.getId().toString()) + .source(JSON.toJSONString(hotelDoc), XContentType.JSON)); } + client.bulk(bulkRequest, RequestOptions.DEFAULT); - // 3.发送请求 - client.bulk(request, RequestOptions.DEFAULT); } @BeforeEach void setUp() { client = new RestHighLevelClient(RestClient.builder( - HttpHost.create("http://192.168.150.101:9200") + HttpHost.create("http://192.168.249.131:9200") )); } diff --git a/src/test/java/cn/itcast/hotel/HotelQueryTest.java b/src/test/java/cn/itcast/hotel/HotelQueryTest.java new file mode 100644 index 0000000..caf5dea --- /dev/null +++ b/src/test/java/cn/itcast/hotel/HotelQueryTest.java @@ -0,0 +1,126 @@ +package cn.itcast.hotel; + +import cn.itcast.hotel.pojo.Hotel; +import cn.itcast.hotel.pojo.HotelDoc; +import com.alibaba.fastjson.JSON; +import org.apache.http.HttpHost; +import org.elasticsearch.action.search.SearchRequest; +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.client.RequestOptions; +import org.elasticsearch.client.RestClient; +import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.common.text.Text; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.search.SearchHit; +import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder; +import org.elasticsearch.search.fetch.subphase.highlight.HighlightField; +import org.elasticsearch.search.sort.SortOrder; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.BeanUtils; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.util.CollectionUtils; + +import java.io.IOException; +import java.util.Map; + +@SpringBootTest +public class HotelQueryTest { + private RestHighLevelClient client; + + @Test + void testMatchAll() throws IOException { +// 准备Request + SearchRequest request = new SearchRequest("hotel"); +// 准备DSL + request.source().query(QueryBuilders.matchAllQuery()); +// 发送请求 + handleResponse(request); + } + + @Test + void testMatch() throws IOException { +// 准备Request + SearchRequest request = new SearchRequest("hotel"); +// 准备DSL + request.source().query(QueryBuilders.matchQuery("all", "如家")); + handleResponse(request); + } + + @Test + void testTerm() throws IOException { + SearchRequest request = new SearchRequest("hotel"); + request.source().query(QueryBuilders.termQuery("city", "成都")); + handleResponse(request); + } + + @Test + void testBoolean() throws IOException { + SearchRequest request = new SearchRequest("hotel"); + BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); + boolQueryBuilder.must().add(QueryBuilders.termQuery("city", "上海")); + boolQueryBuilder.filter().add(QueryBuilders.rangeQuery("price").lte(999)); + handleResponse(request); + } + + @Test + void testPageAndSort() throws IOException { + SearchRequest request = new SearchRequest("hotel"); + int page = 2; + int pageSize = 5; + request.source().query(QueryBuilders.matchAllQuery()); + request.source().sort("price", SortOrder.ASC); + request.source().from((page - 1) * pageSize).size(pageSize); + handleResponse(request); + } + + + @Test + void testHighlight() throws IOException { + SearchRequest request = new SearchRequest("hotel"); + request.source().query(QueryBuilders.matchQuery("all", "如家")); + request.source().highlighter(new HighlightBuilder().field("name").requireFieldMatch(false)); + handleResponse(request); + } + + private void handleResponse(SearchRequest request) throws IOException { + // 发送请求 + SearchResponse response = client.search(request, RequestOptions.DEFAULT); + SearchHit[] searchHits = response.getHits().getHits(); + + for (SearchHit searchHit : searchHits) { + String source = searchHit.getSourceAsString(); + Map highlightFields = searchHit.getHighlightFields(); + if (!CollectionUtils.isEmpty(highlightFields)) { + HighlightField field = highlightFields.get("name"); + Text[] texts = field.getFragments(); + System.out.println(texts[0].string()); + } + HotelDoc hotelDoc = JSON.parseObject(source, HotelDoc.class); + Hotel hotel = new Hotel(); + BeanUtils.copyProperties(hotelDoc, hotel); + String[] location = hotelDoc.getLocation().split(","); + hotel.setLatitude(location[0]); + hotel.setLongitude(location[1]); + System.out.println(hotel); + } + } + + + + + + @BeforeEach + void setUp() { + client = new RestHighLevelClient(RestClient.builder( + HttpHost.create("http://192.168.249.131:9200") + )); + } + + @AfterEach + void tearDown() throws IOException { + client.close(); + } +}