ElasticsSearch7.6.1学习笔记【狂神说Java】

news2024/11/17 21:38:03

文章目录

  • 一、ElasticSearch概述
  • 二、安装elasticsearch-7.6.1,基于windows 10
    • 1、解压安装包以及目录结构介绍
    • 2、安装可视化插件elasticsearch-head
    • 3、解决跨域问题
  • 三、安装Kibana
  • 四、核心概念
  • 五、IK分词器插件
    • 1、什么是ik分词器
    • 2、解压
    • 3、进入kibana测试
    • 4、自定义扩展词汇
  • 六、Rest风格说明
    • 1、基本Rest命令说明:
    • 2、添加索引
    • 3、基本数据类型
    • 4、其他命令
    • 5、修改索引
    • 6、查询
      • 1、简单查询
      • 2、复杂查询
        • 1、条件查询
        • 2、指定只显示的字段
        • 3、排序分页查询
        • 4、must、must_not、should
        • 5、数据过滤
        • 6、匹配多个条件
        • 7、精确查询
        • 8、高亮查询
  • 七、集成spring boot
    • 1、创建springboot项目
    • 2、创建elasticsearch客户端构造器
    • 3、测试索引库的API操作
      • 1、测试创建索引库
      • 2、测试判断索引库是否存在
      • 3、测试删除索引库
    • 4、测试文档API的操作
      • 1、添加文档
      • 2、获取文档内容
      • 3、更新文档数据
      • 4、删除文档数据
      • 5、批量导入数据
      • 6、批量查询
  • 八、模拟京东商品搜索
    • 1、新建springboot项目,导入静态资源
    • 2、获取京东网页上的数据
    • 3、将数据写入elasticSearch中
    • 4、精准匹配查询es的数据,并分页显示
    • 5、修改前端,使用vue、axios
    • 6、对接后端的接口
    • 7、高亮显示

学习视频来源: 【狂神说Java】ElasticSearch7.6.x最新完整教程通俗易懂

一、ElasticSearch概述

Elaticsearch ,简称为es,es是一个开源的高扩展的分布式全文检索引擎,它可以近乎实时的存储、检索数据,本身扩展性很好可以扩展到上百台服务器,处理PB级别( 大数据时代 )的数据。es也使用ava开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。
据国际权威的数据库产品评测机构DB Engines的统计,在2016年1月,ElasticSearch已超过Sor等,成为排名第一的搜索引擎类应用。

历史:
多年前,一个叫做Shay Banon的刚结婚不久的=-失业开发者,由于妻子要去伦敦学习厨师,他便跟着也去了。在他找工作的过程中,为了给妻子构建一个食谱的搜索引擎,他开始构建一个早期版本的Lucene。
直接基于Lucene工作会比较困难,所以shay开始抽象Lucene代码以便/ava程序员可以在应用中添加搜索功能。他发布了他的第-个开源项目,叫做“Compass”。
后来Shav找到一份工作,这份工作处在高性能和内存数据网格的分布式环境中,因此高性能的、实时的、分布式的搜索引整也是理所当然需要的。然后他决定重写Compass库使其成为一个独立的服务叫做Elasticsearch
第一个公开版本出现在2010年2月,在那之后Elasticsearch已经成为Github上最受欢迎的项目之一,代码贡献者超过300人。一5主营Elasticsearch的公司就此成立,他们一边提供商业支持一边开发新功能,不过Elastisearch将永远开源对所有人可用Shay的妻子依旧等待着她的食谱搜索…

谁在使用:
1、维基百科,类似百度百科,全文检索,高亮,搜索推荐/2 ( 权重,百度!)
2、The Guardian(国外新闻网站),类似搜狐新闻,用户行为日志(点击,浏览,收藏,评论)+社交网络数据( 对某某新闻的相关看法 ),数据分析,给到每篇新闻文章的作者,让他知道他的文章的公众反馈(好,坏,热门,垃圾,鄙视,崇拜)
3、Stack Overflow(国外的程序异常讨论论坛),T问题,程序的报错,提交上去,有人会跟你讨论和回答,全文检索,搜索相关问题和答案,程序报错了,就会将报错信息粘贴到里面去,搜索有没有对应的答案
4、GitHub(开源代码管理),搜索上千亿行代码
5、电商网站,检索商品
6、日志数据分析,logstash采集日志,ES进行复杂的数据分析,ELK技术,elasticsearch+logstash+kibana
7、商品价格监控网站,用户设定某商品的价格闽值,当低于该 值的时候,发送通知消息给用户,比如说订阅牙膏的监控,如果高露洁牙膏的家庭套装低于50块钱,就通知我,我就去买
8,BI系统,商业智能,Business lnteligene。比如说有个大型商场集团,BL,分析一下某某区过最近3年的用户消费金额的趋势以及用户群体的组成构成,产出相关的数张报表,**区,最近3年,每年消费金额呈现100%的增长,而且用户群体85%是高级白领,开一个新商场。ES执行数据分析和挖掘,Kibana进行数据可视化
9、国内:站内搜索(电商,招聘,门户,等等),IT系统搜索(OA,CRM,ERP,等等),数据分析(ES热门的一个使用场景)

