zoukankan      html  css  js  c++  java
  • ElasticSearch

    一、安装

    1、安装ElasticSearch

    1.1window下安装

    1.1.1解压缩即可使用

    1.1.2目录结构:

    1.2安装ElasticSearch-head界面显示

    1.2.1下载地址:

    https://github.com/mobz/elasticsearch-head

    1.2.2安装步骤(需要node.js环境):

    • cd elasticsearch-head
    • npm install
    • npm run start

    1.2.3解决跨域问题

    修改elasticsearch.yml,加上

    http.cors.enabled: true
    http.cors.allow-origin: "*"

    1.3安装kibana

    1.3.1什么是kibana?

    Kibana是一个基于Node.js的Elasticsearch索引库数据统计工具,可以利用Elasticsearch的聚合功能,生成各种图表,如柱形图,线状图,饼图等。

    而且还提供了操作Elasticsearch索引数据的控制台,并且提供了一定的API提示,非常有利于我们学习Elasticsearch的语法。

    1.3.2安装步骤

    因为Kibana依赖于node,我们的虚拟机没有安装node,而window中安装过。所以我们选择在window下使用kibana。

    kibana版本需与elasticsearch保持一致

    1)解压即可使用

    2)汉化界面:修改kibana.yml

    加上

    i18n.locale: "zh-CN"

    1.4安装ik分词器

    1.4.1解压到/path/to/elasticsearch-7.6.1/plugins

    1.4.2使用

    GET /_analyze
    {
      "analyzer": "ik_smart",
      "text": "白云城主叶孤城"
    }
    
    GET /_analyze
    {
      "analyzer": "ik_max_word",
      "text": "白云城主叶孤城"
    }

    效果:

     不足:叶孤城没有成为一个词

    1.4.3添加自定义分词字典

    1)新建my.dic

    2)配置IKAnalyzer.cfg.xml:

    3)效果:

    二、操作Elasticsearch

    2.1基本概念

    Elasticsearch也是基于Lucene的全文检索库,本质也是存储数据,很多概念与MySQL类似的。

    对比关系:

    索引(indices)--------------------------------Databases 数据库
    ​
    类型(type)-----------------------------------Table 数据表
    ​
    文档(Document)-------------------------------Row 行
    ​
    字段(Field)----------------------------------Columns 列 

    详细说明:

    是不是与Lucene和solr中的概念类似。

    另外,在SolrCloud中,有一些集群相关的概念,在Elasticsearch也有类似的:

    • 索引集(Indices,index的复数):逻辑上的完整索引 collection1

    • 分片(shard):数据拆分后的各个部分

    • 副本(replica):每个分片的复制

    要注意的是:Elasticsearch本身就是分布式的,因此即便你只有一个节点,Elasticsearch默认也会对你的数据进行分片和副本操作,当你向集群添加新数据时,数据也会在新加入的节点中进行平衡。



    2.2springboot集成elasticsearch

    官方文档地址:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.6/java-rest-high.html

    2.2.1创建springboot工程

     

     

    添加配置类:

    package com.example.esapi.config;
    
    
    import org.apache.http.HttpHost;
    import org.elasticsearch.client.RestClient;
    import org.elasticsearch.client.RestHighLevelClient;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class ElasticSearchConfig {
    
        @Bean
        public RestHighLevelClient restHighLevelClient(){
            RestHighLevelClient restHighLevelClient = new RestHighLevelClient(
                    RestClient.builder(
                            new HttpHost("127.0.0.1", 9200, "http")
                    )
    
            );
            return restHighLevelClient;
    
        }
    
    }

    注意:解决版本不对称问题

    2.2.2索引操作

    package com.example.esapi;
    
    import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
    import org.elasticsearch.action.support.master.AcknowledgedResponse;
    import org.elasticsearch.client.RequestOptions;
    import org.elasticsearch.client.RestHighLevelClient;
    import org.elasticsearch.client.indices.CreateIndexRequest;
    import org.elasticsearch.client.indices.CreateIndexResponse;
    import org.elasticsearch.client.indices.GetIndexRequest;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    
    import java.io.IOException;
    
    @SpringBootTest
    class EsApiApplicationTests {
    
        @Autowired
        private RestHighLevelClient restHighLevelClient;
    
        //测试索引的创建
        @Test
        void testCreateIndex() throws IOException {
            //1.创建索引请求
            CreateIndexRequest request = new CreateIndexRequest("my_index");
            //2.客户端执行请求IndiceClient,请求后获得响应
            CreateIndexResponse createIndexResponse =
                    restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
            System.out.println(createIndexResponse);
        }
    
        //测试获取索引
        @Test
        void testExistIndex() throws IOException {
            GetIndexRequest request = new GetIndexRequest("my_index");
            boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
            System.out.println(exists);
        }
    
        //测试删除索引
        @Test
        void testDeleteIndex() throws IOException {
            DeleteIndexRequest request = new DeleteIndexRequest("my_index");
            //删除
            AcknowledgedResponse delete = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);
            System.out.println(delete.isAcknowledged());
        }
    
    
    }

    2.2.3文档操作

    //测试添加文档
        @Test
        void testAddDocument() throws IOException {
            //创建对象
            User user = new User("jack", 22);
            //创建请求
            IndexRequest request = new IndexRequest("my_index");
            //规则 put/my_index/_doc/1
            request.id("1");
            request.timeout("1s");
            //将我们的数据放入请求 json
            request.source(JSON.toJSONString(user), XContentType.JSON);
            //客户端发送请求,获取响应结果
            IndexResponse indexResponse = restHighLevelClient.index(request, RequestOptions.DEFAULT);
    
            System.out.println(indexResponse.toString());
            System.out.println(indexResponse.status());
        }
    
        //获取文档,判断是否存在 get/index/doc/1
        @Test
        void testIsExists() throws IOException {
            GetRequest request = new GetRequest("my_index", "1");
            //不获取返回的_source的上下文
            request.fetchSourceContext(new FetchSourceContext(false));
            request.storedFields("_none_");
    
            boolean exists = restHighLevelClient.exists(request, RequestOptions.DEFAULT);
            System.out.println(exists);
        }
    
        //获得文档的信息
        @Test
        void testGetDocument() throws IOException {
            GetRequest request = new GetRequest("my_index", "1");
            GetResponse getResponse = restHighLevelClient.get(request, RequestOptions.DEFAULT);
            System.out.println(getResponse.getSourceAsString()); //打印文档的内容
            System.out.println(getResponse);
        }
    
        //更新文档的信息
        @Test
        void testUpdateDocument() throws IOException {
            //创建对象
            User user = new User("mike", 12);
            //创建请求
            UpdateRequest request = new UpdateRequest("my_index", "1");
            request.timeout("1s");
    
            //将我们的数据放入请求 json
            request.doc(JSON.toJSONString(user), XContentType.JSON);
            //客户端发送请求,获取响应结果
            UpdateResponse updateResponse = restHighLevelClient.update(request, RequestOptions.DEFAULT);
    
            System.out.println(updateResponse.status());
        }
    
    
        //删除文档记录
        @Test
        void testDeleteDocument() throws IOException {
            DeleteRequest deleteRequest = new DeleteRequest("my_index", "1");
            deleteRequest.timeout("1s");
    
            DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
            System.out.println(deleteResponse.status());
        }
    
        //批量操作 插入数据
        @Test
        void testBulkDocument() throws IOException {
            BulkRequest bulkRequest = new BulkRequest();
            bulkRequest.timeout("10s");
    
            ArrayList<User> users = new ArrayList<>();
            users.add(new User("jack", 11));
            users.add(new User("july", 22));
            users.add(new User("john", 15));
            users.add(new User("dick", 32));
            users.add(new User("lily", 19));
            users.add(new User("lucy", 20));
    
            //批量处理请求
            for (int i = 0; i < users.size(); i++) {
                bulkRequest.add(
                        new IndexRequest("my_index")
                        .id(""+(i+1))
                        .source(JSON.toJSONString(users.get(i)), XContentType.JSON)
                );
            }
            BulkResponse bulkItemResponses = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
            System.out.println(bulkItemResponses.hasFailures());  //返回false即为成功
        }
    
    
        //查询
        @Test
        void testSearch() throws IOException {
            SearchRequest searchRequest = new SearchRequest("my_index");
            //构建搜索条件
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            //查询条件,我们可以使用QueryBuilders工具来实现
            TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", "lucy");
            sourceBuilder.query(termQueryBuilder);
            sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
    
            searchRequest.source(sourceBuilder);
    
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            System.out.println(JSON.toJSONString(searchResponse.getHits()));
            System.out.println("----------------------------");
            for (SearchHit documentFields : searchResponse.getHits().getHits()) {
                System.out.println(documentFields.getSourceAsMap());
            }
        }

    三、实战

    3.1创建项目

    1)添加依赖

             <!--        解析网页-->
            <dependency>
                <groupId>org.jsoup</groupId>
                <artifactId>jsoup</artifactId>
                <version>1.10.2</version>
            </dependency>   
    
    
            <!-- 阿里fastjson包JSON转换-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.47</version>
            </dependency>

    2)项目结构

    3.2源码

    1)Content.java

    package com.example.jdsearch.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class Content {
        private String img;
        private String price;
        private String title;
    
    }

    2)ContentService

    package com.example.jdsearch.service;
    
    
    import com.alibaba.fastjson.JSON;
    import com.example.jdsearch.pojo.Content;
    import com.example.jdsearch.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.QueryBuilders;
    import org.elasticsearch.index.query.TermQueryBuilder;
    import org.elasticsearch.search.SearchHit;
    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.List;
    import java.util.Map;
    import java.util.concurrent.TimeUnit;
    
    @Service
    public class ContentService {
        @Autowired
        private RestHighLevelClient restHighLevelClient;
    
    
        //解析数据并将数据放入es
        public Boolean parse(String keywords) throws IOException {
            List<Content> contents = new HtmlParseUtil().parse(keywords);
    
            //把查询到的数据放入es
            BulkRequest bulkRequest = new BulkRequest();
            bulkRequest.timeout("3m");
    
    
            //批量处理请求
            for (int i = 0; i < contents.size(); i++) {
                bulkRequest.add(
                        new IndexRequest("jd_index")
                                .source(JSON.toJSONString(contents.get(i)), XContentType.JSON)
                );
            }
            BulkResponse bulkItemResponses = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
            return !bulkItemResponses.hasFailures();  //返回false即为成功
    
        }
    
    
        //搜索
        public List<Map<String, Object>> search(String keywords, Integer pageNo, Integer pageSize) throws IOException {
            if(pageNo <= 1)
                pageNo = 1;
    
            //条件搜索
            SearchRequest searchRequest = new SearchRequest("jd_index");
            //构建搜索条件
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    
            //分页
            sourceBuilder.from(pageNo);
            sourceBuilder.size(pageSize);
    
            //查询条件,我们可以使用QueryBuilders工具来实现
            TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", keywords);
            sourceBuilder.query(termQueryBuilder);
            sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
    
    
            //高亮
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.field("title");
            highlightBuilder.requireFieldMatch(false);//是否需要多个高亮显示
            highlightBuilder.preTags("<span style='color:red'>");
            highlightBuilder.postTags("</span>");
            sourceBuilder.highlighter(highlightBuilder);
    
            //执行结果
            searchRequest.source(sourceBuilder);
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    
            //解析结果
            ArrayList<Map<String, Object>> list = new ArrayList<>();
            for (SearchHit documentFields : searchResponse.getHits().getHits()) {
                Map<String, HighlightField> highlightFields = documentFields.getHighlightFields();
                HighlightField title = highlightFields.get("title");
                Map<String, Object> sourceAsMap =  documentFields.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;
        }
    
    
    
    }

    3)HtmlParseUtil

    package com.example.jdsearch.utils;
    
    import com.example.jdsearch.pojo.Content;
    import org.jsoup.Jsoup;
    import org.jsoup.nodes.Document;
    import org.jsoup.nodes.Element;
    import org.jsoup.select.Elements;
    
    import java.io.IOException;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.util.ArrayList;
    import java.util.List;
    
    public class HtmlParseUtil {
        public static void main(String[] args) throws IOException {
            HtmlParseUtil htmlParseUtil = new HtmlParseUtil();
           List<Content> contents = htmlParseUtil.parse("java");
           contents.forEach(System.out::println);
    
        }
    
    
        public List<Content> parse(String keywords) throws IOException {
            //准备url
            String url = "https://search.jd.com/Search?keyword="+keywords;
            //解析网页,jsoup返回的document对象就是js中的document对象
            Document document = Jsoup.parse(new URL(url), 30000);
            Element j_goodsList = document.getElementById("J_goodsList");
    
            List<Content> contents = new ArrayList<>();
    
            //获取所有的li元素
            Elements elements = j_goodsList.getElementsByTag("li");
            for (Element element : elements) {
                String img = element.getElementsByTag("img").eq(0).attr("data-lazy-img");  //图片延迟加载,不在src
                String price = element.getElementsByClass("p-price").eq(0).text();
                String title = element.getElementsByClass("p-name").eq(0).text();
    
                contents.add(new Content(img, price, title));
    
            }
    
            return contents;
        }
    }

    4)ContentController

    package com.example.jdsearch.web;
    
    import com.example.jdsearch.service.ContentService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    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;
    
    
        //爬取数据
        @RequestMapping("/parse/{keywords}")
        public Boolean parse(@PathVariable("keywords") String keywords) throws IOException {
            return contentService.parse(keywords);
    
        }
    
        //查询数据
        @RequestMapping("/search/{keywords}/{pageNo}/{pageSize}")
        public List<Map<String, Object>> search(
                @PathVariable("keywords") String keywords,
                @PathVariable("pageNo") Integer pageNo,
                @PathVariable("pageSize") Integer pageSize) throws IOException {
    
            return contentService.search(keywords, pageNo, pageSize);
    
        }
    }

    5)IndexController

    package com.example.jdsearch.web;
    
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.GetMapping;
    
    @Controller
    public class IndexController {
    
        @GetMapping({"/", "/index"})
        public String index(){
            return "index";
    
        }
    
    }

    6)index.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}"/>
    
    </head>
    
    <body class="pg">
    <div class="page" id="app">
        <div id="mallPage" 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 type="text" autocomplete="off" value="dd" id="mq"
                                                           class="s-combobox-input" aria-haspopup="true" v-model="keywords">
                                                </div>
                                            </div>
                                            <button type="submit" id="searchbtn" @click.prevent="search">搜索</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="item in items">
                            <div class="product-iWrap">
                                <!--商品封面-->
                                <div class="productImg-wrap">
                                    <a class="productImg">
                                        <img :src="item.img">
                                    </a>
                                </div>
                                <!--价格-->
                                <p class="productPrice">
                                    <em>{{item.price}}</em>
                                </p>
                                <!--标题-->
                                <p class="productTitle">
                                    <a v-html="item.title"> </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>
    
        const app = new Vue({
            el: "#app",
            data:{
                keywords:"",
                items: []
            },
            methods:{
                search: function () {
                    axios.get("/search/"+this.keywords+"/1/10").then(result => {
                        this.items = result.data;
                    })
    
                }
            }
        })
    
    
    </script>
    
    </body>
    </html>
    View Code

    7)application.properties

    spring.thymeleaf.cache=false
    
    server.port=9090

    3.3实现效果

  • 相关阅读:
    AngularJS Insert Update Delete Using PHP MySQL
    Simple task manager application using AngularJS PHP MySQL
    AngularJS MySQL and Bootstrap Shopping List Tutorial
    Starting out with Node.js and AngularJS
    AngularJS CRUD Example with PHP, MySQL and Material Design
    How to install KVM on Fedora 22
    Fake_AP模式下的Easy-Creds浅析
    河南公务员写古文辞职信
    AI
    政协委员:最大愿望是让小学生步行上学
  • 原文地址:https://www.cnblogs.com/dominik/p/14031238.html
Copyright © 2011-2022 走看看