美文网首页
ElasticSearch 入门文档 2021-09-26 至

ElasticSearch 入门文档 2021-09-26 至

作者: 鄙人_阿K | 来源:发表于2021-10-06 23:41 被阅读0次

    分布式框架中间件总纲

    https://www.jianshu.com/p/00aa796bb5b8

    友情链接

    ElasticSearch 安装(docker)

    目录

    一、ElasticSearch 概述
    二、ES 核心概念
    三、IK 分词器插件
    四、Rest 风格说明
    五、关于索引的基本操作
    六、关于文档的基本操作
    七、集成 SpringBoot
    八、案例
          1、爬虫
          2、前后端分离
          3、搜索高亮

    一、ElasticSearch 概述

    1、什么是 ElasticSearch

    The Elastic Stack, 包括 Elasticsearch、Kibana、Beats 和 Logstash(也称为 ELK Stack)。能够安全可靠地获取任何来源、任何格式的数据,然后实时地对数据进行搜索、分析和可视化。Elaticsearch,简称为ES, ES是一个开源的高扩展的分布式全文搜索引擎,是整个Elastic Stack技术栈的核心。它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器,处理PB级别的数据。

    2、全文搜索引擎

    1、Google,百度类的网站搜索,它们都是根据网页中的关键字生成索引,我们在搜索的时候输入关键字,它们会将该关键字即索引匹配到的所有网页返回;还有常见的项目中应用日志的搜索等等。对于这些非结构化的数据文本,关系型数据库搜索不是能很好的支持。
    2、一般传统数据库,全文检索都实现的很鸡肋,因为一般也没人用数据库存文本字段。进行全文检索需要扫描整个表,如果数据量大的话即使对SQL的语法优化,也收效甚微。建立了索引,但是维护起来也很麻烦,对于 insert 和 update 操作都会重新构建索引。
    3、基于以上原因可以分析得出,在一些生产环境中,使用常规的搜索方式,性能是非常差的:
    搜索的数据对象是大量的非结构化的文本数据。
    文件记录量达到数十万或数百万个甚至更多。
    支持大量基于交互式文本的查询。
    需求非常灵活的全文搜索查询。
    对高度相关的搜索结果的有特殊需求,但是没有可用的关系数据库可以满足。
    对不同记录类型、非文本数据操作或安全事务处理的需求相对较少的情况。
    4、为了解决结构化数据搜索和非结构化数据搜索性能问题,我们就需要专业,健壮,强大的全文搜索引擎
    这里说到的全文搜索引擎指的是目前广泛应用的主流搜索引擎。它的工作原理是计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。这个过程类似于通过字典中的检索字表查字的过程。

    3、Elasticsearch And Solr 的区别

    Lucene是Apache软件基金会Jakarta项目组的一个子项目,提供了一个简单却强大的应用程式接口,能够做全文索引和搜寻。在Java开发环境里Lucene是一个成熟的免费开源工具。就其本身而言,Lucene是当前以及最近几年最受欢迎的免费Java信息检索程序库。但Lucene只是一个提供全文搜索功能类库的核心工具包,而真正使用它还需要一个完善的服务框架搭建起来进行应用。
    目前市面上流行的搜索引擎软件,主流的就两款:Elasticsearch和Solr,这两款都是基于Lucene搭建的,可以独立部署启动的搜索引擎服务软件。由于内核相同,所以两者除了服务器安装、部署、管理、集群以外,对于数据的操作 修改、添加、保存、查询等等都十分类似。
    在使用过程中,一般都会将Elasticsearch和Solr这两个软件对比,然后进行选型。这两个搜索引擎都是流行的,先进的的开源搜索引擎。它们都是围绕核心底层搜索库 - Lucene构建的 - 但它们又是不同的。像所有东西一样,每个都有其优点和缺点:


    image.png

    5、Elasticsearch Or Solr 的选型

    Google搜索趋势结果表明,与 Solr 相比,Elasticsearch具有很大的吸引力,但这并不意味着Apache Solr已经死亡。虽然有些人可能不这么认为,但Solr仍然是最受欢迎的搜索引擎之一,拥有强大的社区和开源支持。
    与Solr相比,Elasticsearch易于安装且非常轻巧。此外,你可以在几分钟内安装并运行Elasticsearch。但是,如果Elasticsearch管理不当,这种易于部署和使用可能会成为一个问题。基于JSON的配置很简单,但如果要为文件中的每个配置指定注释,那么它不适合您。总的来说,如果你的应用使用的是JSON,那么Elasticsearch是一个更好的选择。否则,请使用Solr,因为它的schema.xml和solrconfig.xml都有很好的文档记录。
    Solr拥有更大,更成熟的用户,开发者和贡献者社区。ES虽拥有的规模较小但活跃的用户社区以及不断增长的贡献者社区。
    Solr贡献者和提交者来自许多不同的组织,而Elasticsearch提交者来自单个公司。
    Solr更成熟,但ES增长迅速,更稳定。
    Solr是一个非常有据可查的产品,具有清晰的示例和API用例场景。 Elasticsearch的文档组织良好,但它缺乏好的示例和清晰的配置说明。

    由于易于使用,Elasticsearch在新开发者中更受欢迎。一个下载和一个命令就可以启动一切。
    如果除了搜索文本之外还需要它来处理分析查询,Elasticsearch是更好的选择
    如果需要分布式索引,则需要选择Elasticsearch。对于需要良好可伸缩性和以及性能分布式环境,Elasticsearch是更好的选择。
    Elasticsearch在开源日志管理用例中占据主导地位,许多组织在Elasticsearch中索引它们的日志以使其可搜索。
    如果你喜欢监控和指标,那么请使用Elasticsearch,因为相对于Solr,Elasticsearch暴露了更多的关键指标

    6、Elasticsearch 应用案例

    GitHub: 2013年初,抛弃了Solr,采取Elasticsearch 来做PB级的搜索。“GitHub使用Elasticsearch搜索20TB的数据,包括13亿文件和1300亿行代码”。
    维基百科:启动以Elasticsearch为基础的核心搜索架构
    SoundCloud:“SoundCloud使用Elasticsearch为1.8亿用户提供即时而精准的音乐搜索服务”。
    百度:目前广泛使用Elasticsearch作为文本数据分析,采集百度所有服务器上的各类指标数据及用户自定义数据,通过对各种数据进行多维分析展示,辅助定位分析实例异常或业务层面异常。目前覆盖百度内部20多个业务线(包括云分析、网盟、预测、文库、直达号、钱包、风控等),单集群最大100台机器,200个ES节点,每天导入30TB+数据。
    新浪:使用Elasticsearch分析处理32亿条实时日志。
    阿里:使用Elasticsearch构建日志采集和分析体系。
    Stack Overflow:解决Bug问题的网站,全英文,编程人员交流的网站。

    二、ES 核心概念

    1、ElasticSearch 是面向文档的,关系行数据库 和 ElasticSearch 客观对比 【一切皆为JSON】
    image.png

    elasticsearch(集群)中可以包含多个索引(数据库),每个索引中可以包含多个类型(表),每个类型下又包含多个文档(行),每个文档中又包含多个字段(列)。

    2、物理设计:

    elasticsearch在后台把每个索引划分成多个分片,每片分片可以在集群中的不同服务器间迁移一个人就是一个集群!默认的集群名称就是elaticsearh


    image.png
    3、逻辑设计:

    一个索引类型中,包含多个文档,比如说文档1,文档2。当我们索引一篇文档时,可以通过这样的一各顺序找到它:
    索引 -> 类型 -> 文档ID,通过这个组合我们就能索引到某个具体的文档。注意:ID不必是整数,实际上它是个字符串。

    1、文档:就是一条数据

    1       阿K    18      码农
    2       K桑    32      CTO
    

    之前说elasticsearch是面向文档的,那么就意味着索引和搜索数据的最小单位是文档,elasticsearch中,文档有几个重要属性:
    (1)自我包含,一篇文档同时包含字段和对应的值,也就是同时包含key:value
    (2)可以是层次型的,一个文档中包含自文档,复杂的逻辑实体就是这么来的!{就是一个json对象! fastijson进行自动转换!}
    (3)灵活的结构,文档不依赖预先定义的模式,我们知道关系型数据库中,要提前定义字段才能使用,在elasticsearch中,对于字段是非常灵活的,有时候,我们可以忽略该字段,或者动态的添加一个新的字段。

    尽管我们可以随意的新增或者忽略某个字段,但是,每个字段的类型非常重要,比如一个年龄字段类型,可以是字符串也可以是整型。因为elasticsearch会保存字段和类型之间的映射及其他的设置。这种映射具体到每个映射的每种类型,这也是为什么在 elasticsearch中,类型有时候也称为映射类型。

    2、类型:已经废弃,看看就好,没啥用


    image.png

    类型是文档的逻辑容器,就像关系型数据库一样,表格是行的容器。类型中对于字段的定义称为映射,比如name映射为字符串类型。我们说文档是无模式的,它们不需要拥有映射中所定义的所有字段,比如新增一个字段,那么elasticsearch是怎么做的呢?elasticsearch会自动的将新字段加入映射,但是这个字段的不确定它是什么类型,elasticsearch就开始猜,如果这个值是18,那么elasticsearch会认为它是整形。但是elasticsearch也可能猜不对,所以最安全的方式就是提前定义好所需要的映射,这点跟关系型数据库殊途同归了,先定义好字段,然后再使用,别整什么鸡儿。

    3、索引:就是数据库
    索引是映射类型的容器,elasticsearch中的索引是一个非常大的文档集合。索引存储了映射类型的字段和其他设置。然后它们被存储到了各个分片上了。臭宝,我们来研究下分片是如何工作的吧。

    物理设计: 节点和分片如何工作?
    一个集群至少有一个节点,而一个节点就是一个elasricsearch进程,节点可以有多个索引默认的,如果你创建索引,那么索引将会有个5个分片( primary shard ,又称主分片)构成的,每一个主分片会有一个副本( replica shard ,又称复制分片)


    image.png

    上图是一个有3个节点的集群,可以看到主分片和对应的复制分片都不会在同一个节点内,这样有利于某个节点挂掉了,数据也不至于丢失。实际上,一个分片是一个Lucene索引,一个包含倒排索引的文件目录,倒排索引的结构使得elasticsearch在不扫描全部文档的情况下,就能告诉你哪些文档包含特定的关键字。不过,等等,倒排索引是什么呢?

    4、倒排索引
    elasticsearch 使用的是一种称为倒排索引的结构,采用 Lucene倒排索作为底层。这种结构适用于快速的全文搜索,一个索引由文档中所有不重复的列表构成,对于每一个词,都有一个包含它的文档列表。例如,现在有两个文档,每个文档包含如下内容:

    study every day,good good up to forever     # 文档1包含的内容
    To forever,study every day,good good up    #文档2包含的内容
    

    为了创建倒排索引,我们首先要将每个文档拆分成独立的词(或称为词条或者tokens),然后创建一个包含所有不重复的词条的排序列表,然后列出每个词条出现在哪个文档:

    image.png

    现在,我们试图搜索to forever,只需要查看包含每个词条的文档 分数(权重)


    image.png

    两个文档都匹配,但是第一个文档比第二个匹配程度更高。如果没有别的条件,现在,这两个包含关键字的文档都将返回

    案例2:
    image.png
    image.png

    如果要搜索含有python标签的文章,那相对于查找所有原始数据而言,查找倒排索引后的数据将会快的多。只需要查看标签这一栏,然后获取相关的文章ID即可。|

    ★ elasticsearch的索引和Lucene的索引对比

    在elasticsearch中,索引这个词被频繁使用,这就是术语的使用。在elasticsearch中,索引被分为多个分片,每份分片是一个Lucene的索引。所以一个elasticsearch索引是由多个Lucene索引组成的。别问为什么,谁让elasticsearch使用Lucene作为底层呢!如无特指,说起索引都是指elasticsearch的索引。

    三、IK 分词器插件

    1、什么是 IK 分词器
    分词:即把一段中文或者别的划分成一个个的关键字,我们在搜索时候会把自己的信息进行分词,会把数据库中或者索引库中的数据进行分词,然后进行一个匹配操作,默认的中文分词是将每个字看成一个词,比如“我爱阿K"会被为"我""爱""阿""K”,这显然是不符合要求的,所以我们需要安装中文分词器ik来解决这个问题。如果要使用中文,建议使用ik分词器

    IK提供了两个分词算法:∶ ik_smart和ik_max_word,其中ik_smart为最少切分,ik_max_word为最细粒度划分!

    2、安装:直接解压到 es 的 plugins 文件夹下
    下载地址:https://github.com/medcl/elasticsearch-analysis-ik/releases

    (1)进入es 控制台:docker exec -it 71a0 /bin/bash

    image.png

    (2)进入 plugins 文件夹下 创建 IK文件夹,下载文件
    创建文件夹:mkdir /plugins /plugins

    安装wget:yum install wget
    下载版本:wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.4.2/elasticsearch-analysis-ik-7.4.2.zip

    (3)解压:unzip elasticsearch-analysis-ik-7.4.2.zip

    (4)删除:rm -rf elasticsearch-analysis-ik-7.4.2.zip

    (5)重启镜像:docker restart 71a0

    3、用 kibana 测试 分词器、
    (1)测试ik_smart (最少切分) and ik_max_word (最细粒度划分)

    GET _analyze
    {
       "analyzer":"ik_max_word" ,   
       "text": "我喜欢一个人"
    }
     
    
    image.png
    GET _analyze
    {
      "analyzer":"ik_smart" ,   
       "text": "我喜欢一个人"
    }
     
    

    (2)测试 阿K,吹牛逼 词条,发现用最少切分也被拆开;随意需要自定义词典


    image.png

    4、配置自定义分词器
    (1)找到配置文件


    image.png image.png

    (2)创建对应的自定义词典,内容:阿K,吹牛逼;文件名为 ak.dic,在 ik 文件夹下
    vi plugins/ik/config/ak.dic

    image.png

    (3)修改配置 IKAnalyzer.cfg.xml,引入 ak.dic
    打开配置文件:vi IKAnalyzer.cfg.xml
    如果用 vi打开乱码::set encoding=utf8,调整
    写入配置:

    image.png

    (4)重启镜像:docker restart 71a0

    四、Rest 风格说明

    一种软件架构风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

    基本rest命令:


    image.png

    1、创建一个索引

    PUT  /索引名/类型名字/文档 id
    {
          请求体
    }
    
    image.png

    2、创建索引规则,声明字段类型


    image.png

    3、查看 创建好的索引规则


    image.png

    4、7x版本后,废弃了类型,默认类型为 _doc,默认为字段提供类型


    image.png

    4、查看索引(库)信息


    image.png

    5、修改一:前面的饿值会被覆盖


    image.png

    6、修改二:灵活性更好,指定修改对应值


    image.png

    7、删除


    image.png

    五、关于文档的基本操作(查询)

    1、简单查询

    插入测试数据

    PUT /mykk/user/1
    {
      "name":"阿K11",
      "age":18,
      "bir":"1997-06-06",
      "tags":["英俊","帅气","执着"]
    }
    
    PUT /mykk/user/2
    {
      "name":"阿K22",
      "age":22,
      "bir":"1997-06-06",
      "tags":["英俊","帅气","渣男"]
    }
    
    PUT /mykk/user/3
    {
      "name":"阿K33",
      "age":23,
      "bir":"1997-06-06",
      "tags":["英俊","帅气","美丽"]
    }
    

    (1)最简单的查询 :


    image.png

    (2)条件查询:


    image.png
    2、复杂查询 select(排序,分页,高亮,模糊,精准查询)

    (1)简单条件的变种写法


    image.png

    (2)输出指定字段


    image.png

    (3)排序:


    image.png

    (4)分页:from 是从0开始的


    image.png

    (5)多条件匹配【and】:must 所有条件都要符合 eg: where id =1 and name =mykk


    image.png

    (6)多条件匹配【or 】:should 所有条件都要符合 eg: where id =1 or name =mykk


    image.png

    (7)多条件匹配【not 】:must_not 所有条件都要符合 eg: where id !=1


    image.png

    (8)多条件匹配【 filter 】:filter 所有条件都要符合 【 gt 是大于,gte 是大于等于,lt 小于, lte 小于等于 】


    image.png
    3、精确查询详解

    term 查询是通过倒排索引指定的词条进程精确查找

    1、关于分词
    (1)term ,直接查询精确的
    (2)match,会使用分词器解析(先分析文档,然后再通过分析的文档进行查询)

    两个类型 text , keyword
    text:会被分词器解析,拆分掉查询
    keyword:不会被分词器解析,不可再分

    4、高亮搜索
    image.png

    六、集成 SpringBoot

    1、看文档:https://www.elastic.co/guide/index.html

    (1)找到es的客户端 用于开发连接


    image.png

    (2)找到java rest版的


    image.png

    (3)选择高级版


    image.png

    (4)找到maven依赖


    image.png
    image.png
            <dependency>
                <groupId>org.elasticsearch.client</groupId>
                <artifactId>elasticsearch-rest-high-level-client</artifactId>
                <version>7.4.2</version>
            </dependency>
    

    (5)初始化对象


    image.png
    2、实操【索引】

    (1)创建springboot新工程勾选


    image.png

    (2)编写配置

    @Configuration
    public class ElasticSearchClientConfig {
    
        @Bean
        public RestHighLevelClient restHighLevelClient() {
            return new RestHighLevelClient (
                    RestClient.builder (
                            new HttpHost ("101.34.180.131", 9200, "http")));
        }
    }
    

    (3)创建索引

    @SpringBootTest
    class ElasticshedemoApplicationTests {
    
        @Autowired
        @Qualifier("restHighLevelClient")
        private RestHighLevelClient client;
        
        // 测试创建索引   request   PUT  mykk_demo1
        @Test
        void testCreateIndex() throws Exception{
            // 1、创建索引请求
            CreateIndexRequest request = new CreateIndexRequest ("mykk_demo1");
            // 2、客户端执行请求 IndicesClient ,请求后获取响应
            CreateIndexResponse createIndexResponse = client.indices ( ).create (request, RequestOptions.DEFAULT);
    
            System.out.println (createIndexResponse );
        }
    
    }
    

    (4)索引是否存在

        // 测试获取索引
        // 存在返回  true
        @Test
        void testExistIndex()throws Exception{
            GetIndexRequest request = new GetIndexRequest ("mykk_demo1");
            boolean exists = client.indices ( ).exists (request, RequestOptions.DEFAULT);
            System.out.println (exists );
        }
    

    (5)删除索引

        // 测试删除索引
        @Test
        void testDeleteIndex()throws Exception{
            DeleteIndexRequest req = new DeleteIndexRequest ("mykk_demo1");
            AcknowledgedResponse delete = client.indices ( ).delete (req, RequestOptions.DEFAULT);
            System.out.println (delete.isAcknowledged () );
        }
    
    3、实操【文档】

    (1)添加文档

       // 测试文档添加
        @Test
        void testAddDocument()throws Exception{
            User user = new User ("阿K", 18);
    
            // 创建请求
            IndexRequest request = new IndexRequest ("mykk_demo1");
    
            // 请求体  put /mykk_demo1/_doc/1
            request.id ("1");
            request.timeout ("1s"); // 设置超时
    
            // 将数据放入请求  json
            request.source (JSON.toJSONString (user),XContentType.JSON);
    
            // 客户端发送请求,获取响应结果
            IndexResponse indexResponse = client.index (request, RequestOptions.DEFAULT);
            System.out.println (indexResponse.toString () );
            System.out.println (indexResponse.status () );
    
        }
    

    (2)判断文档是否存在

        // 测试文档是否存在
        @Test
        void testExitsDocument() throws Exception{
            GetRequest getRequest = new GetRequest ("mykk_demo1", "1");
    
            // 不获取返回的 _source 上下文信息(提高效率)
            getRequest.fetchSourceContext (new FetchSourceContext (false));
            getRequest.storedFields ("_none_");
    
            boolean exists = client.exists (getRequest, RequestOptions.DEFAULT);
            System.out.println (exists );
        }
    

    (3)获取文档记录

        // 测试获取文档信息
        @Test
        void testGetDocument() throws Exception{
            GetRequest getRequest = new GetRequest ("mykk_demo1", "1");
    
            // 获取文档内容
            GetResponse response = client.get (getRequest, RequestOptions.DEFAULT);
            // 打印文档的内容
            System.out.println (response.getSourceAsString () );
            System.out.println (response );
        }
    

    (4)更新文档记录

        // 测试更新文档信息
        @Test
        void testUpdateDocument() throws Exception{
            // 获取文档
            UpdateRequest updateRequest = new UpdateRequest ("mykk_demo1", "1");
            updateRequest.timeout ("1s");
    
    
            User user = new User ("阿K", 23);
            updateRequest.doc (JSON.toJSONString (user),XContentType.JSON);
    
            UpdateResponse updateResponse = client.update (updateRequest, RequestOptions.DEFAULT);
            System.out.println (updateResponse.status () );
        }
    

    (6)删除文档记录

        // 测试删除文档信息
        @Test
        void testDeleteDocument() throws Exception{
            DeleteRequest deleteRequest = new DeleteRequest ("mykk_demo1", "1");
            deleteRequest.timeout ("1s");
    
            DeleteResponse deleteResponse = client.delete (deleteRequest, RequestOptions.DEFAULT);
            System.out.println (deleteResponse.status () );
        }
    

    (5)插入文档记录

        // 测试批量文档记录
        @Test
        void testBulkDocument() throws Exception{
            BulkRequest bulkRequest = new BulkRequest ( );
            bulkRequest.timeout ("10s");
    
            ArrayList<User> userList = new ArrayList<> ( );
            userList.add (new User ("阿K1",1));
            userList.add (new User ("阿K2",3));
            userList.add (new User ("阿K3",5));
            userList.add (new User ("阿K4",7));
            userList.add (new User ("阿K5",9));
    
            // 批处理请求
            for (int i = 0; i < userList.size ( ); i++) {
                // 批量更新和删除,在这里修改对应请求即可
                bulkRequest.add (new IndexRequest ("mykk_demo1")
                .id (""+(i+1))
                .source (JSON.toJSONString (userList.get (i)),XContentType.JSON));
            }
    
            BulkResponse bulkResponse = client.bulk (bulkRequest, RequestOptions.DEFAULT);
            System.out.println (bulkResponse.hasFailures () );// 是否成功,false 代表成功
        }
    

    (7)查询

        // 查询
        // SearchRequest 搜索请求
        // SearchSourceBuilder 条件构造
        //  HighlightBuilder 构建高亮
        //  TermQueryBuilder 精确查询
        //  MatchAllQueryBuilder 精确所有
        @Test
        // 记住存入的要查询的不能是中文,因为还没有处理
        void testSearch() throws Exception{
    
            SearchRequest searchRequest = new SearchRequest ("mykk_demo1");
            // 构建搜索条件
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder ( );
            sourceBuilder.highlighter ();
    
            // 查询条件:可以使用 QueryBuilders 工具来实现
            // QueryBuilders.termQuery 精确
            // QueryBuilders.matchAllQuery () 匹配所有
            TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery ("name", "ak1");
            // MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery ( );
            sourceBuilder.query (termQueryBuilder);
            sourceBuilder.timeout (new TimeValue (60, TimeUnit.SECONDS));
    
            searchRequest.source (sourceBuilder);
    
            SearchResponse searchResponse = client.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 () );
            }
        }
    

    七、案例(模拟京东)

    搭建项目


    image.png

    导入静态文件
    狂神百度云链接:https://pan.baidu.com/s/1PT3jLvCksOhq7kgAKzQm7g 提取码:s824

    1、爬虫

    (1)去京东官网,找到url搜索规则:https://search.jd.com/Search?keyword=java

    image.png

    (2)编写配置文件

    # 应用名称
    spring.application.name=jingdongelactichserchdemo
    # 应用服务 WEB 访问端口
    server.port=8080
    # THYMELEAF (ThymeleafAutoConfiguration)
    # 开启模板缓存(默认值: true )
    spring.thymeleaf.cache=false
    spring.elasticsearch.rest.uris= 101.34.180.131:9200
    

    (3)导入网页解析的依赖,不支持视频的

            <!--解析网页-->
            <dependency>
                <groupId>org.jsoup</groupId>
                <artifactId>jsoup</artifactId>
                <version>1.10.2</version>
            </dependency>
    

    (4)封装对象用于映射每个爬取的商品(li标签)


    image.png

    (5)爬取京东的搜索工具方法

    @Component
    public class HtmlParseUtil {
    
        public static void main(String[] args)throws Exception {
            parseJD ("阿K").forEach (System.out::println);
        }
    
        /**
         * 用于搜索返回商品爬取数据
         * @param keyword     用于搜索
         * @return            返回商品集合爬取的数据
         * @throws Exception
         */
        public static List<Content> parseJD(String keyword) throws Exception{
            // 爬取的url :https://search.jd.com/Search?keyword=java
            // &enc=urt8 解决中文传参问题
            String url = "https://search.jd.com/Search?keyword="+keyword+"&enc=urt8";
            // Document 既是 html的 Document对象
            Document document = Jsoup.parse (new URL (url), 30000);
            // 所有 js操作 dom的方法这里都有
            Element element = document.getElementById ("J_goodsList");
            // 获取所有的 li元素
            Elements elements = element.getElementsByTag ("li");
    
            // 根据打印找出懒加载图片的 赋值标签,data-lazy-img
            //System.out.println (elements );
    
            // 获取元素中的内容,这里 el 就是每一个 li 标签
            ArrayList<Content> contents = new ArrayList<> ( );
            for (Element el : elements) {
                // 关于这种图片特别多的网站,采用的是延迟加载
                // source-data-lazy-img
                String img = el.getElementsByTag ("img").eq (0).attr ("data-lazy-img");
                String price = el.getElementsByClass ("p-price").eq (0).text ();
                String title = el.getElementsByClass ("p-name").eq (0).text ();
                contents.add (new Content (title,img,price));
            }
            return contents;
        }
    }
    

    (6)编写搜索爬的数据,存储到 es 中

    Controller
    @RestController
    public class ContextController {
    
        @Autowired
        private ContextService contextService;
    
    
        // 爬数据,存es
        @GetMapping("/parse/{keyword}")
        public Boolean parse(@PathVariable("keyword") String keyword)throws Exception{
            return contextService.parseContext (keyword);
        }
    
        // 分页查询
        @GetMapping("/search/{keyword}/{pageNo}/{pageSize}")
        public List<Map<String,Object>> search(
                @PathVariable("keyword")  String keyword,
                @PathVariable("pageNo")   int pageNo,
                @PathVariable("pageSize") int pageSize
        )throws Exception{
            return contextService.searchPage (keyword,pageNo,pageSize);
        }
    }
    
    Servoce
    @Service
    public class ContextService {
    
        @Autowired
        private RestHighLevelClient client;
    
        // 1、解析数据放入 es 索引中
        public boolean parseContext(String keyword) throws Exception{
            List<Content> contents = HtmlParseUtil.parseJD (keyword);
    
            // 将查询的数据存入 es中
            BulkRequest bulkRequest = new BulkRequest ( );
            bulkRequest.timeout ("2m");// 超时2分钟放弃
    
            for (int i = 0; i < contents.size ( ); i++) {
                bulkRequest.add (new IndexRequest ("jd_goods")
                .source (JSON.toJSONString (contents.get (i)),XContentType.JSON));
            }
    
            BulkResponse bulk = client.bulk (bulkRequest, RequestOptions.DEFAULT);
            return !bulk.hasFailures ();
        }
    
        // 2、搜索获取数据,分页功能
        public List<Map<String,Object>> searchPage(String keyword,int pageNo,int pageSize)throws Exception{
            if (pageNo<=1){
                pageNo=1;
            }
    
            // 条件搜索
            SearchRequest searchRequest = new SearchRequest ("jd_goods");
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder ( );
    
            // 分页
            sourceBuilder.from (pageNo);
            sourceBuilder.size (pageSize);
    
            // 精确匹配
            // TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", keyword);无法解决中文搜索
            MatchQueryBuilder termQueryBuilder = QueryBuilders.matchQuery ("title", keyword);
            sourceBuilder.query (termQueryBuilder);
            sourceBuilder.timeout (new TimeValue (60, TimeUnit.SECONDS));
    
            // 执行搜索
            searchRequest.source (sourceBuilder);
            SearchResponse searchResponse = client.search (searchRequest, RequestOptions.DEFAULT);
            // 解析结果
            ArrayList<Map<String, Object>> list = new ArrayList<> ( );
            for (SearchHit documentFields : searchResponse.getHits ( ).getHits ( )) {
                list.add (documentFields.getSourceAsMap ());
            }
            return list;
        }
    
    2、前后端分离

    (1)运行两条命令

    npm install vue
    
    npm install axios
    

    (2)将 node.js 初始化的,找到 两个js 放入工程的静态文件中


    image.png

    (3)引入编写对应js代码

    <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;
                    axios.get('search/'+keyword+'/1/10').then(response=>{
                        console.log(response);
                        this.results = response.data;
                    });
                }
            }
        });
    </script>
    
    image.png
    image.png
    3、搜索高亮

    1、改写 service的搜索分页


    image.png

    2、改写页面的显示


    image.png

    3、效果


    image.png

    文章参考B站:狂神说,尚硅谷以及一些博客

    相关文章

      网友评论

          本文标题:ElasticSearch 入门文档 2021-09-26 至

          本文链接:https://www.haomeiwen.com/subject/wqufnltx.html