二、安装elasticsearch-7.6.1,基于windows 10

安装包狂神说公众号里面回复elasticsearch即可获取

1、解压安装包以及目录结构介绍

解压:elasticsearch-7.6.1-windows-x86_64.zip
1、目录介绍:
在这里插入图片描述
2、熟悉目录!

bin 启动文件
config 
	log4j2.properties :日志配置文件
	jvm.options:java虚拟机相关配置,资源占用配置
		以下两个参数,可以根据自己的硬件资源配置ES的资源占用率,默认是要求1核1G
		-Xms1g
		-Xmx1g
	elasticsearch.yml:elasticsearch的配置文件
		#http.port: 9200:默认9200端口
lib 相关jar包
modules:功能模块
plugins:插件! 如一会用的ik分词器
logs:日志保存	

3、启动
双击:conf/elasticsearch.bat启动即可
在这里插入图片描述
4、测试是否启动成功
http://127.0.0.1:9200/
在这里插入图片描述

2、安装可视化插件elasticsearch-head

1、解压:elasticsearch-head-master.zip
2、由于是前端vue项目,所以需要进入目录使用node.js安装依赖和启动

#进入cmd命令窗口
#用cnpm安装相关依赖
D:\Program Files\elasticsearch\elasticsearch-head-master>cnpm install
#启动elasticsearch-head
D:\Program Files\elasticsearch\elasticsearch-head-master>npm run start

在这里插入图片描述
3、测试
在这里插入图片描述

3、解决跨域问题

1、修改elasticsearch.yml配置文件
打开文件追加以下两行

#开启跨域
http.cors.enabled: true
#允许所有人访问
http.cors.allow-origin: "*"

保存重启elasticsearch

2、测试
在这里插入图片描述
elasticsearch-head连接elasticsearch成功

三、安装Kibana

Kibana是一个什对Elastisearch的开源分析及可视化平台,用来搜索、查看交与存储在Elasticsearch索引中的数据。使用Kibana可以通过各种图表进行高级数据分析及展示。Kbana让海量数据更容易理解。它操作简单,甚于浏览器的用户界面可以快速创建仪表板( dashboard)实时显示Elasticsearch查询动态。设置Kibana非常简单。无需编码或者额外的基础架构,几分钟内就可以完成Kibana安装并启动Elasticsearch索引临测。

1、解压kibana-7.6.1-windows-x86_64.zip
2、解压后的目录
在这里插入图片描述
3、启动
双击:kibana-7.6.1-windows-x86_64\bin\kibana.bat
在这里插入图片描述

4、访问测试:http://localhost:5601/
在这里插入图片描述
5、将kibana改为中文版的
打开:kibana-7.6.1-windows-x86_64\config\kibana.yml
在最后追加:i18n.locale: “zh-CN”
在这里插入图片描述
在这里插入图片描述

四、核心概念

概念
在前面的学习中,我们已经掌握了es是什么,同时也把es的服务已经安装启动,那么es是如何去存储数据,数据结构是什么,又是如何实现搜索的呢?我们先来聊聊ElasticSearch的相关概念吧!
集群,节点,索引,类型,文档,分片,映射是什么 ?

elasticsearch是面向文档,关系行数据库和 elasticsearch 客观的对比!一切都是]SON!

Relational DBElasticsearch
数据库(database)索引(indices)
表(tables)types
行(rows)documents
字段(columns)fields

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

物理设计 :
elasticsearch 在后台把每个索引划分成多个分片,每分分片可以在集群中的不同服务器间迁移

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

倒排索引

elasticsearch使用的是一种称为倒排索引的结构,采用Lucene倒排索作为底层。这种结均活用于快速的全立拽索,一个索引由文档中所有不重复的列表构成,对于每一个词,都有一个包含它的文档列表。例如,现在有两个文档,每个文档包含如下内容:
study every day, good good up to forever# 文档1包含的内容
To forever,study every day,good good up # 文档2包含的内容
为了创建倒排索引,我们首先要将每个文档拆分成独立的词(或称为词条或者tokens),然后创建一个包含所有不重 复的词条的排序列表,然后列出每个词条出现在哪个文档:
在这里插入图片描述
现在,我们试图搜索 to forever ,只需要查看包含每个词条的文档
在这里插入图片描述
在这里插入图片描述

五、IK分词器插件

1、什么是ik分词器

分词:即把一段中文或者别的划分成一个个的关键字,我们在搜索时候会把自己的信息进行分词,会把数据库中或者索引库中的数据进行分词,然后进行一个匹配操作,默认的中文分词是将每个字看成一个词,比如“我爱狂神”会被分为“我”,爱”““狂”,神”,这显然是不符合要求的,所以我们需要安装中文分词器ik来解决这个问题。
K提供了两个分词算法: iksmart和 ikmax_word,其中 iksmart 为最少切分,ikmax word为最细粒度划分!一会我们测试!

2、解压

