ElasticSearch實戰JD
在前面我們已經學習了如何安裝使用ElasticSearch,今天我們就來上手實戰,仿照京東搜尋頁面完成一個實戰項目(注意啟動我們的ElasticSearch)。不明白如何操作的請檢視我之前文章初識ElasticSearch-7.6.x搜尋引擎和SpringBoot內建ElasticSearch
項目源碼:https://github.com/starrysky0616/Aaron-ES-JD
1.導入maven依賴
<properties>
<java.version>1.8</java.version>
<elasticsearch.version>7.6.1</elasticsearch.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- ElasticSearch依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<!-- Lombok依賴 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- Thymeleaf依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- FastJSON依賴 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
<!-- JSoup依賴(解析網頁) -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.10.2</version>
</dependency>
</dependencies>
2.将ElasticSerch注入到SpringBoot
@Configuration
public class ElasticSearchClientConfig {
@Bean
public RestHighLevelClient restHighLevelClient() {
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(
new HttpHost("127.0.0.1", 9200, "http")
)
);
return client;
}
}
3.将我們需要的資料封裝為一個對象
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Content {
private String title;
private String img;
private String price;
}
4.編寫我們的service層(爬取資料以及實作搜尋)
@Service
public class ContentService {
@Resource
private RestHighLevelClient client;
/**
* @Author: Aaron
* @Description: 輸入搜尋條件後将資料解析存儲到ES中,并傳回插入是否成功
* @Date: 2020-05-17 15:01
* @param: keyword
* @return: java.lang.Boolean
**/
public Boolean parseContent(String keyword) throws IOException {
//1.使用JSoup解析網頁擷取資料
List<Content> contentList = new HtmlParseUtils().parseJD(keyword);
//2.判斷索引是否存在
GetIndexRequest getIndexRequest = new GetIndexRequest("jd_goods");
boolean exists = client.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
//3.如果索引不存在則建立jd_goods索引
if (!exists) {
CreateIndexRequest createIndexRequest = new CreateIndexRequest("jd_goods");
client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
}
//4.如果成功建立BulkRequest對象,并設定逾時時間
BulkRequest bulkRequest = new BulkRequest();
bulkRequest.timeout("2m");
for (int i = 0; i < contentList.size(); i++) {
bulkRequest.add(
new IndexRequest("jd_goods")
.source(JSON.toJSONString(contentList.get(i)), XContentType.JSON)
);
}
BulkResponse bulk = client.bulk(bulkRequest, RequestOptions.DEFAULT);
return !bulk.hasFailures();
}
/**
* @Author: Aaron
* @Description: 擷取資料實作搜尋功能
* @Date: 2020-05-17 15:24
* @param: keyword
* @param: pageNo
* @param: pageSize
* @return: List<Map < String, Object>>
**/
public List<Map<String, Object>> searchPage(String keyword, Integer pageNo,
Integer pageSize) throws IOException {
//1.分頁合理化
if (pageNo < 1) {
pageNo = 1;
}
//2.建立搜尋請求
SearchRequest searchRequest = new SearchRequest("jd_goods");
//3.建構搜尋條件
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//4.開啟分頁
searchSourceBuilder.from(pageNo);
searchSourceBuilder.size(pageSize);
//5.精準比對
TermQueryBuilder termQuery = QueryBuilders.termQuery("title", keyword);
searchSourceBuilder.query(termQuery);
//6.關鍵字高亮
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("title");//要高亮的屬性
highlightBuilder.requireFieldMatch(false);//關閉多個高亮
highlightBuilder.preTags("<span style='color:red'>");//高亮的字首
highlightBuilder.postTags("</span>");//高亮的字尾
searchSourceBuilder.highlighter(highlightBuilder);
//7.設定逾時間60s
searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
//8.将我們的搜素條件放到請求當中
searchRequest.source(searchSourceBuilder);
//9.用戶端執行搜尋請求,傳回搜尋結果
SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
//10.将傳回結果封裝
List<Map<String, Object>> mapList = new ArrayList<>();
for (SearchHit hit : search.getHits().getHits()) {
//解析高亮的字段(将原來的字段換成我們新的高亮字段)
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
HighlightField title = highlightFields.get("title");
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
if (null != title) {
Text[] fragments = title.fragments();
String newTitle = "";
for (Text fragment : fragments) {
newTitle += fragment;
}
sourceAsMap.put("title", newTitle);
}
mapList.add(sourceAsMap);
}
return mapList;
}
5.編寫我們的controller層
@RestController
public class ContentController {
@Resource
private ContentService contentService;
@GetMapping("/parseJD/{keyword}")
public Boolean parse(@PathVariable("keyword") String keyword) throws IOException {
return contentService.parseContent(keyword);
}
@GetMapping("/search/{keyword}/{pageNo}/{pageSize}")
public List<Map<String, Object>> searchPage(@PathVariable("keyword") String keyword,
@PathVariable(value = "pageNo") Integer pageNo,
@PathVariable("pageSize") Integer pageSize)
throws IOException {
return contentService.searchPage(keyword, pageNo, pageSize);
}
}
6.簡單寫一個網頁 通過以下路徑通路
@Controller
public class IndexController {
@GetMapping("/")
public String index(){
return "index";
}
}
7.最後看一下成果吧(可以清楚的看到搜尋的java關鍵字高亮)
該項目源碼已放到GitHub,需要的小夥伴自取。 Aaron-ES-JD