資料的獲取
在開發專案之前,我們首先需要獲取資料,我們可以從京東官網爬取一定的資料,
我們搜索Java之后可以發現他的地址實際上就是https://search.jd.com/Search?keyword=java
所以我們可以通過JSOUP對其進行決議,獲取相關的資料,

相關依賴:
<!-- 決議網頁--> <dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.10.2</version> </dependency>
撰寫工具類
添加依賴之后,我們便可以來撰寫我們的工具類爬取相關資料,
在代碼中,通過對html界面中各元素的分析,然后獲取相關的資料,將其存入到es中,

通過對HTML的決議,獲取頁面中的圖片、名字以及價格,將其封裝到物件中,最后回傳商品集合即可,
輸入的查詢關鍵字如果是中文的話需要進行轉義,
public class HtmlParseUtil {
public static void main(String[] args) throws IOException {
new HtmlParseUtil().parseJD("java").forEach(System.out::println);
}
public List<Content> parseJD(String keywords) throws IOException {
//https://search.jd.com/Search?keyword=java
// 前提,需要聯網 ,ajax不能獲取到!
// 中文需要轉義
String url = "https://search.jd.com/Search?keyword=" + keywords;
//決議網頁(document就是瀏覽器頁面物件)
Document document = Jsoup.parse(new URL(url), 30000);
//所有js中的操作都可以使用,
Element element = document.getElementById("J_goodsList");
//獲取所有Li標簽
Elements elements = element.getElementsByTag("li");
List<Content> goodsList = new ArrayList<>();
//獲取元素中的內容 這個的el就是每一個li標簽
for (Element el : elements) {
//關于獲取不到圖片,由于是懶加載的,所以獲取src是獲取不到的
String img = el.getElementsByTag("img").eq(0).attr("data-lazy-img");
String price = el.getElementsByClass("p-price").eq(0).text();
String name = el.getElementsByClass("p-name").eq(0).text();
Content content = new Content();
content.setPrice(price);
content.setImg(img);
content.setTitle(name);
goodsList.add(content);
}
return goodsList;
}
}

業務代碼
工具類完成之后,我們便可以進行業務代碼的撰寫了,
組態檔
首先添加組態檔,將es和spring boot集成,
@Configuration
public class ElasticSearchClientConfig {
@Bean
public RestHighLevelClient restHighLevelClient() {
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(
new HttpHost("127.0.0.1", 9200, "http")));
return client;
}
}
批量添加資料
這個時候開始撰寫對應業務類,我們通過工具類獲取商品集合后,將資料批量插入到es中,
@Service
public class ContentService {
@Autowired
private RestHighLevelClient restHighLevelClient;
//決議資料 放入 es索引中
public Boolean parseObject(String keywords) throws IOException {
List<Content> contents = new HtmlParseUtil().parseJD(keywords);
//將資料批量放入es中
BulkRequest bulkRequest = new BulkRequest();
bulkRequest.timeout("2m");
for (int i = 0; i < contents.size(); i++) {
bulkRequest.add(
new IndexRequest("jd_goods")
.source(JSON.toJSONString(contents.get(i)), XContentType.JSON)
);
}
BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
return !bulk.hasFailures();
}
}
@RestController
public class ContentController {
@Autowired
private ContentService contentService;
@GetMapping("/parse/{keyword}")
public Boolean parse(@PathVariable("keyword") String keywords) throws IOException {
return contentService.parseObject(keywords);
}
}
撰寫完上述代碼之后,我們便可以啟動專案進行測驗,
訪問該地址:http://localhost:9090/parse/java
然后查看es可以看到資料插入成功,

查詢資料
資料成功插入之后,我們便可以直接在es中進行查詢了,
根據前端傳入的關鍵字以及分頁資訊去es中查詢符合的資料,
@GetMapping("/search/{keyword}/{pageNo}/{pageSize}")
public List<Map<String, Object>> search(@PathVariable("keyword") String keyword,
@PathVariable("pageNo") int pageNo,
@PathVariable("pageSize") int pageSize) throws IOException {
return contentService.searchPage(keyword, pageNo, pageSize);
}
//獲取資料
public List<Map<String, Object>> searchPage(String keyword, int pageNo, int pageSize) throws IOException {
if (pageNo <= 1) {
pageNo = 1;
}
//條件搜索
SearchRequest searchRequest = new SearchRequest("jd_goods");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//分頁
sourceBuilder.from(pageNo);
sourceBuilder.size(pageSize);
//精準匹配
TermQueryBuilder termQuery = QueryBuilders.termQuery("title", keyword);
sourceBuilder.query(termQuery);
sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
//執行搜索
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//決議結果
List<Map<String, Object>> list = new ArrayList<>();
for (SearchHit hit : searchResponse.getHits().getHits()) {
list.add(hit.getSourceAsMap());
}
return list;
}
訪問如下介面:http://localhost:9090/search/java/1/10
獲取資料成功,