elasticsearch-analysis-ik-7.6.1.zip
解压到:elasticsearch-7.6.1\plugins\ik下,ik目录自己创建
在这里插入图片描述
重启elasticsearch,kibana
特别提示:elasticsearch的ik路径不要有空格 不然kibana会报错

3、进入kibana测试

1、查看分词器

最少切分
在这里插入图片描述

最细拆分
在这里插入图片描述

默认的分词器有个小问题,就是无法识别自创的词汇,或者不常见的词汇,就会导致这些词汇被一个一个拆成单个词,此时就需要手动添加一些自己需要的词汇
在这里插入图片描述

4、自定义扩展词汇

1、查看默认词汇
进入ik\config
在这里插入图片描述
随便点开一个***.dic文件
在这里插入图片描述
因此我们也可以自己创建一个“*.dic”的文件来存放我们自己的词汇

2、创建自己的词汇字典文件“kuang.dic”
在这里插入图片描述
3、将自己的字典文件配置到ik中
打开IKAnalyzer.cfg.xml文件
在这里插入图片描述
保存,重启ES,回kibana测试
在这里插入图片描述

六、Rest风格说明

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

1、基本Rest命令说明:

methodurl地址描述
PUTlocalhost:9200/索引名称/类型名称/文档id创建文档(指定文档id)
POSTlocalhost:9200/索引名称/类型名称创建文档(指定文档id)
POSTlocalhost:9200/索引名称/类型名称/文档id/_update修改文档
DELETElocalhost:9200/索引名称/类型名称/文档id删除文档
GETlocalhost:9200/索引名称/类型名称/文档id查询文档通过文档id
POSTlocalhost:9200/索引名称/类型名称/_search查询所有数据

2、添加索引

DSL语句的使用

#添加文档数据
PUT user/userinfo/1
{
  "name":"lisi",
  "age":22,
  "city":"chengdu",
  "description":"welcome chengdu"
}

在这里插入图片描述
在这里插入图片描述

3、基本数据类型

上面直接添加的索引数据,会自动创建索引类型,但也可以自己指定数据类型
在这里插入图片描述

#添加索引库
PUT /user2
{
  "mappings":{
    "properties": {
      "name":{
        "type": "text",
        "analyzer": "ik_smart",
        "search_analyzer": "ik_smart",
        "store": false
      },
      "city":{
        "type": "text",
        "analyzer": "ik_smart",
        "search_analyzer": "ik_smart",
        "store": false
      },
      "age":{
        "type": "long",
        "store": false
      },
      "description":{
        "type": "text",
        "analyzer": "ik_smart",
        "search_analyzer": "ik_smart",
        "store": false
      }
    }
  }
}

4、其他命令

通过get _cat/ 可以获得es的当前很少信息,包括健康检查
在这里插入图片描述

5、修改索引

1、方法一 put
在这里插入图片描述
2、方法二post
在这里插入图片描述

6、查询

1、简单查询

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、复杂查询

1、条件查询

在这里插入图片描述

2、指定只显示的字段

指定要显示的字段: “_source”: [“name”,“age”]
在这里插入图片描述

3、排序分页查询

#搜索排序
GET /user/userinfo/_search
{
  "query":{
    "match": {
      "name":"李"
    }
  },
  "sort":[
    {
    "age":{
      "order":"desc"
    }
  }
],
}

#搜索查询并分页
get /user/userinfo/_search
{
  "query":{
    "match_all": {}
  },
  "sort":[
    {
    "age":{
      "order":"desc"
    }
  }
],
"from":0, #从第几个数据开始
"size":2 #单页显示的数据条数
}

在这里插入图片描述

4、must、must_not、should

#多条件查询
#must :多个查询条件完全匹配,相当于and
#must_not:多个查询条件的相反匹配,相当于Not
#should:至少一个查询条件匹配,相当于or
GET /user/userinfo/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "city": "成都"
          }
        },
        {
        "match":{
          "age":20
        }
        }
      ]
    }
  }
}

5、数据过滤

  • gt 大于
  • gte 大于等于
  • lt 小于
  • lte 小于等于
GET /user/userinfo/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "李"
          }
        }
      ],
      "filter": {
        "range": {
          "age": {
            "gte": 20,
            "lte": 30
          }
        }
      }
    }
  }
}

在这里插入图片描述

6、匹配多个条件

单个词包含匹配
在这里插入图片描述

多个词包含匹配
在这里插入图片描述

#多个域匹配
#搜索description,city两个域中都包含“changdu”的数据
GET user/userinfo/_search
{
  "query": {
    "multi_match": {
      "query": "成",
      "fields": [
        "city",
        "description"
        ]
    }
  }
}

7、精确查询

term查询时直接通过倒排索引指定的词条进程精确查找的!
关于分词:

  • term,直接查询精确的
  • match 会使用分词器解析(先分析文档,然后在通过分析的文档进行查询!)

两个类型 text keyword

  • text类型的索引,查询时能被分词模糊查询
  • keyword类型的索引,只能使用倒排索引进行精确查询

8、高亮查询

