SpringBoot集成elasticsearch
引入依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.70</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
建立和客户端的elasticsearch连接
连接之前的操作
确认9090端口可以进行正常访问
/**
* @message 与客户端的elasticSearch进行连接
* @return 返回一个连接对象
*/
@Bean
@Deprecated
public RestHighLevelClient restHighLevelClient(){
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(new HttpHost("127.0.0.1",9200,"http"))
);
return client;
}
从容器中拿到这个restHighLevelClient对象
@Deprecated
@Autowired
@Qualifier("restHighLevelClient")
private RestHighLevelClient restHighLevelClient;
创建一个索引并查看
CreateIndexRequest request = new CreateIndexRequest("jia_sen");
CreateIndexResponse response = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
System.out.println("==========》");
System.out.println(response);
System.out.println("==========》");
System.out.println(request);
// 关闭连接
restHighLevelClient.close();
elasticSearch 中新增加了一条索引
索引的获取以及判断索引是否存在
GetIndexRequest request = new GetIndexRequest("jia_sen");
boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
反之如果不存在就会返回false
删除索引
DeleteIndexRequest request = new DeleteIndexRequest("jia_sen");
AcknowledgedResponse response = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);
// 判断是否将创建的索引删除
System.out.println("==============="+response.isAcknowledged());
文档的操作
创建实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Person implements Serializable {
private String name;
private Integer age;
}
文档添加
Person person = new Person("家森", 21);
IndexRequest request = new IndexRequest("jia_index");
request.id("1");
request.timeout(TimeValue.timeValueMillis(1000));
request.source(JSON.toJSONString(person), XContentType.JSON);
IndexResponse response = restHighLevelClient.index(request, RequestOptions.DEFAULT);
System.out.println(response.status());
System.out.println(request);
文档信息的获取
GetRequest request = new GetRequest("jia_index","1");
GetResponse response = restHighLevelClient.get(request, RequestOptions.DEFAULT);
System.out.println(response.toString());
文档信息的获取判断是否存在
GetRequest request = new GetRequest("jia_index","1");
// 不获取返回 _source 的上下文信息
request.fetchSourceContext(new FetchSourceContext(false));
request.storedFields("_none_");
boolean exists = restHighLevelClient.exists(request, RequestOptions.DEFAULT);
文档的更新
UpdateRequest request = new UpdateRequest("jia_index", "1");
Person person = new Person("家森", 19);
request.doc(JSON.toJSONString(person),XContentType.JSON);
UpdateResponse response = restHighLevelClient.update(request, RequestOptions.DEFAULT);
System.out.println(response.status());//返回状态信息
文档的删除
DeleteRequest request = new DeleteRequest("jia_index", "1");
request.timeout("1s");
DeleteResponse response = restHighLevelClient.delete(request, RequestOptions.DEFAULT);
System.out.println(response);//返回状态信息
文档的搜索
@Test
@Deprecated
public void testSearch() throws IOException {
//创建请求对象
SearchRequest searchRequest = new SearchRequest();
//构建搜索条件
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//查询条件 使用QueryBuilders工具类创建
//精确查询
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", "jiasen");
//匹配查询相当于模糊查询
// MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
//设置高亮
searchSourceBuilder.highlighter(new HighlightBuilder());
//设置分页
// searchSourceBuilder.from();
// searchSourceBuilder.size();
//设置一个过期时间
searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
//将条件放入查询构造器中
searchSourceBuilder.query(termQueryBuilder);
//将条件添加到请求中去
searchRequest.source(searchSourceBuilder);
//客户端查询请求
SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
SearchHits hits = search.getHits();
System.out.println("==================>"+JSON.toJSONString(hits));
for (SearchHit documentFields : hits.getHits()) {
System.out.println(documentFields.getSourceAsMap());
}
restHighLevelClient.close();
}
批量添加指挥保留最后一个
IndexRequest request = new IndexRequest("bulk");
request.source(JSON.toJSONString(new Person("liu",1)),XContentType.JSON);
request.source(JSON.toJSONString(new Person("min",2)),XContentType.JSON);
request.source(JSON.toJSONString(new Person("kai",3)),XContentType.JSON);
IndexResponse index = restHighLevelClient.index(request, RequestOptions.DEFAULT);
批量插入
bulkRequest.timeout("10s");
ArrayList<Person> peoples = new ArrayList<>();
peoples.add(new Person("jiaSen1",18));
peoples.add(new Person("jiaSen2",19));
peoples.add(new Person("jiaSen3",12));
peoples.add(new Person("jiaSen4",13));
peoples.add(new Person("jiaSen5",14));
peoples.add(new Person("jiaSen6",15));
peoples.add(new Person("jiaSen7",16));
for (int i = 0; i < peoples.size(); i++) {
//数据信息
bulkRequest.add(new IndexRequest("bulk")
//没有设置id会随机生成一个id
.id(""+(i+1)).source(JSON.toJSONString(peoples.get(i)),XContentType.JSON)
);
//封装批量信息
BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
System.out.println(bulk.status());
}
}
仿京东搜索项目搭建
需要引入的依赖
//请求的url地址
String url="https://search.jd.com/Search?keyword=java";
//解析网页(jsoup 解析返回的对象是浏览器Document对象)
Document document = Jsoup.parse(new URL(url), 30000);
//使用document可以使用js对document的所有操作
//获取元素(通过id)
Element j_goodsList = document.getElementById("J_goodsList");
//获取J_goodsList ul中的每一个li
assert j_goodsList != null;
Elements lis = j_goodsList.getElementsByTag("li");
//获取li下的 img, price ,name
//因为图片是一个懒加载的过程所以加载图片时会先放在data-lazy-img中
for (Element li : lis) {
String img = li.getElementsByTag("img").eq(0).attr("data-lazy-img");
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 class HtmlParseUtil {
public static List<Content> parseJD(String keyword) throws IOException {
//请求的url地址
String url="https://search.jd.com/Search?keyword="+keyword;
//解析网页(jsoup 解析返回的对象是浏览器Document对象)
Document document = Jsoup.parse(new URL(url), 30000);
//使用document可以使用js对document的所有操作
//获取元素(通过id)
Element j_goodsList = document.getElementById("J_goodsList");
//获取J_goodsList ul中的每一个li
assert j_goodsList != null;
Elements lis = j_goodsList.getElementsByTag("li");
ArrayList<Content> contents = new ArrayList<>();
//获取li下的 img, price ,name
for (Element li : lis) {
String img = li.getElementsByTag("img").eq(0).attr("data-lazy-img");
String name = li.getElementsByClass("p-name").eq(0).text();
String price = li.getElementsByClass("p-price").eq(0).text();
Content content = new Content(name,img,price);
contents.add(content);
}
return contents;
}
}
service层中批量添加数据el
@Deprecated
@Autowired
@Qualifier("restHighLevelClient")
private RestHighLevelClient restHighLevelClient;
/**
* 将网页信息批量添加进el中
* @param keywords 前端传入的关键字
* @return !bulk.hasFailures();
* @throws IOException 抛出ioe异常
*/
public Boolean parseContent(String keywords) throws IOException {
List<Content> contents = HtmlParseUtil.parseJD(keywords);
BulkRequest bulkRequest = new BulkRequest();
for (Content content : contents) {
bulkRequest.add(new IndexRequest("jd_goods")
.source(JSON.toJSONString(content), XContentType.JSON)
);
}
BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
return !bulk.hasFailures();
}
controller层传参数
private ContentService contentService;
@Autowired
public void setContentService(ContentService contentService) {
this.contentService = contentService;
}
@GetMapping("/parse/{keyword}")
public String parse(@PathVariable String keyword) throws IOException {
contentService.parseContent(keyword);
return "index";
}
遇到的问题
在 elasticsearch.yml 配置 xpack.security.enabled 为 false,然后重启 Elasticsearch:
xpack.security.enabled: false
将数据从el中查询出来(关键字高亮显示)
/**
*
* @param keyword 搜索的关键信息
* @param pageIndex from
* @param pageSize size
* @return list集合
*/
public List<Map<String,Object>> highLightSearch(String keyword,Integer pageIndex,Integer pageSize) throws IOException {
SearchRequest searchRequest = new SearchRequest("jd_goods");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
// 精确查询,添加查询条件
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", keyword);
searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
searchSourceBuilder.query(termQueryBuilder);
//查询分页
searchSourceBuilder.from(pageIndex);
searchSourceBuilder.size(pageSize);
//进行高亮设置
HighlightBuilder highlightBuilder = new HighlightBuilder();
//高亮关键信息 并设置高亮字段的样式
highlightBuilder.field("name");
highlightBuilder.preTags("<span style='color:red'>");
highlightBuilder.postTags("</span>");
searchSourceBuilder.highlighter(highlightBuilder);
//执行查询
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse= restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
SearchHits hits = searchResponse.getHits();
List<Map<String, Object>> results = new ArrayList<>();
for (SearchHit documentFields : hits.getHits()) {
//使用高亮字段覆盖原来的字段
Map<String, Object> sourceAsMap = documentFields.getSourceAsMap();
Map<String, HighlightField> highlightFields = documentFields.getHighlightFields();
HighlightField name = highlightFields.get("name");
//替换
if (name!=null){
Text[] fragments = name.fragments();
StringBuilder new_name = new StringBuilder();
for (Text text : fragments) {
new_name.append(text);
}
sourceAsMap.put("name",new_name.toString());
}
results.add(sourceAsMap);
}
return results;
}
controller层
@ResponseBody
@GetMapping("/h_search/{keyword}/{pageIndex}/{pageSize}")
public List<Map<String,Object>> highlightParse(@PathVariable("keyword") String keyword,
@PathVariable("pageIndex") Integer pageIndex,
@PathVariable("pageSize") Integer pageSize) throws IOException {
return contentService.highLightSearch(keyword, pageIndex, pageSize);
}
使用vue语法将后端数据进行渲染
观察京东给官网的操作我们只需要做一个div维护者一个ul 然后ul中将li进行数据遍历即可
使用vue将数据进行渲染
<!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>狂神说Java</a></li>
<li><a>狂神说前端</a></li>
<li><a>狂神说Linux</a></li>
<li><a>狂神说大数据</a></li>
<li><a>狂神聊理财</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="#"> 狂神说 </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>店铺: 狂神说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>
import {axios} from "../static/js/axios.min";
new Vue({
el:"#app",
data:{
"keyword":'',
"results":[]
},
methods:{
searchKey(){
let keyword= this.keyword;
console.log(keyword)
axios.get('h_search/'+keyword+'/0/10').then(response=>{
this.results=response.data;
})
}
}
});
</script>
</body>
</html>
**否则会出现DevTools 无法加载源映射: **