保定專業(yè)做網(wǎng)站的公司最近的國際新聞
文章目錄
- 1.1 索引庫操作
- 1.1.1 創(chuàng)建索引庫 :
- 1.1.2 刪除索引庫 :
- 1.1.3 判斷索引庫是否存在
- 1.2 文檔操作
- 1.2.1 新增文檔
- 1.2.2 查詢文檔
- 1.2.3 刪除文檔
- 1.2.4 修改文檔
- 1.2.5 批量導入文檔
- 1.3 RestClient查詢
- 1.3.1 普通查詢
- 1.3.2 復合條件查詢
- 1.3.3 分頁排序查詢
- 1.3.4 高亮分頁查詢
- 1.3.5 分頁過濾復合查詢
- 1.3.6 處理響應結(jié)果
- 1.4 Mysql和ES數(shù)據(jù)同步
- 1.4.1 引入依賴和配置yml
- 1.4.2 定義交換機隊列名稱( 常量 )
- 1.4.3 聲明和綁定交換機與隊列( 使用注解不需要聲明 )
- 1.4.4 編寫業(yè)務邏輯
1.1 索引庫操作
引入依賴 :
<dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId></dependency>
因為SpringBoot默認的ES版本是
7.17.10
,所以我們需要覆蓋默認的ES版本:
<properties><maven.compiler.source>11</maven.compiler.source><maven.compiler.target>11</maven.compiler.target><elasticsearch.version>7.12.1</elasticsearch.version>
</properties>
初始化
RestClient
:
@Bean
public RestHighLevelClient client(){return new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.164.128:9200")));
}
在啟動類加上如上的代碼初始化client.
結(jié)合數(shù)據(jù)表結(jié)構(gòu)創(chuàng)建索引庫結(jié)構(gòu) :
PUT /items
{"mappings": {"properties": {"id": {"type": "keyword"},"name":{"type": "text","analyzer": "ik_max_word","copy_to": "all"},"price":{"type": "integer"},"stock":{"type": "integer"},"image":{"type": "keyword","index": false},"category":{"type": "keyword","copy_to": "all"},"brand":{"type": "keyword","copy_to": "all"},"sold":{"type": "integer"},"commentCount":{"type": "integer"},"isAD":{"type": "boolean"},"updateTime":{"type": "date"},"all":{"type": "text","analyzer": "ik_max_word"}} }
}
1.1.1 創(chuàng)建索引庫 :
@Test
void testCreateIndex() throws IOException {// 1.創(chuàng)建Request對象CreateIndexRequest request = new CreateIndexRequest("items");// 2.準備請求參數(shù)request.source(MAPPING_TEMPLATE, XContentType.JSON);// 3.發(fā)送請求client.indices().create(request, RequestOptions.DEFAULT);
}// 這個可以放到constants里面
static final String MAPPING_TEMPLATE = "{\n" +" \"mappings\": {\n" +" \"properties\": {\n" +" \"id\": {\n" +" \"type\": \"keyword\"\n" +" },\n" +" \"name\":{\n" +" \"type\": \"text\",\n" +" \"analyzer\": \"ik_max_word\"\n" +" },\n" +" \"price\":{\n" +" \"type\": \"integer\"\n" +" },\n" +" \"stock\":{\n" +" \"type\": \"integer\"\n" +" },\n" +" \"image\":{\n" +" \"type\": \"keyword\",\n" +" \"index\": false\n" +" },\n" +" \"category\":{\n" +" \"type\": \"keyword\"\n" +" },\n" +" \"brand\":{\n" +" \"type\": \"keyword\"\n" +" },\n" +" \"sold\":{\n" +" \"type\": \"integer\"\n" +" },\n" +" \"commentCount\":{\n" +" \"type\": \"integer\"\n" +" },\n" +" \"isAD\":{\n" +" \"type\": \"boolean\"\n" +" },\n" +" \"updateTime\":{\n" +" \"type\": \"date\"\n" +" }\n" +" }\n" +" }\n" +"}";
1.1.2 刪除索引庫 :
@Test
void testDeleteIndex() throws IOException {// 1.創(chuàng)建Request對象DeleteIndexRequest request = new DeleteIndexRequest("items");// 2.發(fā)送請求client.indices().delete(request, RequestOptions.DEFAULT);
}
1.1.3 判斷索引庫是否存在
@Test
void testExistsIndex() throws IOException {// 1.創(chuàng)建Request對象GetIndexRequest request = new GetIndexRequest("items");// 2.發(fā)送請求boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);// 3.輸出System.err.println(exists ? "索引庫已經(jīng)存在!" : "索引庫不存在!");
}
1.2 文檔操作
1.2.1 新增文檔
索引庫結(jié)構(gòu)與數(shù)據(jù)庫結(jié)構(gòu)還存在一些差異,因此我們要定義一個索引庫結(jié)構(gòu)對應的實體
package com.hmall.item.domain.dto;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.time.LocalDateTime;@Data
@ApiModel(description = "索引庫實體")
public class ItemDTO{@ApiModelProperty("商品id")private String id;@ApiModelProperty("商品名稱")private String name;@ApiModelProperty("價格(分)")private Integer price;@ApiModelProperty("庫存數(shù)量")private Integer stock;@ApiModelProperty("商品圖片")private String image;@ApiModelProperty("類目名稱")private String category;@ApiModelProperty("品牌名稱")private String brand;@ApiModelProperty("銷量")private Integer sold;@ApiModelProperty("評論數(shù)")private Integer commentCount;@ApiModelProperty("是否是推廣廣告,true/false")private Boolean isAD;@ApiModelProperty("更新時間")private LocalDateTime updateTime;
}
操作代碼 :
@Test
void testAddDocument() throws IOException {// 1.根據(jù)id查詢商品數(shù)據(jù)Item item = itemService.getById(100002644680L);// 2.轉(zhuǎn)換為文檔類型ItemDTO itemDTO = BeanUtil.copyProperties(item, ItemDTO.class);// 3.將ItemDTO轉(zhuǎn)jsonString doc = JSONUtil.toJsonStr(itemDTO);// 1.準備Request對象IndexRequest request = new IndexRequest("items").id(itemDTO.getId());// 2.準備Json文檔request.source(doc, XContentType.JSON);// 3.發(fā)送請求client.index(request, RequestOptions.DEFAULT);
}
1.2.2 查詢文檔
@Test
void testGetDocumentById() throws IOException {// 1.準備Request對象GetRequest request = new GetRequest("items").id("100002644680");// 2.發(fā)送請求GetResponse response = client.get(request, RequestOptions.DEFAULT);// 3.獲取響應結(jié)果中的sourceString json = response.getSourceAsString();ItemDTO itemDTO = JSONUtil.toBean(json, ItemDTO.class);System.out.println("itemDTO = " + itemDTO);
}
1.2.3 刪除文檔
@Test
void testDeleteDocument() throws IOException {// 1.準備Request,兩個參數(shù),第一個是索引庫名,第二個是文檔idDeleteRequest request = new DeleteRequest("item", "100002644680");// 2.發(fā)送請求client.delete(request, RequestOptions.DEFAULT);
}
1.2.4 修改文檔
@Test
void testUpdateDocument() throws IOException {// 1.準備RequestUpdateRequest request = new UpdateRequest("items", "100002644680");// 2.準備請求參數(shù)request.doc("price", 58800,"commentCount", 1);// 3.發(fā)送請求client.update(request, RequestOptions.DEFAULT);
}
1.2.5 批量導入文檔
@Test
void testBulkRequest() throws IOException {// 批量查詢酒店數(shù)據(jù)List<Hotel> hotels = hotelService.list();// 1.創(chuàng)建RequestBulkRequest request = new BulkRequest();// 2.準備參數(shù),添加多個新增的Requestfor (Hotel hotel : hotels) {// 2.1.轉(zhuǎn)換為文檔類型HotelDocHotelDoc hotelDoc = new HotelDoc(hotel);// 2.2.創(chuàng)建新增文檔的Request對象request.add(new IndexRequest("hotel").id(hotelDoc.getId().toString()).source(JSONUtil.toJsonStr(hotelDoc), XContentType.JSON));}// 3.發(fā)送請求client.bulk(request, RequestOptions.DEFAULT);
}
1.3 RestClient查詢
1.3.1 普通查詢
@Test
void testMatch() throws IOException {// 1. 創(chuàng)建Request對象SearchRequest request = new SearchRequest("hotel");// 2. 組織請求參數(shù)request.source().query(QueryBuilders.matchQuery("all", "如家"));// 3. 發(fā)送請求SearchResponse response = client.search(request, RequestOptions.DEFAULT);handleResponse(response);
}
1.3.2 復合條件查詢
@Test
void testBool() throws IOException {// 1.準備RequestSearchRequest request = new SearchRequest("hotel");// 2.準備DSL// 2.1.準備BooleanQueryBoolQueryBuilder boolQuery = QueryBuilders.boolQuery();// 2.2.添加termboolQuery.must(QueryBuilders.termQuery("city", "杭州"));// 2.3.添加rangeboolQuery.filter(QueryBuilders.rangeQuery("price").lte(250));request.source().query(boolQuery);// 3.發(fā)送請求SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.解析響應handleResponse(response);
}
1.3.3 分頁排序查詢
@Test
void testPageAndSort() throws IOException {int pageNo = 1, pageSize = 5;// 1.準備RequestSearchRequest request = new SearchRequest("hotel");// 2.1.搜索條件參數(shù)//request.source().query(QueryBuilders.matchAllQuery());request.source().query(QueryBuilders.matchQuery("all", "如家"));// 2.2.排序參數(shù)request.source().sort("price", SortOrder.ASC);// 2.3.分頁參數(shù)request.source().from((pageNo - 1) * pageSize).size(pageSize);// 3.發(fā)送請求SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.解析響應handleResponse(response);
}
1.3.4 高亮分頁查詢
@Test void testHighLight() throws IOException {int pageNo = 1, pageSize = 3;// 1.準備RequestSearchRequest request = new SearchRequest("hotel");// 2.1.搜索條件參數(shù)request.source().query(QueryBuilders.matchQuery("all", "如家"));// 2.2 高亮條件
// request.source().highlighter(
// new HighlightBuilder()
// .field("name")
// .preTags("<em>")
// .postTags("</em>")
// );request.source().highlighter(new HighlightBuilder().field("name").field("brand").requireFieldMatch(false));// 2.3.排序參數(shù)request.source().sort("price", SortOrder.ASC);// 2.4.分頁參數(shù)request.source().from((pageNo - 1) * pageSize).size(pageSize);// 3.發(fā)送請求SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.解析響應handleResponse(response);}
1.3.5 分頁過濾復合查詢
/*** 搜索* @param params 請求參數(shù)* @return 分頁結(jié)果*/
@Override
public PageResult search(RequestParams params) {try {// 1. 準備RequestSearchRequest request = new SearchRequest("hotel");// 2.1 queryboolBasicQuery(params, request);// 2.2 分頁int pageNo = params.getPage();int pageSize = params.getSize();request.source().from((pageNo - 1) * pageSize).size(pageSize);// 3. 發(fā)送請求SearchResponse response = client.search(request, RequestOptions.DEFAULT);return handleResponse(response);} catch (IOException e) {throw new RuntimeException(e);}
}
/*** 構(gòu)建基本的bool查詢* @param params 請求參數(shù)* @param request 請求對象*/
private void boolBasicQuery(RequestParams params, SearchRequest request) {// 1.構(gòu)建BooleanQueryBoolQueryBuilder boolQuery = QueryBuilders.boolQuery();// 關(guān)鍵字搜索String key = params.getKey();if (StrUtil.isEmpty(key)) {boolQuery.must(QueryBuilders.matchAllQuery());} else {boolQuery.must(QueryBuilders.matchQuery("all", key));}// 城市條件String city = params.getCity();if(StrUtil.isNotEmpty(city)){boolQuery.filter(QueryBuilders.termQuery("city", city));}// 品牌條件String brand = params.getBrand();if(StrUtil.isNotEmpty(brand)){boolQuery.filter(QueryBuilders.termQuery("brand", brand));}// 星級條件String starName = params.getStarName();if(StrUtil.isNotEmpty(starName)){boolQuery.filter(QueryBuilders.termQuery("starName", starName));}// 價格條件Integer minPrice = params.getMinPrice();Integer maxPrice = params.getMaxPrice();if(minPrice != null && maxPrice != null){boolQuery.filter(QueryBuilders.rangeQuery("price").gte(minPrice).lte(maxPrice));}request.source().query(boolQuery);// // 2.算分控制// FunctionScoreQueryBuilder functionScoreQuery =// QueryBuilders.functionScoreQuery(// // 原始查詢,相關(guān)性算分的查詢// boolQuery,// // function score的數(shù)組// new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{// // 其中的一個function score 元素// new FunctionScoreQueryBuilder.FilterFunctionBuilder(// // 過濾條件// QueryBuilders.termQuery("isAD", true),// // 算分函數(shù)// ScoreFunctionBuilders.weightFactorFunction(10)// )// });// request.source().query(functionScoreQuery);
}
1.3.6 處理響應結(jié)果
private void handleResponse(SearchResponse response) {SearchHits searchHits = response.getHits();// 1. 獲取總條數(shù)long total = searchHits.getTotalHits().value;log.info("總條數(shù):{}", total);// 2. 遍歷結(jié)果數(shù)組SearchHit[] hits = searchHits.getHits();for(SearchHit hit : hits) {// 3. 獲取JSON字符串String json = hit.getSourceAsString();// 4. 轉(zhuǎn)換為Java對象HotelDoc hotelDoc = JSONUtil.toBean(json, HotelDoc.class);// 5. 獲取高亮結(jié)果Map<String, HighlightField> highlightFields = hit.getHighlightFields();if(CollUtil.isNotEmpty(highlightFields)){// 5.1 有高亮結(jié)果 獲取name的高亮結(jié)果HighlightField field1 = highlightFields.get("name");HighlightField field2 = highlightFields.get("brand");if(field1 != null && field2 != null){String name = field1.getFragments()[0].string();String brand = field2.getFragments()[0].string();hotelDoc.setName(name);hotelDoc.setBrand(brand);}}log.info("HotelDoc:{}", hotelDoc);}
}
1.4 Mysql和ES數(shù)據(jù)同步
這里我使用的是rbmq做異步通知es更新數(shù)據(jù)
1.4.1 引入依賴和配置yml
<!--amqp-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
rabbitmq:host: 192.168.164.128port: 5672username: itheimapassword: 123321virtual-host: /
1.4.2 定義交換機隊列名稱( 常量 )
/*** @author Ccoo* 2024/2/12*/
public class MqConstants {/*** 交換機*/public final static String HOTEL_EXCHANGE = "hotel.topic";/*** 監(jiān)聽新增和修改的隊列*/public final static String HOTEL_INSERT_QUEUE = "hotel.insert.queue";/*** 監(jiān)聽刪除的隊列*/public final static String HOTEL_DELETE_QUEUE = "hotel.delete.queue";/*** 新增或修改的RoutingKey*/public final static String HOTEL_INSERT_KEY = "hotel.insert";/*** 刪除的RoutingKey*/public final static String HOTEL_DELETE_KEY = "hotel.delete";
}
1.4.3 聲明和綁定交換機與隊列( 使用注解不需要聲明 )
/*** @author Ccoo* 2024/2/12*/
@Configuration
public class MqConfig {@Beanpublic TopicExchange topicExchange(){return new TopicExchange(MqConstants.HOTEL_EXCHANGE, true, false);}@Beanpublic Queue insertQueue(){return new Queue(MqConstants.HOTEL_INSERT_QUEUE, true);}@Beanpublic Queue deleteQueue(){return new Queue(MqConstants.HOTEL_DELETE_QUEUE, true);}@Beanpublic Binding insertQueueBinding(){return BindingBuilder.bind(insertQueue()).to(topicExchange()).with(MqConstants.HOTEL_INSERT_KEY)}@Beanpublic Binding deleteQueueBinding(){return BindingBuilder.bind(deleteQueue()).to(topicExchange()).with(MqConstants.HOTEL_DELETE_KEY)}
}/*** 監(jiān)聽酒店新增或修改的業(yè)務* @param id 酒店id*/@RabbitListener(queues = MqConstants.HOTEL_INSERT_QUEUE)public void listenHotelInsertOrUpdate(Long id){hotelService.insertById(id);}/*** 監(jiān)聽酒店刪除的業(yè)務* @param id 酒店id*/@RabbitListener(queues = MqConstants.HOTEL_DELETE_QUEUE)public void listenHotelDelete(Long id){hotelService.deleteById(id);}
/*** 監(jiān)聽酒店新增或修改的業(yè)務* @param id 酒店id*/
@RabbitListener(bindings = @QueueBinding(value = @Queue(name = MqConstants.HOTEL_INSERT_QUEUE, durable = "true"),exchange = @Exchange(name = MqConstants.HOTEL_EXCHANGE, type = ExchangeTypes.TOPIC),key = MqConstants.HOTEL_INSERT_KEY
))
public void listenHotelInsertOrUpdate(Long id){hotelService.insertById(id);
}/*** 監(jiān)聽酒店刪除的業(yè)務* @param id 酒店id*/
@RabbitListener(bindings = @QueueBinding(value = @Queue(name = MqConstants.HOTEL_DELETE_QUEUE, durable = "true"),exchange = @Exchange(name = MqConstants.HOTEL_EXCHANGE, type = ExchangeTypes.TOPIC),key = MqConstants.HOTEL_DELETE_KEY
))
public void listenHotelDelete(Long id){hotelService.deleteById(id);
}
1.4.4 編寫業(yè)務邏輯
/*** 刪除數(shù)據(jù)同步到ES* @param id*/
@Override
public void deleteById(Long id) {try {// 1.準備RequestDeleteRequest request = new DeleteRequest("hotel", id.toString());// 2.發(fā)送請求client.delete(request, RequestOptions.DEFAULT);} catch (IOException e) {throw new RuntimeException(e);}
}
/*** 新增或修改數(shù)據(jù)同步到ES* @param id*/
@Override
public void insertById(Long id) {try {// 0.根據(jù)id查詢酒店數(shù)據(jù)Hotel hotel = getById(id);// 轉(zhuǎn)換為文檔類型HotelDoc hotelDoc = new HotelDoc(hotel);// 1.準備Request對象IndexRequest request = new IndexRequest("hotel").id(hotel.getId().toString());// 2.準備Json文檔request.source(JSONUtil.toJsonStr(hotelDoc), XContentType.JSON);// 3.發(fā)送請求client.index(request, RequestOptions.DEFAULT);} catch (IOException e) {throw new RuntimeException(e);}
}