GET /user/userinfo/_search
{
  "query": {
    "match": {
      "name": "李"
    }
  },
  "highlight": {
    "fields": {
      "name":{} #要高亮的字段
    }
  }
}

在这里插入图片描述

自定义高亮标签
如果不想用< em >标签,也可以自定义标签

GET /user/userinfo/_search
{
  "query": {
    "match": {
      "name": "李"
    }
  },
  "highlight": {
    "pre_tags":"<p class='key' 'style'='color:red'>", #前缀
    "post_tags": "</p>",  #后缀
    "fields": {
      "name":{}
    }
  }
}

在这里插入图片描述

七、集成spring boot

1、创建springboot项目

在这里插入图片描述
在这里插入图片描述
由于是springboot默认生成的elasticsearch client版本与我们使用的elasticsearch版本不一致,所以需要自定义elasticsearch的maven版本
在这里插入图片描述

2、创建elasticsearch客户端构造器

官方文档
在这里插入图片描述
创建ElasticSearchClientConfig类,调用RestHighLevelClient方法,创建构造器并注入到springboot中
在这里插入图片描述

package com.jjl.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 ElasticSearchClientConfig {
    @Bean
    public RestHighLevelClient restHighLevelClient(){
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost("127.0.0.1", 9200, "http")));
        return client;
    }
}

3、测试索引库的API操作

1、测试创建索引库

进入springboot的测试类

package com.jjl;

import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.IOException;

/*
* es7.6.1 高级客户端测试*/
@SpringBootTest
class KuangshenEsApiApplicationTests {
    @Autowired
    //默认只用使用”restHighLevelClient“这个名字,但是如果觉得不想用这个名字,
    // 则可以使用@Qualifier绑定,绑定之后就可以随意定义名字了
    @Qualifier("restHighLevelClient")
    private RestHighLevelClient client;

    //测试索引创建  request
    @Test
    void testCreateIndex() throws IOException {
        //1.创建索引请求
        CreateIndexRequest request = new CreateIndexRequest("kuang_index");
        //2.执行创建请求,类型使用Java执行刚才在kibana里面执行的请求
        //CreateIndexResponse 请求后获得响应
        CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);
        System.out.println(createIndexResponse);
    }
}

允许查看输出
在这里插入图片描述
进入elasticsearch-head检查是否创建成功
在这里插入图片描述

2、测试判断索引库是否存在

    //测试获取索引
    @Test
    void testExistIndex() throws IOException {
        //获取"kuang_index"索引库的请求
        GetIndexRequest request = new GetIndexRequest("kuang_index");
        //判断索引库是否存在
        boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
        System.out.println(exists);
    }

在这里插入图片描述

3、测试删除索引库

    //删除索取库请求
    @Test
    void testDeleteIndex() throws IOException {
        //获取"kuang_index"索引库的请求
        DeleteIndexRequest request = new DeleteIndexRequest("kuang_index");
        //获取删除之返回的结果
        AcknowledgedResponse delete = client.indices().delete(request, RequestOptions.DEFAULT);
        //isAcknowledged()如果删除成功则会返回true,否则false
        System.out.println(delete.isAcknowledged());
    }

在这里插入图片描述

4、测试文档API的操作

导入阿里的fastjson依赖

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>2.0.20</version>
        </dependency>

1、添加文档

    //测试添加文档
    @Test
    void testAddDocument() throws IOException {
        //创建对象
        User user = new User("狂神说", 3);
        //创建请求
        IndexRequest request = new IndexRequest("kuang_index");
        //规则
        request.id("1");
        //过期时间,1秒
        request.timeout(TimeValue.timeValueSeconds(1));
        //将数据放入请求
        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 testIsExists() throws IOException {
        GetRequest getRequest = new GetRequest("kuang_index", "1");
        // 不获取返回的上下文
        getRequest.fetchSourceContext(new FetchSourceContext(false));
        getRequest.storedFields("_none");
        boolean exists = client.exists(getRequest, RequestOptions.DEFAULT);
        System.out.println(exists);//返回true或者false
    }

    //获取文档信息
    @Test
    void testGetDocument() throws IOException {
        GetRequest getRequest = new GetRequest("kuang_index", "1");
        GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT);
        //打印文档内容
        System.out.println(getResponse.getSourceAsString());
        System.out.println(getResponse);//返回全部内容,和命令是一样的
    }

在这里插入图片描述

3、更新文档数据

    @Test
    void testUpdateDocument() throws IOException {
        UpdateRequest updateRequest = new UpdateRequest("kuang_index", "1");
        updateRequest.timeout("1s");
        User user = new User("狂神说Java", 25);
        //JSON.toJSONString(user):调用阿里的JSON将user转换为json,
        //XContentType.JSON:指定传输类型为json
        updateRequest.doc(JSON.toJSONString(user), XContentType.JSON);
        UpdateResponse update = client.update(updateRequest, RequestOptions.DEFAULT);
        System.out.println(update.status());//返回OK
    }

