SpringBoot集成ES+京东搜索

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 无法加载源映射: **
在这里插入图片描述

完结
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值