接上文讲述了ES环境的安装;本文将继续介绍和springboot整合并实战写demo;
创建一个springboot项目
省略
<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.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.2.5.RELEASEversion>
<relativePath/>
parent>
<groupId>com.damongroupId>
<artifactId>damonyuan-es-apiartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>damonyuan-es-apiname>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
<elasticsearch.version>7.6.1elasticsearch.version>
properties>
<dependencies>
<dependency>
<groupId>org.jsoupgroupId>
<artifactId>jsoupartifactId>
<version>1.10.2version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.70version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-elasticsearchartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-configuration-processorartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
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里面查看,此处就不一一体贴图了!
教程中两个项目是分开的;由于本人主要是学习入门,一个项目也方便保存学习,就不新建项目了
就是前面的,强调一下就是需要注意导入的版本和我们安装的版本一致
server.port=9999
spring.thymeleaf.cache=false
下载地址
链接:https://pan.baidu.com/s/1pmK0uEkdaPBvhfmGY06Nlg
提取码:6666
@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;
}
@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("")
.postTags("");
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);
}
}
下载并引入vue和axios
npm install vue
npm install axios
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}"/>
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 ">
<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 Javaa>li>
<li><a>Damon Yuan 前端a>li>
<li><a>Damon Yuan Linuxa>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>3a>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>