4、删除文档数据

    //删除文档信息
    @Test
    void testDeleteDocument() throws IOException {
        DeleteRequest request = new DeleteRequest("kuang_index", "25");
        //超时时间,超时1秒就不执行了
        request.timeout("1s");
        DeleteResponse deleteResponse = client.delete(request, RequestOptions.DEFAULT);
        System.out.println(deleteResponse.status());
    }

5、批量导入数据

 @Test
    //批量导入数据
    void testBulkRequest() throws IOException{
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout("10s");
        ArrayList<Object> userList = new ArrayList<>();
        userList.add(new User("jjl",5));
        userList.add(new User("jjl1",25));
        userList.add(new User("jjl2",15));
        userList.add(new User("jjl3",35));
        userList.add(new User("jfan1",12));
        userList.add(new User("jfan3",10));
        userList.add(new User("jfan5",11));
        for (int i = 0; i < userList.size(); i++) {
            //批量删除或者批量更新,就在这里调用相应方法即可
            bulkRequest.add(
                    new IndexRequest("kuang_index")
                            .id(""+(i+1))//这里如果不指定生成id,则会默认生成无序不重复的id
                            .source(JSON.toJSONString(userList.get(i)),XContentType.JSON));
        }
        BulkResponse response = client.bulk(bulkRequest, RequestOptions.DEFAULT);
        //.hasFailures()是否失败,返回”false“表示没有失败,则是成功
        System.out.println(response.hasFailures());

    }

6、批量查询

 @Test
    //批量查询
    void testSearch() throws IOException {
        SearchRequest searchRequest = new SearchRequest("kuang_index");
        //构建条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //查询条件,我们可以使用QueryBuilders工具来实现
        //termQuery精确匹配查询条件
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", "jjl");
        //matchAllQuery:查询所有数据
//        MatchAllQueryBuilder allQuery = QueryBuilders.matchAllQuery();

        sourceBuilder.query(termQueryBuilder);
        //设置超时时间
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        //分页
/*        sourceBuilder.from();//从哪里开始分页
        sourceBuilder.size();//单页显示条数*/

        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        System.out.println(JSON.toJSONString(searchResponse.getHits()));
        //遍历输出
        for (SearchHit documentFields : searchResponse.getHits().getHits()) {
            System.out.println(documentFields.getSourceAsMap());
        }


    }
}

八、模拟京东商品搜索

1、新建springboot项目,导入静态资源

在这里插入图片描述
修改端口、关闭thymeleaf缓存
在这里插入图片描述
导入静态资源
解压:搜索页面.rar
在这里插入图片描述
创建controller类测试
在这里插入图片描述
启动测试
在这里插入图片描述

2、获取京东网页上的数据

获取京东网页上的数据(获取请求返回的页面信息,筛选出我们想要的数据就是可以)
jsoup包
1、导入依赖

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

2、编写测试类
先查看要获取的商品信息,可以看出商品信息都在 id为“J_goodsList”所属的div里面
在这里插入图片描述

package com.jjl.util;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import java.net.URL;
import java.io.IOException;
public class HtmlParseUtil {
    public static void main(String[] args) throws IOException {
        //获取请求
        // 前提,
        String url = "https://search.jd.com/Search?keyword=java";
        //解析网页 (Jsoup返回Document就是浏览器Document
        Document document = Jsoup.parse(new URL(url), 30000);
        // 所有js中可以用的方法,这里都可以用
        // 获取J_goodsList下的数据
        Element jGoodsList = document.getElementById("J_goodsList");
        System.out.println(jGoodsList.html());
    }
}

在这里插入图片描述
进一步筛选出商品的图片url、商品title、商品的价格

package com.jjl.util;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.net.URL;
import java.io.IOException;
import java.util.List;

