接上文讲述了ES环境的安装;本文将继续介绍和springboot整合并实战写demo;
Springboot整合
创建一个springboot项目
省略
pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.damon</groupId>
<artifactId>damonyuan-es-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>damonyuan-es-api</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<elasticsearch.version>7.6.1</elasticsearch.version>
</properties>
<dependencies>
<!-- jsoup解析页面 -->
<!-- 解析网页 爬视频可 研究tiko -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.10.2</version>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.70</version>
</dependency>
<!-- ElasticSearch -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<!-- thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- devtools热部署 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!-- -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- lombok 需要安装插件 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- <dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>7.6.1</version>
</dependency>-->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
编写配置
@Configuration
public class ElasticSearchClientConfig {
@Bean
public RestHighLevelClient restHighLevelClient(){
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(
new HttpHost("127.0.0.1",9200,"http")
)
);
return client;
}
}
实体
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
}
测试
测试都是在DamonyuanEsApiApplicationTests类中
@SpringBootTest
class DamonyuanEsApiApplicationTests {
@Autowired
public RestHighLevelClient restHighLevelClient;
//创建索引
@Test
public void testCreateIndex() throws Exception{
CreateIndexRequest request = new CreateIndexRequest("damon_index");
CreateIndexResponse response = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
System.out.println(response.isAcknowledged());//查看是否成功
System.out.println(response);//查看返回对象
restHighLevelClient.close();
}
//查看索引是否存在
@Test
public void testIndexIsExist() throws Exception{
GetIndexRequest request = new GetIndexRequest("damon_index");
boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
System.out.println(exists);//查看是否成功
restHighLevelClient.close();
}
//删除索引
@Test
public void testDeleteIndex() throws Exception{
DeleteIndexRequest request = new DeleteIndexRequest("damon_index");
AcknowledgedResponse delete = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);
System.out.println(delete.isAcknowledged());//查看是否成功
restHighLevelClient.close();
}
//创建文档
@Test
public void testAddDocument() throws Exception{
User damon = new User(1,"damon");
IndexRequest request = new IndexRequest("damon_index");//创建请求
request.id("1");//设置id
request.timeout(TimeValue.timeValueMillis(1000));//设置超时时间
request.source(JSON.toJSONString(damon), XContentType.JSON);//将数据存入请求中
IndexResponse response = restHighLevelClient.index(request,RequestOptions.DEFAULT);
System.out.println(response.status());//获取建立索引的状态信息
System.out.println(response);
restHighLevelClient.close();
}
//获取文档
@Test
public void testGetDocument() throws Exception{
GetRequest request = new GetRequest("damon_index","1");
GetResponse response = restHighLevelClient.get(request, RequestOptions.DEFAULT);
System.out.println(response.getSourceAsString());
System.out.println(response);
restHighLevelClient.close();
}
//查看文档是否存在
@Test
public void testDocumentIsExists() throws Exception{
GetRequest request = new GetRequest("damon_index","1");
request.fetchSourceContext(new FetchSourceContext(false));
request.storedFields("_none_");
boolean exists = restHighLevelClient.exists(request, RequestOptions.DEFAULT);
System.out.println(exists);
restHighLevelClient.close();
}
//更新文档
@Test
public void testUpdateDocument() throws Exception{
UpdateRequest request = new UpdateRequest("damon_index","1");
User user = new User(27,"damon Yuan");
request.doc(JSON.toJSON(user),XContentType.JSON);
UpdateResponse response = restHighLevelClient.update(request,RequestOptions.DEFAULT);
System.out.println(response.status());
restHighLevelClient.close();
}
//删除文档
@Test
public void testDeleteDocument() throws Exception{
DeleteRequest request = new DeleteRequest("damon_index","1");
request.timeout("1s");
DeleteResponse delete = restHighLevelClient.delete(request, RequestOptions.DEFAULT);
System.out.println(delete.status());
restHighLevelClient.close();
}
// 查询
// SearchRequest 搜索请求
// SearchSourceBuilder 条件构造
// HighlightBuilder 高亮
// TermQueryBuilder 精确查询
// MatchAllQueryBuilder
// xxxQueryBuilder ...
@Test
public void testSearch() throws Exception{
SearchRequest request = new SearchRequest();
SearchSourceBuilder builder = new SearchSourceBuilder();
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", "damon");
// builder.highlighter(new HighlightBuilder());
// builder.from(0);
// builder.size(5);
builder.timeout(new TimeValue(60, TimeUnit.SECONDS));
builder.query(termQueryBuilder);
SearchResponse search = restHighLevelClient.search(request, RequestOptions.DEFAULT);
SearchHits hits = search.getHits();
System.out.println(JSON.toJSONString(hits));
System.out.println("-------------");
for(SearchHit doc:hits.getHits()){
System.out.println(doc.getSourceAsMap());
}
restHighLevelClient.close();
}
//不能批量添加 后面的把前面的覆盖了
@Test
public void testBulkDocument() throws Exception{
IndexRequest request = new IndexRequest("bulk");
request.source(JSON.toJSONString(new User(1,"ni")),XContentType.JSON);
request.source(JSON.toJSONString(new User(2,"hao")),XContentType.JSON);
request.source(JSON.toJSONString(new User(3,"ma")),XContentType.JSON);
IndexResponse index = restHighLevelClient.index(request, RequestOptions.DEFAULT);
System.out.println(index.status());
restHighLevelClient.close();
}
@Test
public void testBulkDocument2() throws Exception{
BulkRequest request = new BulkRequest();
request.timeout("10s");
List<User> list = new ArrayList<>();
list.add(new User(1,"ni"));
list.add(new User(2,"shi"));
list.add(new User(3,"shui"));
list.add(new User(4,"?"));
for (int i = 0; i < list.size(); i++) {
request.add(new IndexRequest("bulk_index").source(JSON.toJSONString(list.get(i)),XContentType.JSON));
}
BulkResponse bulk = restHighLevelClient.bulk(request, RequestOptions.DEFAULT);
System.out.println(bulk.status());
restHighLevelClient.close();
}
}
测试结果可以在head里面查看,此处就不一一体贴图了!
ElasticSearch实战
教程中两个项目是分开的;由于本人主要是学习入门,一个项目也方便保存学习,就不新建项目了
项目结构
pom
就是前面的,强调一下就是需要注意导入的版本和我们安装的版本一致
application.preperties
server.port=9999
spring.thymeleaf.cache=false
前端素材
下载地址
链接:https://pan.baidu.com/s/1pmK0uEkdaPBvhfmGY06Nlg
提取码:6666
controller
@Controller
public class IndexController {
@GetMapping({"/","index"})
public String index(){
return "index";
}
}
启动访问
编写工具栏
解析html
public class HtmlParseUtil {
public static void main(String[] args) throws Exception {
System.out.println(parseJD("java"));
// // 请求url
// String url = "https://search.jd.com/Search?keyword=java";
// Document document = Jsoup.parse(new URL(url), 30000);
//
// //获取元素
// Element j_goodsList = document.getElementById("J_goodsList");
// Elements liList = j_goodsList.getElementsByTag("li");
// //System.out.println(liList);
//
// //获取img price name
// for (Element li:liList) {
// String img = li.getElementsByTag("img").eq(0).attr("data-lazy-img");//获取li第一张图
// String name = li.getElementsByClass("p-name").eq(0).text();
// String price = li.getElementsByClass("p-price").eq(0).text();
// System.out.println("--------------");
// System.out.println("img:"+img);
// System.out.println("name:"+name);
// System.out.println("price:"+price);
// }
}
public static List<Goods> parseJD(String keyword) throws Exception{
// 请求url
String url = "https://search.jd.com/Search?keyword="+keyword;
Document document = Jsoup.parse(new URL(url), 30000);
//获取元素
Element j_goodsList = document.getElementById("J_goodsList");
Elements liList = j_goodsList.getElementsByTag("li");
//System.out.println(liList);
List<Goods> list = new ArrayList<>();
//获取img price name
for (Element li:liList) {
String img = li.getElementsByTag("img").eq(0).attr("data-lazy-img");//获取li第一张图
String name = li.getElementsByClass("p-name").eq(0).text();
String price = li.getElementsByClass("p-price").eq(0).text();
// System.out.println("--------------");
// System.out.println("img:"+img);
// System.out.println("name:"+name);
// System.out.println("price:"+price);
Goods goods = new Goods(img,name,price);
list.add(goods);
}
return list;
}
}
用main 方法可以查看到es-head中填入了很多数据
至于节点为啥是那个几个可以在JD上面审查元素查看
商品实体
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Goods implements Serializable {
private static final long serialVersionUID = -8049497962627482693L;
private String img;
private String name;
private String price;
}
ContentService
@Service
public class ContentService {
@Autowired
private RestHighLevelClient restHighLevelClient;
public Boolean parseContent(String keywords) throws Exception{
List<Goods> list = HtmlParseUtil.parseJD(keywords);
BulkRequest request = new BulkRequest();
request.timeout("2m");
for (int i = 0; i < list.size(); i++) {
request.add(new IndexRequest("jd_goods_index")
//.id(""+(i)) 随机id
.source(JSON.toJSONString(list.get(i)), XContentType.JSON));
}
BulkResponse bulk = restHighLevelClient.bulk(request, RequestOptions.DEFAULT);
restHighLevelClient.close();
return !bulk.hasFailures();
}
public List<Map<String,Object>> search(String keyword,Integer pageNum,Integer pageSize) throws Exception{
SearchRequest request = new SearchRequest("jd_goods_index");//创建请求索引
SearchSourceBuilder builder = new SearchSourceBuilder();//创建搜索源
TermQueryBuilder name = QueryBuilders.termQuery("name", keyword);// 条件采用 精确查找 跟进查询name
builder.query(name)
.from(pageNum)
.size(pageSize);
//高亮
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("name")
.preTags("<span style='color:red'>")
.postTags("</span>");
builder.highlighter(highlightBuilder);
request.source(builder);//将搜索源放入请求中
SearchResponse search = restHighLevelClient.search(request, RequestOptions.DEFAULT);
SearchHits hits = search.getHits();
List<Map<String,Object>> results = new ArrayList<>();
for(SearchHit doc: hits.getHits()){
Map<String,Object> map = doc.getSourceAsMap();
//高亮
Map<String, HighlightField> highlightFieldMap = doc.getHighlightFields();
HighlightField name1 = highlightFieldMap.get("name");
if(name1!=null){
Text[] fragments = name1.fragments();
StringBuilder n_name = new StringBuilder();
for (Text text:fragments) {
n_name.append(text);
}
map.put("name",n_name.toString());
}
results.add(map);
}
return results;
}
}
追加控制器
@RestController
public class GoodsController {
@Autowired
private ContentService contentService;
@GetMapping("/parse/{keyword}")
public Boolean parse(@PathVariable("keyword")String keyword) throws Exception{
return contentService.parseContent(keyword);
}
@GetMapping("/search/{keyword}/{pageNum}/{pageSize}")
public List<Map<String, Object>> search(@PathVariable("keyword")String keyword,
@PathVariable("pageNum")Integer pageNum,
@PathVariable("pageSize")Integer pageSize) throws Exception{
return contentService.search(keyword,pageNum,pageSize);
}
}
resource
下载并引入vue和axios
npm install vue
npm install axios
resource下放入相应资源
修改html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8"/>
<title>狂神说Java-ES仿京东实战</title>
<link rel="stylesheet" th:href="@{/css/style.css}"/>
<!-- <script th:src="@{/js/jquery.min.js}"></script>-->
</head>
<body class="pg">
<div class="page">
<div id="app" class=" mallist tmall- page-not-market ">
<!-- 头部搜索 -->
<div id="header" class=" header-list-app">
<div class="headerLayout">
<div class="headerCon ">
<!-- Logo-->
<h1 id="mallLogo">
<img th:src="@{/images/jdlogo.png}" alt="">
</h1>
<div class="header-extra">
<!--搜索-->
<div id="mallSearch" class="mall-search">
<form name="searchTop" class="mallSearch-form clearfix">
<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" id="mq"
class="s-combobox-input" aria-haspopup="true">
</div>
</div>
<button type="submit" @click.prevent="searchKey" id="searchbtn">搜索</button>
</div>
</fieldset>
</form>
<ul class="relKeyTop">
<li><a>Damon Yuan Java</a></li>
<li><a>Damon Yuan 前端</a></li>
<li><a>Damon Yuan Linux</a></li>
<li><a>Damon Yuan 大数据</a></li>
<li><a>Damon Yuan 发财</a></li>
</ul>
</div>
</div>
</div>
</div>
</div>
<!-- 商品详情页面 -->
<div id="content">
<div class="main">
<!-- 品牌分类 -->
<form class="navAttrsForm">
<div class="attrs j_NavAttrs" style="display:block">
<div class="brandAttr j_nav_brand">
<div class="j_Brand attr">
<div class="attrKey">
品牌
</div>
<div class="attrValues">
<ul class="av-collapse row-2">
<li><a href="#"> Damon yuan </a></li>
<li><a href="#"> Java </a></li>
</ul>
</div>
</div>
</div>
</div>
</form>
<!-- 排序规则 -->
<div class="filter clearfix">
<a class="fSort fSort-cur">综合<i class="f-ico-arrow-d"></i></a>
<a class="fSort">人气<i class="f-ico-arrow-d"></i></a>
<a class="fSort">新品<i class="f-ico-arrow-d"></i></a>
<a class="fSort">销量<i class="f-ico-arrow-d"></i></a>
<a class="fSort">价格<i class="f-ico-triangle-mt"></i><i class="f-ico-triangle-mb"></i></a>
</div>
<!-- 商品详情 -->
<div class="view grid-nosku" >
<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 v-text="result.price"></em>
</p>
<!--标题-->
<p class="productTitle">
<a v-html="result.name"></a>
</p>
<!-- 店铺名 -->
<div class="productShop">
<span>店铺: Damon Yuan Java </span>
</div>
<!-- 成交信息 -->
<p class="productStatus">
<span>月成交<em>999笔</em></span>
<span>评价 <a>3</a></span>
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script th:src="@{/js/vue.min.js}"></script>
<script th:src="@{/js/axios.min.js}"></script>
<script>
new Vue({
el:"#app",
data:{
"keyword": '', // 搜索的关键字
"results":[] // 后端返回的结果
},
methods:{
searchKey(){
var keyword = this.keyword;
console.log(keyword);
axios.get('search/'+keyword+'/0/20').then(response=>{
console.log(response.data);
this.results=response.data;
})
}
}
});
</script>
</body>
</html>
启动9999访问
输入访问