此处没有安装步骤,安装过程挺简单,开箱即用,只是安装过程有一些坑,此处只有碎碎念,随记。
目录
0、前述。
1、部署过程的一些问题。
2、搜索使用的技术。
3、freenom域名。
4、部分代码。
0、前述。
趁着双11优惠,弄了一台1核2G的阿里云服务器,琢磨着部署点什么东西上去,刚好最近在学elasticsearch,就把做的一个搜索部署上去好了。
访问地址:
效果图:
1、部署过程的一些问题。
(1)elasticsearch、kibana、IK分词器,三者版本要一致,都用相同的版本。
特别是elasticsearch与IK的版本要一致,否则ES直接启动不了。
使用的elasticsearch版本:7.15.1。
使用的kibana版本:7.15.1。
使用的ik分词器版本:7.15.1。
(2)elasticsearch 7.x版本,JDK必须使用1.8以上版本,官方推荐使用jdk 11版本。
在安装ES之前,我已经在服务器上安装了一个JDK 1.8的版本,在window上jdk 1.8搭配elasticsearch7.15.0是可以运行的,在服务器上ES启动不了,最终服务器的jdk换成了jdk 11。
(3)启动ES,不要使用root用户,创建一个专门用于elasticsearch的用户,否则启动不了。
例如:创建一个名称为elastic的用户,添加到elastic组中。
groupadd elastic useradd els -g elastic passwd elastic chown -R elastic:elastic /root
使用命令切换用户到elastic,然后启动ES。
su elastic
在window下不是管理员用户可以启动ES。
(4)服务器内存太小,只有2G。ES启动后不久后自动关闭,被系统kill掉了。或启动之后占满了内存,系统卡死。
修改elasticsearch的jvm内存。
vim elasticsearch-7.15.1/config/jvm.options
找到配置内容。
## -Xms4g ## -Xmx4g
去掉#号,修改配置为如下。
-Xms256m -Xmx256m
(5)安装kibana,修改kibana的jvm内存。
vim kibana-7.15.1-linux-x86_64/config/node.options
找到配置内容。
#--max-old-space-size=4096
去掉#号,修改配置为如下:
--max-old-space-size=400
(6)部署在服务器上的kibana,通过浏览器访问不到。
修改配置kibana.yml文件。
vim kibana-7.15.1-linux-x86_64/config/kibana.yml
找到配置内容。
#server.host: "localhost"
去掉#号,修改成服务器的内网IP地址,是内网IP地址,不是外网IP地址。默认kibana为localhost,只有安装kibana的服务器可以访问,其他访问不了。
修改配置:
server.host: "172.x.x.x"
修改完成之后,还是访问不到kibana。
修改阿里云服务器安全组规则访问,开启防火墙相关端口。
kibana.yml默认访问端口是5601。
#server.port: 5601
云服务器 ECS:
网络与安全-->安全组-->配置规则-->入方向。
(6)使用了jsoup,爬取不到数据,连接超时timeout。
jsoup端口随机生成的,。。。开启服务器出方向端口。
云服务器 ECS:
网络与安全-->安全组-->配置规则-->出方向。
2、搜索使用的技术。
(1)使用的主要技术elasticsearch、kibana、jsoup、spring boot。
次要技术:lombok、fastjson、selenium。
jsoup用来抓取解析数据,elasticsearch用来存储数据。kibana用来建ES索引,查看数据。
selenium用来配合Firefox浏览器等网页加载完成,再用jsoup解析数据,要打开浏览器,只能在有界面的系统使用,window下、带界面的Linux可以跑。
使用matchAllQuery搜索全部记录。
使用BoolQuery布尔查询组合matchQuery全文检索查询和TermQueryBuilder精准匹配查询 。
使用IK分词器ik_smart方式。
实现搜索高亮HighlightBuilder。
(2)建立ES索引。
使用默认shard,5个primary shard,5个replica shard。
title字段,使用IK分词器ik_smart解析,结合ES自带keyword分词器使用。
PUT /jd_goods
{
"mappings": {
"properties": {
"img": {
"type": "keyword"
},
"price": {
"type": "double"
},
"shopname": {
"type": "keyword"
},
"title": {
"type": "text",
"analyzer": "ik_smart",
"fields": {
"keyword": {
"type": "keyword"
}
}
},
"url": {
"type": "keyword"
}
}
}
}
3、freenom域名。
部署好了,绑定一个玉米,折腾了半天申请下来一个freenom免费玉米,配置好,因为没有备案,不到1分钟域名就被封了。。。。。。
4、部分代码。
package com.xinxin.controller;
import com.xinxin.service.ContentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.util.List;
import java.util.Map;
@RestController
public class ContentController {
@Autowired
private ContentService contentService;
@GetMapping("/searchAll/{pageNo}/{pageSize}")
public List
package com.xinxin.service;
import com.alibaba.fastjson.JSON;
import com.xinxin.pojo.Content;
import com.xinxin.utils.ESconst;
import com.xinxin.utils.HtmlParseUtil;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.Timevalue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@Service
public class ContentService {
@Autowired
private RestHighLevelClient restHighLevelClient;
public Boolean parseContent(String keywords) throws Exception {
List contents = new HtmlParseUtil().parseJD(keywords);
//System.out.println(JSON.toJSonString(contents));
//把从网站查询到的数据放入ES中。
BulkRequest bulkRequest = new BulkRequest();
bulkRequest.timeout("2m");
for (int i = 0; i < contents.size(); i++) {
bulkRequest.add(
new IndexRequest(ESconst.ES_INDEX)
.source(JSON.toJSonString(contents.get(i)), XContentType.JSON));
}
BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
return !bulk.hasFailures();
}
public List> searchPage(String keyword, int pageNo, int pageSize) throws IOException {
if (pageNo <= 1) {
pageNo = 1;
}
//条件搜索
SearchRequest searchRequest = new SearchRequest(ESconst.ES_INDEX);
//搜索源构建对象
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//分页
sourceBuilder.from(pageNo);
sourceBuilder.size(pageSize);
//termQuery精准匹配
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", keyword);
sourceBuilder.query(termQueryBuilder);
sourceBuilder.timeout(new Timevalue(60, TimeUnit.SECONDS));
//执行搜索
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//解析结果
List> list = new ArrayList<>();
for (SearchHit hit : searchResponse.getHits().getHits()) {
//hit.getSourceAsMap() 源文档内容,就是数据中_source中的内容
list.add(hit.getSourceAsMap());
}
return list;
}
public List> searchPageHighlightBuilder(String keyword, int pageNo, int pageSize) throws IOException {
if (pageNo <= 1) {
pageNo = 1;
}
//条件搜索
SearchRequest searchRequest = new SearchRequest(ESconst.ES_INDEX);
//搜索源构建对象
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//分页
sourceBuilder.from(pageNo);
sourceBuilder.size(pageSize);
//termQuery精确匹配
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", keyword);
sourceBuilder.query(termQueryBuilder);
sourceBuilder.timeout(new Timevalue(60, TimeUnit.SECONDS));
//高亮,加上高亮。
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("title");
highlightBuilder.preTags("");
highlightBuilder.postTags("");
//是否多个高亮显示
highlightBuilder.requireFieldMatch(false);
sourceBuilder.highlighter(highlightBuilder);
//执行搜索
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//解析结果
List> list = new ArrayList<>();
for (SearchHit hit : searchResponse.getHits().getHits()) {
//解析出高亮,放到map中。
Map highlightFields = hit.getHighlightFields();
HighlightField title = highlightFields.get("title");
//源文档内容,就是数据中_source中的内容
//原来的结果。
Map sourceAsMap = hit.getSourceAsMap();
//解析高亮的字段,将原来的字段替换为我们高亮的字段既可以。
if (title != null) {
Text[] fragments = title.fragments();
String n_title = "";
for (Text text : fragments) {
n_title += text;
}
sourceAsMap.put("title", n_title);
}
list.add(sourceAsMap);
}
return list;
}
public List> searchAllBuilder(int pageNo, int pageSize) throws IOException {
//搜索请求对象
SearchRequest searchRequest = new SearchRequest(ESconst.ES_INDEX);
//搜索源构建对象
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//分页查询,设置起始下标,从0开始
searchSourceBuilder.from(pageNo);
//每页显示个数
searchSourceBuilder.size(pageSize);
//搜索方式
//matchAllQuery:搜索全部
searchSourceBuilder.query(QueryBuilders.matchAllQuery());
//source源字段过虑,第一个参数结果集包括哪些字段,第二个参数表示结果集不包括哪些字段 "title", "img", "price", "url", "shopname"
searchSourceBuilder.fetchSource(new String[]{"title", "img", "price", "url", "shopname"}, new String[]{});
//向搜索请求对象中添加搜索源
searchRequest.source(searchSourceBuilder);
//执行搜索,向es发出http请求
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//解析结果
List> list = new ArrayList<>();
for (SearchHit documentFields : searchResponse.getHits().getHits()) {
list.add(documentFields.getSourceAsMap());
}
return list;
}
public List> searchPageById(String id) throws IOException {
//条件搜索
SearchRequest searchRequest = new SearchRequest(ESconst.ES_INDEX);
//搜索源构建对象
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//termsQuery精准匹配,根据id查询。
//String[] split = new String[]{"1","2"};
//List idList = Arrays.asList(split);
TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery("_id", id);
sourceBuilder.query(termsQueryBuilder);
sourceBuilder.timeout(new Timevalue(60, TimeUnit.SECONDS));
//执行搜索
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//解析结果
List> list = new ArrayList<>();
for (SearchHit hit : searchResponse.getHits().getHits()) {
//hit.getSourceAsMap() 源文档内容,就是数据中_source中的内容
list.add(hit.getSourceAsMap());
}
return list;
}
public List> searchMatchQueryHighlight(String keyword, int pageNo, int pageSize) throws IOException {
if (pageNo <= 1) {
pageNo = 1;
}
//条件搜索
SearchRequest searchRequest = new SearchRequest(ESconst.ES_INDEX);
//搜索源构建对象
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//分页
sourceBuilder.from(pageNo);
sourceBuilder.size(pageSize);
//matchQuery即全文检索。它的搜索方式是先将搜索字符串分词,再使用各各词条从索引中搜索。
MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("title", keyword).minimumShouldMatch("80%"); //80%相似度就能匹配到
sourceBuilder.query(matchQueryBuilder);
sourceBuilder.timeout(new Timevalue(60, TimeUnit.SECONDS));
//高亮,加上高亮。
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("title");
highlightBuilder.preTags("");
highlightBuilder.postTags("");
//是否多个高亮显示
highlightBuilder.requireFieldMatch(false);
sourceBuilder.highlighter(highlightBuilder);
//执行搜索
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//解析结果
List> list = new ArrayList<>();
for (SearchHit hit : searchResponse.getHits().getHits()) {
//解析出高亮,放到map中。
Map highlightFields = hit.getHighlightFields();
HighlightField title = highlightFields.get("title");
//源文档内容,就是数据中_source中的内容
//原来的结果。
Map sourceAsMap = hit.getSourceAsMap();
//解析高亮的字段,将原来的字段替换为我们高亮的字段既可以。
if (title != null) {
Text[] fragments = title.fragments();
String n_title = "";
for (Text text : fragments) {
n_title += text;
}
sourceAsMap.put("title", n_title);
}
list.add(sourceAsMap);
}
return list;
}
public List> searchMultiMatchQueryBuilder(String keyword, int pageNo, int pageSize) throws IOException {
if (pageNo <= 1) {
pageNo = 1;
}
//条件搜索
SearchRequest searchRequest = new SearchRequest(ESconst.ES_INDEX);
//搜索源构建对象
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//分页
sourceBuilder.from(pageNo);
sourceBuilder.size(pageSize);
//multiQuery多字段匹配查询,一次可以匹配多个字段。单项匹配是在一个field中去匹配,多项匹配是拿关键字去多个Field中匹配。
//keyword(注:xxx yyy中间需要有空格不然不分词)在title或者shopname中任何一个有就可以。
MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(keyword, "title", "shopname")
.minimumShouldMatch("50%") //50%相似度就能匹配到
.field("title", 10);//提升boost:给name字段的权重提高10倍
sourceBuilder.query(multiMatchQueryBuilder);
sourceBuilder.timeout(new Timevalue(60, TimeUnit.SECONDS));
//高亮,加上高亮。
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("title");
highlightBuilder.preTags("");
highlightBuilder.postTags("");
//是否多个高亮显示
highlightBuilder.requireFieldMatch(false);
sourceBuilder.highlighter(highlightBuilder);
//执行搜索
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//解析结果
List> list = new ArrayList<>();
for (SearchHit hit : searchResponse.getHits().getHits()) {
//解析出高亮,放到map中。
Map highlightFields = hit.getHighlightFields();
HighlightField title = highlightFields.get("title");
//源文档内容,就是数据中_source中的内容
//原来的结果。
Map sourceAsMap = hit.getSourceAsMap();
//解析高亮的字段,将原来的字段替换为我们高亮的字段既可以。
if (title != null) {
Text[] fragments = title.fragments();
String n_title = "";
for (Text text : fragments) {
n_title += text;
}
sourceAsMap.put("title", n_title);
}
list.add(sourceAsMap);
}
return list;
}
public List> searchBoolQueryBuilder(String keyword, String shopname, int pageNo, int pageSize) throws IOException {
if (pageNo <= 1) {
pageNo = 1;
}
//条件搜索
SearchRequest searchRequest = new SearchRequest(ESconst.ES_INDEX);
//搜索源构建对象
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//分页
sourceBuilder.from(pageNo);
sourceBuilder.size(pageSize);
//BoolQuery布尔查询,搜索方式。
//1.先定义一个MultiMatchQuery,多字段匹配查询。
// multiQuery多字段匹配查询,一次可以匹配多个字段。单项匹配是在一个field中去匹配,多项匹配是拿关键字去多个Field中匹配。
// keyword(注:xxx yyy中间需要有空格不然不分词)在title或者shopname中任何一个有就可以。
MultiMatchQueryBuilder field = QueryBuilders.multiMatchQuery(keyword, "title", "price")
.minimumShouldMatch("50%") //50%相似度就能匹配到
.field("title", 10);//提升boost:给name字段的权重提高10倍
//2.再定义一个termQuery,精准匹配查询。
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title.keyword", keyword);
//3.再定义一个BooleanQuery布尔查询,把上面两个查询结合在一起。
//BoolQuery布尔查询。
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.should(field);
boolQueryBuilder.should(termQueryBuilder);
sourceBuilder.query(boolQueryBuilder);
sourceBuilder.timeout(new Timevalue(60, TimeUnit.SECONDS));
//高亮,加上高亮。
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("title");
highlightBuilder.preTags("");
highlightBuilder.postTags("");
//是否多个高亮显示
highlightBuilder.requireFieldMatch(false);
sourceBuilder.highlighter(highlightBuilder);
//执行搜索
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//解析结果
List> list = new ArrayList<>();
for (SearchHit hit : searchResponse.getHits().getHits()) {
//解析出高亮,放到map中。
Map highlightFields = hit.getHighlightFields();
HighlightField title = highlightFields.get("title");
//源文档内容,就是数据中_source中的内容
//原来的结果。
Map sourceAsMap = hit.getSourceAsMap();
//解析高亮的字段,将原来的字段替换为我们高亮的字段既可以。
if (title != null) {
Text[] fragments = title.fragments();
String n_title = "";
for (Text text : fragments) {
n_title += text;
}
sourceAsMap.put("title", n_title);
}
list.add(sourceAsMap);
}
return list;
}
public List> searchBoolQueryBuilder2(String keyword, int pageNo, int pageSize) throws IOException {
if (pageNo <= 1) {
pageNo = 1;
}
//条件搜索
SearchRequest searchRequest = new SearchRequest(ESconst.ES_INDEX);
//搜索源构建对象
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//分页
sourceBuilder.from(pageNo);
sourceBuilder.size(pageSize);
//BoolQuery布尔查询,搜索方式。
//1.先定义一个MultiMatchQuery,多字段匹配查询。
// multiQuery多字段匹配查询,一次可以匹配多个字段。单项匹配是在一个field中去匹配,多项匹配是拿关键字去多个Field中匹配。
// keyword(注:spring css中间需要有空格不然不分词)在title或者shopname中任何一个有就可以。
MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("title", keyword).minimumShouldMatch("80%"); //80%相似度就能匹配到
matchQueryBuilder.analyzer("ik_smart");
//matchQueryBuilder.analyzer("comma");
//2.再定义一个termQuery,精准匹配查询。
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title.keyword", keyword);
//MatchQueryBuilder matchQueryBuilder1 = QueryBuilders.matchQuery("title", keyword);
//matchQueryBuilder1.analyzer("keyword");
//3.再定义一个BooleanQuery布尔查询,把上面两个查询结合在一起。
//BoolQuery布尔查询。
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.should(termQueryBuilder);
boolQueryBuilder.should(matchQueryBuilder);
sourceBuilder.query(boolQueryBuilder);
sourceBuilder.timeout(new Timevalue(60, TimeUnit.SECONDS));
//高亮,加上高亮。
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("title");
highlightBuilder.preTags("");
highlightBuilder.postTags("");
//是否多个高亮显示
highlightBuilder.requireFieldMatch(false);
sourceBuilder.highlighter(highlightBuilder);
//执行搜索
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//解析结果
List> list = new ArrayList<>();
for (SearchHit hit : searchResponse.getHits().getHits()) {
//解析出高亮,放到map中。
Map highlightFields = hit.getHighlightFields();
HighlightField title = highlightFields.get("title");
//源文档内容,就是数据中_source中的内容
//原来的结果。
Map sourceAsMap = hit.getSourceAsMap();
//解析高亮的字段,将原来的字段替换为我们高亮的字段既可以。
if (title != null) {
Text[] fragments = title.fragments();
String n_title = "";
for (Text text : fragments) {
n_title += text;
}
sourceAsMap.put("title", n_title);
}
list.add(sourceAsMap);
}
return list;
}
public List> searchBoolFilterQueryBuilder(String keyword, int pageNo, int pageSize) throws IOException {
if (pageNo <= 1) {
pageNo = 1;
}
//条件搜索
SearchRequest searchRequest = new SearchRequest(ESconst.ES_INDEX);
//搜索源构建对象
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//分页
sourceBuilder.from(pageNo);
sourceBuilder.size(pageSize);
//BoolQuery布尔查询,搜索方式。
//1.先定义一个MultiMatchQuery,多字段匹配查询。
// multiQuery多字段匹配查询,一次可以匹配多个字段。单项匹配是在一个field中去匹配,多项匹配是拿关键字去多个Field中匹配。
// keyword(注:spring css中间需要有空格不然不分词)在title或者shopname中任何一个有就可以。
MultiMatchQueryBuilder field = QueryBuilders.multiMatchQuery(keyword, "title", "shopname")
.minimumShouldMatch("50%") //50%相似度就能匹配到
.field("title", 10);//提升boost:给name字段的权重提高10倍
//2.再定义一个BooleanQuery布尔查询。
//BoolQuery布尔查询。
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(field);
//过虑是针对搜索的结果进行过虑,过虑器主要判断的是文档是否匹配,不去计算和判断文档的匹配度得分,
// 所以过虑器性能比查询要高,且方便缓存,推荐尽量使用过虑器去实现查询或者过虑器和查询共同使用。
//过滤器,过滤条件。
//boolQueryBuilder.filter(QueryBuilders.termQuery("publish", "201001"));//在publish里过滤201001
boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(60).lte(100)); //价格区间
sourceBuilder.query(boolQueryBuilder);
sourceBuilder.timeout(new Timevalue(60, TimeUnit.SECONDS));
//高亮,加上高亮。
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("title");
highlightBuilder.preTags("");
highlightBuilder.postTags("");
//是否多个高亮显示
highlightBuilder.requireFieldMatch(false);
sourceBuilder.highlighter(highlightBuilder);
//执行搜索
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//解析结果
List> list = new ArrayList<>();
for (SearchHit hit : searchResponse.getHits().getHits()) {
//解析出高亮,放到map中。
Map highlightFields = hit.getHighlightFields();
HighlightField title = highlightFields.get("title");
//源文档内容,就是数据中_source中的内容
//原来的结果。
Map sourceAsMap = hit.getSourceAsMap();
//解析高亮的字段,将原来的字段替换为我们高亮的字段既可以。
if (title != null) {
Text[] fragments = title.fragments();
String n_title = "";
for (Text text : fragments) {
n_title += text;
}
sourceAsMap.put("title", n_title);
}
list.add(sourceAsMap);
}
return list;
}
public List> search(String keyword, int pageNo, int pageSize) throws Exception {
List> list = searchBoolQueryBuilder2(keyword, pageNo, pageSize);
if (list.size()==0 || list.isEmpty()) {
Boolean bool = parseContent(keyword);
if (bool) {
while (list.size()==0) {
list = searchBoolQueryBuilder2(keyword, pageNo, pageSize);
}
}
}
return list;
}
}
package com.xinxin.utils;
import com.xinxin.pojo.Content;
import org.jsoup.Jsoup;
import org.jsoup.nodes.document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.openqa.selenium.Platform;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxBinary;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxProfile;
import org.springframework.util.StringUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class HtmlParseUtil {
public static void main(String[] args) throws Exception {
new HtmlParseUtil().parseJD("java").forEach(System.out::println);
}
public List parseJD(String keywords) throws IOException, InterruptedException {
//获取请求 https://search.jd.com/Search?keyword=java&enc=utf-8
String requestURL = "https://search.jd.com/Search?enc=utf-8&keyword=" + keywords;
//方式一:等待网页加载完成解析。
//版本:firefox浏览器:91.3.0esr (64 位)。geckodriver.exe:v0.30.0。
//1、安装firefox浏览器。
//2、下载geckodriver.exe驱动。下载地址:https://github.com/mozilla/geckodriver/releases,根据系统情况下载对于的驱动。例如:下window的驱动geckodriver-v0.30.0-win64.zip。
//3、解压geckodriver-v0.30.0-win64.zip,将geckodriver.exe放到firefox安装目录,例如:D:Program FilesMozilla Firefox
//方式二:不等网页加载完成就解析,解析网页,jsoup返回document就是浏览器document对象。
document document = Jsoup.parse(new URL(requestURL), 30000);
//System.out.println(document.html());
Element element = document.getElementById("J_goodsList");
//System.out.println(element.html());
//获取所有的li元素
Elements elements = element.getElementsByTag("li");
List goodsList = new ArrayList<>();
Content content = null;
//获取元素中的内容。
for (Element el : elements) {
//获取图片,第1个img标签的src属性。
String img = el.getElementsByTag("img").eq(0).attr("data-lazy-img");
if ("done".equals(img) || StringUtils.isEmpty(img)) {
img = el.getElementsByTag("img").eq(0).attr("src");
}
if ("done".equals(img) || StringUtils.isEmpty(img)) {
img = el.getElementsByTag("img").eq(0).attr("source-data-lazy-img");
}
//获取价格,获取p-price样式的div的文本。
//System.out.println(el.getElementsByClass("p-price").eq(0).select("strong").text());
String price = el.getElementsByClass("p-price").eq(0).select("strong").text();
price = price.replaceFirst("¥", "");
//获取标题,获取p-name样式的div的文本。
String title = el.getElementsByClass("p-name").eq(0).select("em").text();
//获取详情页地址
String url = el.getElementsByTag("a").eq(0).attr("href");
//店铺名称
String shopname = el.getElementsByClass("hd-shopname").eq(0).text();
System.out.println("=====================================");
System.out.println(img);
System.out.println(price);
System.out.println(title);
System.out.println(url);
System.out.println(shopname);
content = new Content();
content.setTitle(title);
Double price1 = StringUtils.isEmpty(price) ? 6.66d : Double.parseDouble(price);
content.setPrice(price1);
content.setImg(img);
content.setUrl(url);
content.setShopname(shopname);
goodsList.add(content);
}
return goodsList;
}
}