public class HtmlParseUtil {
    public static void main(String[] args) throws IOException {
        //获取请求
        // 前提
        String url = "https://search.jd.com/Search?keyword=java";
        //解析网页 (Jsoup返回Document就是浏览器Document
        Document document = Jsoup.parse(new URL(url), 30000);
        // 所有js中可以用的方法,这里都可以用
        Element jGoodsList = document.getElementById("J_goodsList");
        // 获取所有的li元素
        Elements elements = jGoodsList.getElementsByTag("li");
        // 获取元素中的内容,这里el 就是每一li标签
        for (Element element : elements) {

            String img = element.getElementsByTag("img").eq(0).attr("data-lazy-img");
            String price = element.getElementsByClass("p-price").eq(0).text();
            String title = element.getElementsByClass("p-name").eq(0).text();
            System.out.println("===================");
            System.out.println(img);
            System.out.println(price);
            System.out.println(title);
        }
    }

在这里插入图片描述
3、封装成工具类
先创建一个商品的pojo

package com.jjl.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(indexName = "skuinfo",indexStoreType = "docs")
public class Content {
    @Field(type = FieldType.Text, analyzer = "ik_max_word",searchAnalyzer = "ik_max_word")
    private String title;
    private String img;
    private String price;
}

提取工具类

@Component
public class HtmlParseUtil {
//提取为方法
//String keywords:要搜索的关键字, int age:要搜索的页数
    public List<Content> parseJD(String keywords, int age) throws IOException {
        age =age+2;
        ArrayList<Content> goodsList = new ArrayList<>();
        for (int i = 2; i <age ; i++) {
            //获取请求
            // 前提
            String url = "https://search.jd.com/Search?keyword=" + keywords + "&page=" + i;
            //解析网页 (Jsoup返回Document就是浏览器Document
            Document document = Jsoup.parse(new URL(url), 30000);
            // 所有js中可以用的方法,这里都可以用
            Element jGoodsList = document.getElementById("J_goodsList");
            // 获取所有的li元素
            Elements elements = jGoodsList.getElementsByTag("li");
            // 获取元素中的内容,这里el 就是每一li标签
            for (Element element : elements) {
                String img = element.getElementsByTag("img").eq(0).attr("data-lazy-img");
                String price = element.getElementsByClass("p-price").eq(0).text();
                String title = element.getElementsByClass("p-name").eq(0).text();
                Content content = new Content();
                content.setTitle(title);
                content.setPrice(price);
                content.setImg(img);
                goodsList.add(content);
            }
        }
        return goodsList;
    }
}

测试工具类
在这里插入图片描述

3、将数据写入elasticSearch中

1、导入阿里的fastjson依赖
2、新建config文件夹创建elasticsearch配置类
在这里插入图片描述
3、编写service层

package com.jjl.service;

import com.alibaba.fastjson2.JSON;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.client.indices.CreateIndexResponse;
import com.jjl.pojo.Content;
import com.jjl.util.HtmlParseUtil;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
//业务编写
public class ContentService {
    @Autowired
    private RestHighLevelClient restHighLevelClient;
    @Autowired
    private HtmlParseUtil htmlParseUtil;

    //1.解析数据放入 es 索引中
    public Boolean parseContent(String index,String keywords,int page)throws Exception{
        CreateIndexRequest jdGoods = new CreateIndexRequest(index);
        CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(jdGoods, RequestOptions.DEFAULT);
        if (createIndexResponse.isAcknowledged()) {
            List<Content> contents = htmlParseUtil.parseJD(keywords, page);
            BulkRequest bulkRequest = new BulkRequest();
            bulkRequest.timeout("2m");
            for (int i = 0; i < contents.size(); i++) {
                bulkRequest.add(new IndexRequest(index)
                        .source(JSON.toJSONString(contents.get(i)), XContentType.JSON)
                );
            }
            BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
            return !bulk.hasFailures();
        }else {
            System.out.println("索引库"+index+"创建失败");
            return true;
        }
    }
}

4、编写controller层

package com.jjl.controller;

import com.jjl.service.ContentService;
import org.elasticsearch.common.recycler.Recycler;
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;

//前端的请求编写
@RestController
public class ContentController {
    @Autowired
    private ContentService contentService;
    @GetMapping("/parse/{index}/{keywords}/{page}")
    public Boolean parse(@PathVariable("index") String index,
                         @PathVariable("keywords") String keywords,
                         @PathVariable("page") int page) throws Exception {
        return contentService.parseContent(index,keywords,page);
    }
}

5、启动springboot,测试
测试:创建jd_good索引库,搜到关键字java的商品信息,搜索10页的数据
在这里插入图片描述
6、查看elasticsearch-head是否成功执行并获取数据
在这里插入图片描述

4、精准匹配查询es的数据,并分页显示

1、编写service层

    // 2、获取这些数据实现搜索功能
    public List<Map<String,Object>> searchPage(String keyword,int pageNo,int pageSize) throws IOException {
        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);
        sourceBuilder.query(termQueryBuilder);
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));

        //执行搜索
        searchRequest.source(sourceBuilder);
        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        ArrayList<Map<String,Object>> list = new ArrayList<>();
        for (SearchHit documentFields : search.getHits().getHits()) {
            list.add(documentFields.getSourceAsMap());
        }
        return list;
    }

2、controller层调用

    @GetMapping("/search/{keyword}/{pageNo}/{pageSize}")
    public List<Map<String,Object>> search(@PathVariable("keyword") String keyword,
                                           @PathVariable("pageNo") int pageNo,
                                           @PathVariable("pageSize") int pageSize) throws IOException {
        if (pageNo==0){
            pageNo=1;
        }
        return contentService.searchPage(keyword, pageNo, pageSize);
    }

3、重启测试
在这里插入图片描述

5、修改前端,使用vue、axios

1、下载vue和axios的package包
建议下载vue2版本的

3、将vue.min.js和axios.min.js文件复制到static/js/下

vue.min.js路径:node_modules\vue\dist
axios.min.js路径:node_modules\axios\dist\

复制到static/js/下
在这里插入图片描述
4、修改index.html页面

  • 注释jquery
    在这里插入图片描述

  • 引入vue和axios
    在这里插入图片描述

  • 绑定标签,创建keyword和results存放数据
    在这里插入图片描述
    在这里插入图片描述

  • 双向绑定获取keyword的文本框
    在这里插入图片描述

  • 绑定搜索时的鼠标单击事件
    在这里插入图片描述
    在这里插入图片描述

  • 测试当单击搜索时,控制台能否获取到输入的keyword
    在这里插入图片描述