前端代碼
首先需要準備vue.js以及axios.js;
我們可以直接創建一個目錄,然后執行相關VUE陳述句即可,
比如我創建一個test目錄,然后進入目錄打開cmd開始執行陳述句;
npm init
npm install axios
npm install vue
然后便可以在對應的目錄中獲取檔案,

獲取資料之后將其放入static中的js目錄中,接下來便可以撰寫前端代碼了,
流程可以分為以下幾步:
- 對搜索框進行雙向系結
- 點擊搜索按鈕后向后端發起請求
- 回圈展示資料
首先撰寫VUE代碼:
new Vue({
el: '#app',
data: {
keyword: '',//搜索關鍵字
results: []//搜索結果
},
methods: {
}
})
對搜索框進行雙向系結,以及系結按鈕事件:
<fieldset>
<legend>天貓搜索</legend>
<div class="mallSearch-input clearfix">
<div class="s-combobox" id="s-combobox-685">
<div class="s-combobox-input-wrap">
<input v-model="keyword" type="text" autocomplete="off" value="dd"
id="mq"
class="s-combobox-input" aria-haspopup="true">
</div>
</div>
<button type="submit" id="searchbtn" @click.prevent="searchKey">搜索</button>
</div>
</fieldset>
撰寫觸發事件:
searchKey() {
let keyword = this.keyword;
console.log(keyword);
//對接后端代碼
axios.get('search/' + keyword + '/1/10').then(response => {
console.log(response.data);
this.results = response.data;//系結資料
})
}
回圈展示:
<div class="product" v-for="result in results">
<div class="product-iWrap">
<!--商品封面-->
<div class="productImg-wrap">
<a class="productImg">
<img :src="result.img">
</a>
</div>
<!--價格-->
<p class="productPrice">
<em><b>¥</b>{{result.price}}</em>
</p>
<!--標題-->
<p class="productTitle">
<a> {{result.title}} </a>
</p>
<!-- 店鋪名 -->
<div class="productShop">
<span>店鋪: alibaba </span>
</div>
<!-- 成交資訊 -->
<p class="productStatus">
<span>月成交<em>999筆</em></span>
<span>評價 <a>3</a></span>
</p>
</div>
</div>
界面展示:

高亮展示
前后端實作時候,一個大致的商城界面便出現了,還剩最后一步我們可以優化以下,就是搜索之后的高亮展示,
高亮展示其實很簡單,我們只需要在查詢es的時候,使用HighlightBuilder條件構造器即可,然后最后將高亮的資料替換到我們的回傳結果中即可,
//高亮展示
public List<Map<String, Object>> searchPageHighLight(String keyword, int pageNo, int pageSize) throws IOException {
if (pageNo <= 1) {
pageNo = 1;
}
//條件搜索
SearchRequest searchRequest = new SearchRequest("jd_goods");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//分頁
sourceBuilder.from(pageNo);
sourceBuilder.size(pageSize);
//精準匹配
TermQueryBuilder termQuery = QueryBuilders.termQuery("title", keyword);
sourceBuilder.query(termQuery);
sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
//高亮設定
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("title");
highlightBuilder.requireFieldMatch(false);//多個高亮顯示
highlightBuilder.preTags("<span style='color:red'>");
highlightBuilder.postTags("</span>");
sourceBuilder.highlighter(highlightBuilder);
//執行搜索
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//決議結果
List<Map<String, Object>> list = new ArrayList<>();
for (SearchHit hit : searchResponse.getHits().getHits()) {
//決議高亮的欄位
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
HighlightField title = highlightFields.get("title");
Map<String, Object> sourceAsMap = hit.getSourceAsMap();//原來的結果
//置換結果 將原來的欄位換為高亮的欄位,
if (title != null) {
Text[] fragments = title.getFragments();
String n_title = "";
for (Text fragment : fragments) {
n_title += fragment;
}
sourceAsMap.put("title", n_title);//替換
}
list.add(sourceAsMap);
}
return list;
}
最后需要對前端進行小小的修改,這樣才能對高亮的html進行決議,
<!--標題-->
<p class="productTitle">
<a v-html="result.title"></a>
</p>

總結
以上便是一個完整的ES專案,在以后如果遇到需要大量查詢資料的時候,我們便可以將資料從資料庫中讀取出來放入ES中,然后通過ES進行搜索,這樣會極大的提高性能,
專案地址:
ed-study
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/374738.html
標籤:java
下一篇:一文看懂JVM運行時記憶體分布
