天天看點

ElasticSearch實戰JD

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關鍵字高亮)

ElasticSearch實戰JD

該項目源碼已放到GitHub,需要的小夥伴自取。 Aaron-ES-JD