6、对接后端的接口

1、测试使用axios向后端发起,将结果输出到控制台
在这里插入图片描述
在这里插入图片描述
2、将数据展示到页面上
在这里插入图片描述
在这里插入图片描述
3、展示
在这里插入图片描述

7、高亮显示

1、修改八、4精准匹配查询的类

// 2、获取这些数据实现搜索功能
    public List<Map<String,Object>> searchPage(String keyword,int pageNo,int pageSize) throws IOException {
        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);
        sourceBuilder.query(termQueryBuilder);
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));

        //高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("title");
        //是否显示多个高亮,列如(同一个title中包含了多个要搜索的词),关闭之后值显示第一个
        highlightBuilder.requireFieldMatch(false);
        highlightBuilder.preTags("<span style='color:red'>");
        highlightBuilder.postTags("</span>");
        sourceBuilder.highlighter(highlightBuilder);

        //执行搜索
        searchRequest.source(sourceBuilder);
        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        ArrayList<Map<String,Object>> list = new ArrayList<>();
        for (SearchHit documentFields : search.getHits().getHits()) {
            Map<String, HighlightField> highlightFields = documentFields.getHighlightFields();
            //指定要高亮的字段
            HighlightField title = highlightFields.get("title");
            //原本的结果
            Map<String, Object> sourceAsMap = documentFields.getSourceAsMap();
            //解析高亮的字段
            if (title!=null){
                //如果title这个高亮的字段存在,这就赋给fragments
                Text[] fragments = title.fragments();
                String n_title= "";
                //已经被处理过的高亮title遍历给n_title
                for (Text text:fragments){
                    n_title += text;
                }
                //将原来的title替换为n_title
                sourceAsMap.put("title",n_title);
            }
            list.add(sourceAsMap);
        }
        return list;
    }

2、修改index.html
使用vue解析后端传过来的高亮html标签
在这里插入图片描述
使用v-html解析
在这里插入图片描述
测试查看
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/133732.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

状态压缩DP——蒙德里安的梦想

状态压缩DP——蒙德里安的梦想一、题目描述二、思路分析1、状态表示——状态压缩2、状态转移3、循环4、初始化三、代码一、题目描述 二、思路分析 这道题中&#xff0c;其实刚一看是非常的抽象的&#xff0c;也是非常麻烦的。麻烦的点在于我们既需要考虑横着放的方块&#xff…

【Linux】shell命令以及运行原理和Linux权限的理解

&#x1f680; 作者简介&#xff1a;一名在后端领域学习&#xff0c;并渴望能够学有所成的追梦人。 &#x1f40c; 个人主页&#xff1a;蜗牛牛啊 &#x1f525; 系列专栏&#xff1a;&#x1f6b2;Linux &#x1f4d5; 学习格言&#xff1a;博观而约取&#xff0c;厚积而薄发 …

VBA之正则表达式(39)-- 提取规格数据(2/2)

实例需求&#xff1a;A列为某产品名称&#xff0c;现需要提取其中的规格数据&#xff0c;具体规则如下&#xff1a; 规格数据以如下关键字开头&#xff1a;RO、RE、SQ、SD、QD、OB、HX、ET、QR、D2规则数据可能有多段&#xff08;截图中红色部分&#xff09;提取规格数据之后&…

SpringBoot简单功能分析,静态资源访问和静态资源配置原理解析

目录 1、SpringMVC自动配置概览 2、简单功能分析 2.1、静态资源访问 1、静态资源目录 2、静态资源访问前缀 3、webjar 2.2、欢迎页支持 2.3、自定义 Favicon 2.4、静态资源配置原理 1、SpringMVC自动配置概览 官网Web (spring.io) Spring Boot provides auto-configur…

论文综述——UNIRE: A Unified Label Space for Entity Relation Extraction

UNIRE: A Unified Label Space for Entity Relation Extraction1 任务介绍2 UniRE模型3 实验4 总结1 任务介绍 过构建标签空间来对实体和关系进行联合抽取的方法。 实体关系抽取旨在提取文本中的实体并检测它们的实体类型&#xff0c;以及对每个实体对检测它们的关系。作者提…

MAX78000FTHR简单介绍与初次上手

特点 MAX78000FTHR是基于MAX78000的小型板微控制器单元&#xff08;MCU&#xff09;。 该 MCU 面向在边缘运行的人工智能 (AI) 应用程序。在这种情况下&#xff0c;“边缘”并不意味着技术的前沿&#xff08;尽管这就是芯片&#xff09;&#xff1b;这意味着靠近需要它的地方…

vector对于自定义类型的操作(memcpy浅拷贝问题)

目录 如果对于不涉及资源管理的自定义类型的操作&#xff08;Date&#xff09;&#xff1a; 对涉及资源管理类操作&#xff08;String&#xff09;&#xff1a; 一、插入四个元素&#xff08;代码正常编译没有任何资源泄露问题&#xff09; 二、当插入第五个元素时&#xf…

【C++进阶】Map 和 Set(详解)

