ES实战项目——仿京东商城
Posted 憨憨龟.
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ES实战项目——仿京东商城相关的知识,希望对你有一定的参考价值。
数据的获取
在开发项目之前,我们首先需要获取数据。我们可以从京东官网爬取一定的数据。
我们搜索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进行搜索,这样会极大的提高性能。
项目地址:
以上是关于ES实战项目——仿京东商城的主要内容,如果未能解决你的问题,请参考以下文章
商城项目实战 | 2.2 Android 仿京东商城——自定义 Toolbar
分享后盾网原创视频,仿京东商城(基于HDPHP框架开发,适合提高)视频教程(PHP实战)