&#x1f308;欢迎来到C专栏~~Map 和Set (꒪ꇴ꒪(꒪ꇴ꒪ )&#x1f423;,我是Scort目前状态&#xff1a;大三非科班啃C中&#x1f30d;博客主页&#xff1a;张小姐的猫~江湖背景快上车&#x1f698;&#xff0c;握好方向盘跟我有一起打天下嘞&#xff01;送给自己的一句鸡汤&am…

【JavaScript】DOM 的概念、获取DOM元素和操作元素属性

文章目录【JavaScript】DOM 的概念、获取DOM元素和操作元素属性一. 概念二. DOM 操作(1) 获取DOM元素的方式1. document 获取元素方法2. 通过 HTML5 新增的方法获取案例&#xff1a;登录界面密码显示与隐藏(2) 读写元素内部的结构内容1. 改变元素节点里的内容2. 改变元素节点的…

操作系统的基本概念、功能、目标

文章目录&#x1f380;前言&#xff1a;本篇博客知识总览&#x1fa82;操作系统所处位置&#x1f4d6;操作系统的概念&#x1f3af;操作系统的功能和目标&#x1fa85;1.操作系统作为系统资源的管理者&#x1fa85;2.操作系统作为用户与计算机硬件之间的接口&#x1fa85;3.操作…

连接数据库和简单操作数据库

连接数据库和简单操作数据库JDBC程序编写步骤创建一个演员表数据库表的连接前置工作五种连接方式方式五的配置文件配置文件里面的内容通过JDBC进行对actor表操作。ideal执行后的结果数据库actor表结果JDBC程序编写步骤 1.注册驱动-加载Driver类 2.获取连接-得到Connection 3.执…

【阶段一】Python快速入门04篇:运算符、循环语句、条件语句与函数

本篇的思维导图: 运算符 算术运算符 算术运算就是常规的加、减、乘、除类运算。下表为基本的算术运算符及其示例。 描述 代码

【C++常用容器】STL基础语法学习map容器

目录 ●map基本概念 ●map构造和赋值 ●map大小和交换 ●map插入和删除 ●map查找和统计 ●map排序&#xff08;map初始排序顺序为从小到大&#xff0c;用仿函数将其改为从大到小&#xff09; ●map基本概念 map中的所有元素都是pair&#xff0c;pair中第一个元素为key&a…

【WeThinkIn出品】2022年度总结

Rocky Ding公众号&#xff1a;WeThinkIn写在前面 【WeThinkIn出品】栏目专注于分享Rocky的最新思考与经验总结&#xff0c;包含但不限于技术领域。欢迎大家一起交流学习&#x1f4aa; 这篇文章发布的时候&#xff0c;应该已经是2023年了。在这里Rocky祝大家元旦快乐&#xff01…

前端最常用的几个线上设计网站

文章目录前言CoDesign 腾讯自研设计平台【墙裂推荐】蓝湖- 高效的产品设计协作平台【墙裂推荐】zeplin Deliver on the promise of design 【国外&#xff0c;不推荐】总结前言 随着IT技术的不断进步&#xff0c;很多团队都将很对线下工作转移到了线上&#xff0c;不仅便捷&a…

Ae 效果详解:毛边

Ae菜单&#xff1a;效果/风格化/毛边Effects/Stylize/Roughen Edges毛边 Roughen Edges效果可使得 Alpha 通道的边缘变粗糙&#xff0c;可以为图像添加各种边缘效果。通过分形影响改变边缘样式&#xff0c;并可增加颜色以模拟铁锈和其他类型的腐蚀。此效果可为文本或图形提供自…

算法之数组常见题目

数组是存储在连续内存空间上的相同类型数据的集合。在数组中可以方便地通过下标索引的方式获取对应的数据。 需要注意的是&#xff1a; 数组的下标都是从0开始的。数组在内存空间是连续的&#xff0c;所以删除或者增添元素时难免要移动其他元素的地址&#xff0c;只能覆盖。 …

【Kubernetes | Pod/容器】如何修改 Pod 中容器的守护进程

目录题1. 环境设定1.1 创建名为 vmware-nginx 的 Pod2. 查看容器默认守护进程2.1 查看容器所在节点2.2 查看容器ID2.3 查看容器中运行的进程信息3. 修改容器默认守护进程3.1 类比 Docker3.2 修改 YAML 文件改变默认守护进程参数说明4. 验证4.1 删除旧的 vmware-nginx.yaml 容器…

质性分析软件nvivo的学习(一)

1、软件安装&#xff1a; 科研也是需要投资的&#xff0c;建议淘宝购买软件,价格60米。 2、软件基础使用说明&#xff1a; 说明&#xff1a;以下笔记来源都是通过B站视频自学总结的&#xff0c;您可以选择通过下面的B站视频学习&#xff0c;也可以选择通过我总结的内容速学。…

(Week 9)图论(C++,Dijkstra,Floyd)

文章目录【深基18.例3】查找文献&#xff08;C&#xff0c;图的遍历&#xff09;题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1解题思路&#xff1a;【模板】floyd&#xff08;C&#xff09;题目背景题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1样例 #2样…