elasticSearch的基本使用加项目实战(Java爬取数据+elasticSearch)

一.es的安装

2.1、Es安装 为了避免出现不必要的一些问题,

我们这里选择 7.3.1版本

1. 安装es

下载 https://www.elastic.co/downloads/past-releases/elasticsearch-7-3-1 2. 安装 :安装很简单,只需要解压即可。解压后进入 bin 目录,运行里面的 elasticsearch.bat ,即 可运行 Es 3. 访问:启动 Es 服务后,访问 localhost:9200 即可看到如下界面:

2、安装head 可视化界面,他就是一个数据的展示

插件 head插件可以很方便的操作es,head插件与es的关系就像navicat与MySQL数据库的关系,不过head 插件的界面也是通过访问网址浏览的。

1. 下载:https://github.com/mobz/elasticsearch-head 该插件没有可执行文件,需要下载源码,通过 nodejs 的方式来进行启动,所以在运行前先确 保安装了node环境。

2. 安装grunt: 运行 head 需要借助于 grunt 命令,所以需要安装 。

打开 cmd 或 PowerShell 执行命 令 直接输入cmd命令

3. 安装所需要的依赖:进入插件所在目录,执行

npm install

4. Es 需要做相关的配置,主要是为了解决跨域的问题,在Es 的安装根目录的conf下有 elasticsearch.yml,在 此文件中添加如下内容:

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

5. 运行 head: 进入到 head 插件所在的目录,执行 npm run start , 启动成功如下图:

6. 访问 loclhost:9100 ,如下图:

在没有创建索引的时候会显示一个绿色的

我们添加索引之后就会显示黄色的标签

3.安装kibana 来实现存储数据

1.kibana是什么?

kilbana是针对Elasticsearch的一个可视化平台,可以实现搜索查看Elasticsearch索引中的数据,使用kibana通过各种图表来实现数据分析和展示

2.官网

Kibana:数据的探索、可视化和分析 | Elastic

在下载kibana的时候注意要和咱们的Elasticsearch的版本要一执

Kibana 7.3.1 | Elastic 下载地址

他的解压速度很慢

解压完成之后就显示这些文件夹

进入bin目录点击kibana的bat文件

3.访问测试

点击启动完成之后就会显示一下信息,他的默认的端口是5601端口

访问5601端口然后就会显示一下信息

4.开发工具可以使用(postmain,curl,谷歌浏览器)

5.汉化kibana,在我们的这个kibana的这个安装包当中有一个汉化包

找到我们的这个kibana的这个config的这个配置文件当中的这个kibana的yaml文件,把这个配置文件中的这个i18m的这个参数来进行更改

文件地方:

更改内容

然后重新启动kibana访问我们的默认端口5601,然后页面显示中文了

4.ES核心概念

1.Es和MySQL的对比

 

在es中每个索引可以是数据库当中的多个表组成,同时每个document对象都可以是多个数据库的行组成

物理设计

elasticSearch在后台把每个索引划分成多个分片,每片分片可以在集群中的不同的服务器之间迁移

在安装kibana了之后他会自动的默认添加kibana的两个集群

 

elasticsearch他的底层的索引主要是使用的我们的一个倒排索引,通过倒排索引来进行分片机制

倒排索引的分析网址:

倒排索引 | Elasticsearch: 权威指南 | Elastic

easticsserch的Ik分词器

如果要使用中文分词器就建议使用我们的这个IK分词器,他可以把一个词语分为多个字来进行检索操作,注意Ik分词器要和我的这个es的版本要一致

IK分词器下载地址:https://github.com/medcl/elasticsearch-analysis-ik/releases?page=6 

然后进行解压到我的这个elasticesserch文件夹中的这个plugin的文件夹下面,

 重启es

然后发现Ik分词器已经被启动了

同时也可以去我的这个es目录下的bin目录下面运行cmd执行 这条命令,然后可以查看所有的elasticerch所有的插件

elasticsearch-plugin  list  

 

分词器的分类

分词器主要是分为两种类型:ik_smart类型的和ik_max_word

ik_smart最少切分,只会切出一个分词

 

ik_max_word:最细粒度划分,可以吧当前的这个词语都进行分开

但是在使用分词器的时候如果说要去拆分一个名字的话那就会显示三个不同的字,那么这样是不可以的,所以我们需要在ik分词器当中进行设置

设置我们的这个分词器的词典的文件在es中的plugin中找到ik下面的config文件夹,同时我们需要去自定义dic文件,在最后去更改下面的这个xml文件,去把我们的这个dic文化注入到我们的这个xml文件当中

这个文件的默认内容如下

注入步骤如下:

1.创建我的一个dic文件,然后在文件里面添加自定义的词语

2.在这个dic文件中添加信的词汇

3.然后把这个dic文件注入到我们的这个IKAnalyzer.cfg.xml文件就可以了

重启es

在启动的时候我们发现es启动了gong.dic

然后我们使用kibana来测试,此时我们发现龚俊豪变成了一个完整的词

5.使用restful风格来创建es的索引

restFull风格主要是用于客户端和服务端进行相互之间进行交互,基于这种风格软件可以设计更简洁更有层次的机制

基本的restful风格

1.创建索引(创建索引的语法组成)

PUT/索引名称/类型名/文档id

{

字段信息

}

然后查看es发现我们的这个test的索引创建成功

数据刚好是我们在kibana里面创建的数据

2.es中字段的类型

字符串类型

text、keyword

text:支持分词,全文检索,支持模糊、精确查询,不支持聚合,排序操作;text类型的最大支持的字符长度无限制,适合大字段存储;

keyword:不进行分词,直接索引、支持模糊、支持精确匹配,支持聚合、排序操作。keyword类型的最大支持的长度为——32766个UTF-8类型的字符,可以通过设置ignore_above指定自持字符长度,超过给定长度后的数据将不被索引,无法通过term精确匹配检索返回结果。

数值型

long、Integer、short、byte、double、float、half float、scaled float

日期类型

date

te布尔类型

boolean

二进制类型

binary

等等…

6. Put命令

使用put操作来添加字段的类型,来把数据存入到es当中

1>创建规则类型

7.get命令

使用get命令查询非常的简单,只需要提供的的es中的索引名称即可

语法:get 索引名称

 

8.查看数据的类型 

如果说我们在添加数据的时候没有指定我们相对应的数据类型那么我们的es就会自动默认生成数据类型

扩展:我们通过elasticsearch可以查看到很多索引的很多详细信息

比如说使用

GET _cat/health可以查看这个es索引的一个健康状态

GET _cat/indices可以查看我的这个所有索引的一个状态

9.修改索引

1>使用put操作添加原来的值,来直接进行替换,他的这个put后面添加的斜杆的参数意思如下:

第一个参数索引名称,第二个参数索引类型,第三个参数索引id,我们可以去在同一个索引类型下面有多个索引Id来进行操作,但是在同一个索引中只能有一个索引类型

但是如果说使用put操作的话如果少填写了一个字段的话那么久会彻底无法恢复到之前的数据了

那么我们可以使用post方式来进行修改

我们去查看一下elasticsearch的这个可视化界面发现我们的值已经被更改成功了

10删除索引

删除索引我们可以直接使用delete的这个命令来实现

然后去执行删除命令

最后去刷新elasticsearch的可视化界面进行查询这个test1的索引是否还存在

同时也可以根据这个索引的下标去进行删除

DELETE 索引名称/索引类型Type/下标

 

此时我们的这个test1索引不存在了,同时也可以删除这个索引下面的这个id或者是索引类型来进行删除

11elasticsearch的基本操作

基本操作

1.使用kibana来创建数据

 

2.保证我们的这个elasticsearch中的数据存储在elasticsearch当中

3.我们可以通过get命令找到每个索引下面的对应的类型下面的对应的id

4.在我们使用put在更新我们的这个elasticsearch中的数据的时候我们会发现我们的这个数据的版本也会随着进行改变

5.建议使用post来进行更改我们的这个elasticsearch中的这个数据中的信息,一定要去在我们的这个下标进行修改,但是在修改的时候可能会出现一下图片的这种情况

那么我们可以在后面添加一个下标后面添加 /_update来实现进行修改

操作如下:

6.通过get来实现数据的分词查找

语法如下:

Get 索引名称/索引类型./search?q=字段名 : "检索内容"

12.复杂搜索

1.在查询elasticsearch的时候我可以在get的后面凭借我的这个类型和我的这个id,然后我还可以在最后面去拼接我的这个_serach这个关键字来实现进行检索操作

2.使用get来控制我们的这个记过数量

我们可以通过"_source":["字段名称1",“字段名称2”]

3.进行降序排序

他的语法是

GET /gjh/user/_search  指定索引所在位置
{
  
  "query":{  实现查找的固定语法
    "match": {
      "name": "小" 
    }
  },
  "sort":[  实现排序的关键字
    {
      "age":{  指定根据什么字段来进行排序
        "order":"asc"   指定我的这个排序的顺讯,asc是正序,desc是到序的意思
      }
    }
    ]
}

 

4.实现分页操作

使用分页查询主要是要通过两个参数来进行查询,第一个参数就是使用from他就是控制我们这个每页查询的数量,size就是我的这个每页线束的数量,然后我们通过设置这两个参数的值以后我们就来实现进行查询操作那么,他的数据就渲染出来了,其实他和我们Mysql当中的这个limit的关键字来进行查询的效果是一样的

5.使用boolean值来进行查询

使用must(相当于Mysql数据库当中的and)值来进行查询的语法:

GET /索引名称/类型/_search
{
  "query":{
    "bool": {
      "must": [
        {
          "match": {
            "字段名":"检索值" 
          }
        },
        {
          "match":{
             "字段名":integer类型的值
           }   
        }
      ]
    }
  }
}

 

使用should(相当于Mysql中的or)来实现检索

使用must_not(相当于Mysql中的not in )不包含这个数据的关键字

使用过滤器来实现数据的过滤实现我们先更改一下查询的条件,然后我们可以通过filter过滤器来设置允许那个范围的值可以被查询到

在这个过滤器当中涉及到两个关键字

gte:我们可以拆分来看,gt是大于的意思,e是代表eq的意思,他就是等于

lte:同样我们也可以进行拆分来看 lt是小于的意思,同时e是代表eq的意思,他就是等于

匹配多个条件检索,通过使用match来指定列明,然后可以使用空格隔开,实现多个条件进行拼接

精确查询

精确查询主要是通过使用我们的这个倒排索引来指定的词条来进行查找

term:直接查询精确的

match:会使用分词器解析(把相同的数据分析成文档,然后通过分析文档来进行查询)

两个text和password类型

text不会被分词器解析

password是会被我的这个分词器进行解析的

1.创建规则

PUT testdb
{
  "mappings": {
    "properties":{
      "name":{  //在这个name值是字段名,type对应的值是我的这个数据的类型
        "type": "text"
      },
      "desc":{
        "type":"keyword"
      }
    }
  }
}

 2.添加数据

PUT testdb/_doc/1
{
  "name":"龚俊豪",
  "desc":"他是一个大傻逼"
}

3.按照精准度查询(keywork),精准排序他是不会进行分词的,没有被分析,就是把这个值看成一个整体

4.标准分词器(standard),可以被进行拆分

5.使用term来进行精准查询,把我需要查询出来只要包含这个字的数据都会被查询出来

 6.使用keyword的话来查询的时查询的条件的数据一定要和我的这个下面的数据要一模一样,否则查询不出来,因为keyword他是不具备分词功能的

 

7. 使shouid来实现精确查询多个字段的值,注意每个shouid的下面都要有多个term,我的这个字段和值才能在term里面进行多个条件的查询

8.实现elasticsearch的高亮查询主要是通过highlight这个来包裹我的这个数据的字段,实现我的这个字段来进行高亮查找,他主要是在json中的这个关键字加了一个em标签

 自定义elasticsearch的高亮标签,主要是通过pre_tags来设置高亮页面的前缀,通过post_tags来设置高亮的后缀

 

二.Springboot整合elasticSearch 

 1.找官网

Welcome to Elastic Docs | Elastic

 

elasticsearch的官方文档

Java REST Client [7.17] | Elastic

同时也可以在这个官网上面查看到我们的 这个maven依赖

我们的这个maven依赖,注意这个依赖的版本要和我的这个本地的elasticSearch一致

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.17.3</version>
</dependency>

 2.找对象

 3.分析类中的方法即可

配置项目

在使用Springboot项的时候需要注意我的这个elasticsearch的版本要改成我本地的elasticsearch的版本要一致,如果说我们在创建springboot项目的时候在nosql模块中选中了elasticsearch的话我们就直接在这个更改他的这个版本

<elasticsearch.version>7.3.1</elasticsearch.version>

 2.elasticsearch底层的自动配置类

在elasticsearch当中他一共有三个回调对象,在这几个回调对象当中分别回调了三个方法

1.RestClientBuilderConfigguration(获取我当前的这个链接对象)

2.RestHigLevelClientConfiguration(获取我的这个高级的链接对象)

3.RestClientFallbackConfiguration(获取我的这个回调链接对象)

他的底层实现方法

/*
 * Copyright 2012-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.boot.autoconfigure.elasticsearch.rest;

import java.time.Duration;

import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Elasticsearch rest client infrastructure configurations.
 *
 * @author Brian Clozel
 * @author Stephane Nicoll
 */
class RestClientConfigurations {

   @Configuration(proxyBeanMethods = false)
   static class RestClientBuilderConfiguration {
    //读取配置信息
      @Bean
      @ConditionalOnMissingBean
      RestClientBuilder elasticsearchRestClientBuilder(RestClientProperties properties,
            ObjectProvider<RestClientBuilderCustomizer> builderCustomizers) {
         HttpHost[] hosts = properties.getUris().stream().map(HttpHost::create).toArray(HttpHost[]::new);
         RestClientBuilder builder = RestClient.builder(hosts);
         PropertyMapper map = PropertyMapper.get();
         map.from(properties::getUsername).whenHasText().to((username) -> {
            CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
            Credentials credentials = new UsernamePasswordCredentials(properties.getUsername(),
                  properties.getPassword());
            credentialsProvider.setCredentials(AuthScope.ANY, credentials);
            builder.setHttpClientConfigCallback(
                  (httpClientBuilder) -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider));
         });
         builder.setRequestConfigCallback((requestConfigBuilder) -> {
            map.from(properties::getConnectionTimeout).whenNonNull().asInt(Duration::toMillis)
                  .to(requestConfigBuilder::setConnectTimeout);
            map.from(properties::getReadTimeout).whenNonNull().asInt(Duration::toMillis)
                  .to(requestConfigBuilder::setSocketTimeout);
            return requestConfigBuilder;
         });
         builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
         return builder;
      }

   }

   @Configuration(proxyBeanMethods = false)
   @ConditionalOnClass(RestHighLevelClient.class)
   static class RestHighLevelClientConfiguration {
    //高级客户端
      @Bean
      @ConditionalOnMissingBean
      RestHighLevelClient elasticsearchRestHighLevelClient(RestClientBuilder restClientBuilder) {
         return new RestHighLevelClient(restClientBuilder);
      }
    //普通的客户端
      @Bean
      @ConditionalOnMissingBean
      RestClient elasticsearchRestClient(RestClientBuilder builder,
            ObjectProvider<RestHighLevelClient> restHighLevelClient) {
         RestHighLevelClient client = restHighLevelClient.getIfUnique();
         if (client != null) {
            return client.getLowLevelClient();
         }
         return builder.build();
      }

   }
    //回调客户端
   @Configuration(proxyBeanMethods = false)
   static class RestClientFallbackConfiguration {

      @Bean
      @ConditionalOnMissingBean
      RestClient elasticsearchRestClient(RestClientBuilder builder) {
         return builder.build();
      }

   }

}

 3.实现API测试

自定义高级客户端配置类如下:

package com.gjh.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; 
/**
 * 添加elasticsearch的配置
 */
@Configuration
public class ElasticSearchClientConfig{
    /**
     * 添加我的这个elasticsearch的这个配置类,用来构建我们的这个elasticsearch的工具
     * @return 返回client对象
     */
    @Bean
    public RestHighLevelClient restHighLevelClient(){
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost("localhost", 9200, "http")));
        return client;
    }

}

注意再使用的时候我们需要把我们刚刚注入进来的那个restHighLevelClient引入到我们的这个操作elasticsearch的类当中,我们可以使用Spring自带的注解@Autowrite的这个注解,,只要是关于索引的信息都是按照这样的逻辑来进行操作

1>创建elasticsearch的这个索引

@Test
void createIndex() throws IOException {
    CreateIndexRequest request = new CreateIndexRequest("gong_indexs");//创建我的这个索引的请求
    //客户端执行请求,他需要的一个参数就是我的这个索引和我的这个,第二个参数就是说设置我的这个请求参数,一般是使用默认的
    CreateIndexResponse response =//通过使用create来得到我的这个创建索引的对象,然后参数给出默认的参数即可
            restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);//得到请求后的响应
    System.err.println("response所响应出来的数据有"+response);
}

2>测试获取索引是否存在

/**
 * 测试获取索引,判断我的这个索引是否存在
 */
@Test
void testExists() throws IOException {
    //得到我的这个索引,获取这个elasticsearch的这个索引信息
    GetIndexRequest request = new GetIndexRequest("gong_indexs");
    //判断我的这个请求是否存在
    System.out.println(restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT));
}

3>删除指定的elasticsearch的索引

/**
 * 删除索引
 */
@Test
void deleteExistsIndex() throws IOException {
    DeleteIndexRequest request = new DeleteIndexRequest("gong_indexs");//用来得到我的这个删除的这个索引对象,用来实现指定我的这个删除索引对象
    AcknowledgedResponse delete = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);//用来实现删除索引
    System.out.println(delete.isAcknowledged());
}

4>创建文档

    /**
     * 测试添加文档
     */
    @Test
    void testAddDocument() throws IOException {
        Gson gson = new Gson();//使用谷歌的Gson,把对象转换成json格式
        //创建document的对象
        User user = new User("龚俊豪", 18);//准备插入数据的实体类
        //创建请求
        IndexRequest request = new IndexRequest("gong_index");//创建我的这个索引库
        request.id("2");//设置这个索引的id
        request.timeout(TimeValue.timeValueSeconds(1));//设置我的这个数据的过期时间
        //设置过期时间的第二种方法
//        request.timeout("1");
        //将我们的这个数据存入到elasticsearch当中,在存入的时候我们要注意一定要你把这个数据转换成json格式的对象
        request.source(gson.toJson(user), XContentType.JSON);//发送响应,并且指定响应的格式
        //向客户端发送请求
        IndexResponse response = restHighLevelClient.index(request, RequestOptions.DEFAULT);//给我们的这个elasticsearch中发送请求信息,获取响应的结果
        System.err.println("数据"+response.toString());//查看这个发送响应的信息
        System.err.println("状态"+response.status());//打印这个响应数据的状态
    }

5>crud文档

[1]实现文档的数据添加

他主要是通过文档这个IndexRequest来设置文档这个索引的一些信息,比如说我需要把我的这个实体类添加到那个IndexRequest,注意我再存储数据的时候一定要使用gson把数据转换成Json格式,然后我再后面的这个Json的这个类型,比如说XContentType的这个类的对象当中,然后把我的IndexRequest放入到我的这个自定义的RestHigLevenlClient的高级客户端的这个自定义的对象当中

 /**
     * 测试添加文档
     */
    @Test
    void testAddDocument() throws IOException {
        //创建document的对象
        User user = new User("龚俊豪", 18);//准备插入数据的实体类
        //创建请求
        IndexRequest request = new IndexRequest("gong_index");//创建我的这个索引库
        request.id("2");//设置这个索引的id
        request.timeout(TimeValue.timeValueSeconds(1));//设置我的这个数据的超时时间
        //设置过期时间的第二种方法
//        request.timeout("1");
        //将我们的这个数据存入到elasticsearch当中,在存入的时候我们要注意一定要你把这个数据转换成json格式的对象
        request.source(gson.toJson(user), XContentType.JSON);//发送响应,并且指定响应的格式
        //向客户端发送请求
        IndexResponse response = restHighLevelClient.index(request, RequestOptions.DEFAULT);//给我们的这个elasticsearch中发送请求信息,获取响应的结果
        System.err.println("数据"+response.toString());//查看这个发送响应的信息
        System.err.println("状态"+response.status());//打印这个响应数据的状态
    }

[2]获取文档信息,判断文档中的数据是否存在

他这个的一个思路就是通过GetRequest的这个请求得到我需要获得的这个文档信息,最主要的步骤就是我需要使用getRequest的对象通过fetchSourceContetext来设置我的这个请求不获取数据,他需要去实例化一个FetchSourceContext对象,并且传入一个boolean类型的false值,最后我们还需要通过GetRequest对象去设置storedFilds来指定我需要查询的这个索引里面的字段

/**
 * 获取数据文档,判断我的这个文档的字段是否存在
 */
@Test
 void testIsExists() throws IOException {
    GetRequest getRequest = new GetRequest("gong_index","1");//得到这个索引的对象,然后通过这个Id来进行读取相关信息
    //当时我们是来获取这个文档是否存在,那么此时此刻我们可以不获取他的这个索引下标的内容
    getRequest.fetchSourceContext(new FetchSourceContext(false));//设置不获取索引文档的上下文
    getRequest.storedFields("name");//设置需要查询是否存在的
    boolean exists = restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT);//设置这个查询数据信息的方法
    System.out.println(exists);
}

 [3]根据文档下标去获取我的这个文档信息

他的一个思路就是通过GetRequest来根据文档这个索引的名称和这个索引的下标去读取到这个相对应的文档信息,然后通我们自定义的这个restHigLeelCient对象去通过我们自定义的RestHigLevelClient的get方法来得到response,通过这个response的对象去调用getSourceAsString得到文档源

/**
 * 获取文档的信息
 */
@Test
void testGetDocument() throws IOException {
    GetRequest request = new GetRequest("gong_index", "1");//获取这个索引下面的文档为1号的数据信息
    GetResponse response = restHighLevelClient.get(request, RequestOptions.DEFAULT);//得到我的这个对象的响应体
    System.out.println(response.getSourceAsString());//打印文档来源
    System.out.println(response);//打印整个响应头信息
}

[4]更新文档信息

更新文档:首先第一步我需要定义一个UpdateRequest来得到这个请求对象,按照上面的查询的思路一样,把我们的这个索引名称和我需要更改的下标,然后我们按照使用kibana的思路是一样的,首先设置我的这个响应超时时间,其次准备一个实体类对象,把需要更改的数据全部存放到我们的这个对象当中,使用doc文档的格式存入,最后把这个UpdateRequest对象放到我们的这个restHighLevelClient的这个Update的方法里面,并且指定我们的这个文档类型是默认的,最终通过updateResponse对象去调用status方法来得到我们的这个数据是否修改成功

/**
 * 更新文档信息
 */
@Test
void testUpdateDocument() throws IOException {
    UpdateRequest request = new UpdateRequest("gong_index", "1");//得到这个请求对象
    request.timeout("1s");//在修改的时候可以设置这个响应超时时间
    User user = new User("小郭", 16);//设置需要更改信息,以实体类的形式传入
    request.doc(gson.toJson(user),XContentType.JSON);//把需要修改的文档信息放入到这个文档信息当中,并且把我们的这个对象的信息需要变成json格式的数据,然后再第二个参数转换成
    UpdateResponse updateResponse = restHighLevelClient.update(request, RequestOptions.DEFAULT);//得到我的这个修改信息的响应体
    System.out.println(updateResponse.status());//显示这个修改的结果,如果修改成功就显示OK
}

 [5]使用elasticSearch来实现数据的批量插入

在实现批量数据插入的时候我们需要考虑接触到一个新的对象就是BulkRequest,通过这个Bulk的单词我们顾名思义就知道他是大批数据存入到elasticSearch当中,他的一个思路就是说我首先需要在BulkRequest的对象中设置我们的这个超时响应时间,然后我们可以准备一个对象集合,把我们的数据以对象的形式存入到我们的这个集合当中,其次我们可以通过for循环来便利我们的这个集合,通过使用IndexRequest的这个对象,来指定我们的这个索引的名称,然后这个索引编号我建议还是使用for循环的这个下标+1的形式来存入,这样可以达到我们的这个下标id他是属于一个有序,然后我们老样子通过source来把我们的这个集合里的数据循环的存入这个bulkRequest的这个对象中,注意我们需要把他转换成JSON格式,然后在第二个参数当中指定我们的这个数据类型是一个Json类型的数据,最后使用我们定义的这个高级客户端的restHithLevelClient对象去调用bulk,把我们的这个bulkRequest参数放入,和这个默认的文档类型存入到restHithLevelClient对象中,最终得到我们的这个响应体,我们通过这个bulkResponse的这个对象得到我们的这个数据的修改状态是怎样的

/**
 * 实现批量新增这个文档记录
 * 再插入我的这个信息的时候我的这个bulkResponse他的这个hasFailures是用来得到我的这个插入信息的结果
 * 如果说我的这个文档批量插入数据成功的话他是返回的一个false类型的变量
 */
@Test
void lockBlockRequest() throws IOException {
    BulkRequest bulkRequest = new BulkRequest();//得到我的这个批量信息数据的对象
    bulkRequest.timeout("1s");//设置我的这个响应的超时时间
    List<User> userArrayList = new ArrayList<>();//定义一个list[集合,用来存储用户的信息
    userArrayList.add(new User("小郭1",15));
    userArrayList.add(new User("小龚2",15));
    userArrayList.add(new User("小郭3",15));
    userArrayList.add(new User("小龚4",15));
    userArrayList.add(new User("小郭5",15));
    for (int i = 0; i < userArrayList.size(); i++) {
      bulkRequest.add(new IndexRequest("gong_index")//指定我的这个索引名称
                    .id(""+(i+1))//使用Id的时候建议使用for循环,保证我们的id是有序的
                    .source(gson.toJson(userArrayList.get(i)),XContentType.JSON));//注意我在实现批量新增的时候我的这个source需要把它转换成String类型的json字符串,注意在使用source的时候一定要指定数据类型为json
    }
    BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);//得到这个bulk的响应信息
    System.out.println(bulkResponse.hasFailures());//打印我的这个值是否响应成功,返回false就代表插入成功
}

[6]实现高亮查询elasticSerach里面的数据

既然我们要去做检索的话那么我们就需要用到检索数据的对象就是SearchRequest,我们得到这个对象的第一件事就是要得到我们的这个索引,然后我们现在就需要去实例化一个构建查询条件的对象,通过TermQueryBuilder对象,这个就需要通过termQuery来指定我们的这个需要进行高亮检索的字段和关键字返回值,

查看sourceBuilder的这些方法主要是通过这个SearchSourceBuilder类里面的所有的参数显示出来的,源码如下:

1.其中这个QueryBuilders可以通过matchAllQuery来得到我们的这个elasticSerach当中的所有值的

2.我们也可以通过termQuery来设置我们需要进行高亮查询的关键字以及索引字段名称,得到我们的这个TermQueryBuilder对象,其次我们通过把TermQueryBuilder放入我们刚刚定义的这个searchSourceBuilder里面其次还需要把我们的这个searchSourceBuilder对象存入到SearchRequest对象中,最后通过我们的这个高级客户端的对象--->RestHigLeventClient对象去调用search对象,把这个SearchRequest放入到restHighLevelClient.serach方法当中,来得到SearchRestResponse对象,通过这个对象去得到我们的这个响应的结果,通过使用getHits来得到响应的Json字符串

然后我们再去设置 ,注意在进行查询数据的时候我们只能去通过一个字去进行查询

3.我们在便利的时候需要通过这个SearchRespons的这个对象中的SearchHits类中的getHits的这个方法,这个方法主要是得到了响应的所有的数据

 /**
    * 查询我的这个文档的数据 
     * 主要是通过搜索请求SearchRequest
     * 构建高亮查询查询TermQueryBuilder
     * 通过使用使用matchAllQuery来查询整个索引的数据
     *
     * @throws IOException
     */
    @Test
    void testSearch() throws IOException {
        SearchRequest request = new SearchRequest("gong_index");//得到我的这个request的方法,主要是用来得到我的这个请求方法
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //查询条件使用QueryBuilder的工具类来进行实现
        //查询条件 QueryBuilders.termQuery精确匹配,主要是通过高亮查询,就是根据某一个关键字来进行查询
        TermQueryBuilder queryBuilder = QueryBuilders.termQuery("name", "龚");
//        MatchAllQueryBuilder queryBuilder = QueryBuilders.matchAllQuery();//查询整个索引文档的数据
        sourceBuilder.query(queryBuilder);
        //设置当前的这个查询时间
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        //然后把我们的这个sourceQueryBuilder放入到我们的这个查询数据的构建器里面去
        request.source(sourceBuilder);//把这个索引对象放入到这个request对象里面进行构造器构造
        SearchResponse searchResponse = restHighLevelClient.search(request, RequestOptions.DEFAULT);//得到我的这个查询的响应对象
        System.out.println(gson.toJson(searchResponse.getHits()));//输出我的这个响应状态
        System.out.println("======================");
        for (SearchHit documentFields : searchResponse.getHits().getHits()) {
            System.out.println(documentFields.getSourceAsMap());//打印出我们所有的数据
        }
    }

三.完成京东的搜索信息

1.爬虫

1>是什么

我们在实现项目搜索的过程当中要么是用的数据库当中的数据,要么就会是把数据存储在缓存当中,要么就是使用爬虫爬取相关信息

2>导入的相关依赖

<!--        同时也可以使用jsoup来获取相关电影信息-->
<!--        解析网页当中的相关数据,解析网页相关信息-->
        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.10.2</version>
        </dependency>

 3>然后我们需要去编写一个获取数据的工具类

测试爬取相关网页的相关代码

爬取数据的这个主要的思路是:

首先需要得到我们的这个请求商品数据的Url地址,其中我可以使用我们刚刚引入的这个jsoup的依赖来通过这个Jsoup使用Parse参数来把url,注意我们在传入url参数的时候我们需要实例化一个Url对象,把我们的这个url地址放到我们的这个参数当中,并且把我们的这个超时时间传入到这个Parse中,这个超时时间的意思就是如果说我的这个数据在我们指定的这个时间之内如果说还未响应到相关的结果信息那么他就会抛出一个IO流的相关信息,然后我们可以通过这个document根据我们的这个页面上面的一些id或者是标签得到我们的这个element对象,最后通过这个element对象得到我们的这个标签里面的信息或者是id里面的相关信息,如果说我们需要把他变成一个对象类型的集合,在这个工具类方法当中实例化一个对象类型的集合,然后把我们得到的相关数据封装到我们的这个对象当中,并且把集合进行返回,比如说下面这张图 

一下代码是我的这个测试爬取数据的demo,我开始是判断我这个数据是否能够爬取成功,我们测试之后发现没问题我们就把这个数据发放到我们的这个Content实体类集合中

 //首先我们在解析网页的时候我们需要得到我们的这个爬取网页信息的Url地址,然后在使用我们的这个jsoup工具包
        String url = "https://search.jd.com/Search?keyword=java";//得到我们需要获得的这个数据的url地址,在这里前提是电脑设备要连接网络
        //实例化一个document对象,然后通过这个document对象可以实现获得前端的一些html页面的标签
        //这个jsoup的第二个参数的意思是这个程序最多等待三十秒之后如果未读取这个Url信息就会抛出相关的异常信息
        Document document = Jsoup.parse(new URL(url), 30000);
        Element element = document.getElementById("J_goodsList");//这个主要是通过京东的这个商品的网页的Html代码得到他的这个数据的id,然后得到我们的这个element对象,可以通过这个element对象来得到所有的相关信息
        //在京东的页面在这个id为J_goodsList的方法当中他是由多个li标签组成的,所有我们可以通过这个Element对象来得到这个下面的所有的li标签,然后放入到我们的这个页面当中
        Elements elementsByTag = element.getElementsByTag("li");//得到所有的li标签
//        System.out.println(elementsByTag);
        for (Element el : elementsByTag) {
            //首先我们在这里会发现我们在使用p-img的这个class标签去得到相关的数据,我们获取不到,关于图片特别多的网址都是延迟加载的
            //这个主要是采用的一个懒加载的机制,在我们的这个jd的这个html的代码可以查看都
            String img = el.getElementsByTag("img").eq(0).attr("data-lazy-img");//得到文档这个img标签的所有数据
            // 这句话的主要意思是说我获得我这个页面中的所有的img标签,然后通过这个标签来获取得到这个data-lazy-img属性,他是属于一种懒加载的模式
            String price = el.getElementsByClass("p-price").eq(0).text();//得到我的这个京东页面所响应的价格相关的数据信息
            String title = el.getElementsByClass("p-name").eq(0).text();//得到每个商品的名称信息
            System.out.println("=====================================");
            System.out.println(img);
            System.out.println(price);
            System.out.println(title);
        }

爬取图片信息注意事项,他的这个图片就相当于是懒加载的形式,通过调用这个标签来得到我们的则个图片的url地址

 这个的id我主要是根据京东上面的这个id来进行获取相关的信息,所以我们主要还是更具这个id来进行爬取

我们同时也可以把我们的这个爬取出来的数据转换成list集合批量存放到我们的elasticSearch当中,批量添加我们还是按照上面的这个BulkRequest来实现数据添加

4>使用代码的方式实现高亮查询

在我们的这个代码中实现高亮查询还是和我使用kibana的方法益一样,首先现需要在我们的这个SearchBuilder的这个对象中去调用我们的这个 highlighter()的方法,在这个方法当中他需要一个highlighterBuilde类型的参数,然后通过这个higiligthterBuilder的这个对象去设置我们需要通过这个higligthterBuilder对象当中的field的这个方法去设置我们这个字段名称,其次再根据preTags来设置前缀,就是说我的这个字段的一些样式的前缀,最后再去根据postTags来设置我的这个后缀,一般就是设置我们这个标签的后缀,然后我们把这个highlighterBuilder参数添加到我们的这个searchBuilder的这个highlighter的这个方法当中,然后还可以设置一些查询的条件,最后我们去便利我们的这个response下的hits这个方法,然后把我们的这个循环便利这个hits().hits()的这个方法,然后我们得到我们的这个高亮的字段数据HighlightFields,然后我们需要进行去get他的这个值,其次去得到我们未进行高亮设置的这个数据getSourceAsMap,得到一个Map集合,最后

判断他是否为空,如果不为空我们就替换这个getSourceAsMap集合中的这个key,最后把我们的这个Map集合存到我们的这个自定义的list集合当中,最后进行返回给前端

代码如下:

 /**
     * 用来实现高亮查询
     * @param keyWords
     * @param pageSize
     * @param pageNo
     * @return
     * @throws Exception
     */
    @Override
    public List<Map<String, Object>> searchPage(String keyWords, int pageSize, int pageNo) throws Exception {
        List<Map<String, Object>> pageInfo = new ArrayList<>();//得到我当前的这个数据
        //首先我们如果说我的这个页码是为零的话我们需要进行页码的初始化
        if (pageNo<=1) {
            pageNo = 1;
        }
        //因为我需要根据我的这个条件来进行检索查询,那么我们就需要实例化一个条件searchRequest的对象来实现进行检索
        SearchRequest request = new SearchRequest("jd_content");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();//得到这个search的builder对象

        sourceBuilder.from(pageNo);//设置分页的相关页码
        sourceBuilder.size(pageSize);//设置当前页码的数据大小条数

        //TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title",keyWords);//的带我的这个相关的参数信息,这个使用的是最细粒度划分
        MatchPhraseQueryBuilder termQueryBuilder = QueryBuilders.matchPhraseQuery("title", keyWords);//实现精准查询
        //设置高亮字段
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("title");//指定高亮字段名称
        highlightBuilder.requireFieldMatch(false);//是否开启多个高亮
        highlightBuilder.preTags("<span style='color:red'>");//设置前缀高亮
        highlightBuilder.postTags("</span>");//设置后缀高亮
        //进行构建
        sourceBuilder.highlighter(highlightBuilder);

        sourceBuilder.query(termQueryBuilder);//把我们的这个参数对象放到这个Builder里面
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));//设置我的这个超时响应时间,并且设置我的这个时间的单位


        request.source(sourceBuilder);//把这个检索对象存放到我的这个search的这个请求当中
        SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);//得到我的这个search对象所响应出来的相关数据


        for (SearchHit documentFields : response.getHits().getHits()) {//循环便利我们的这个数据信息
            Map<String, HighlightField> highlightFields = documentFields.getHighlightFields();//得到我们的择膏高亮字段
            HighlightField title = highlightFields.get("title");//得到title高亮的字段
            Map<String, Object> sourceAsMap = documentFields.getSourceAsMap();//得到原来的结果
//            sourceAsMap.put("title",title);
            if (title != null) {
                Text[] fragments = title.fragments();//得到title信息,通过这个fragments对象来得到的我们需要高亮的信息
                String n_title = "";//定义一个title方法,用来拼接我们的这个title信息
                for (Text fragment : fragments) {
                     n_title += fragment;//得到我们的这个tile信息
                    sourceAsMap.put("title",n_title);//把我们的这个标题存放到我们的这个集合当中去进行替换
                }
            }
            pageInfo.add(sourceAsMap);//得到我们相关的数据存入到这个Map集合当中
        }
        return pageInfo;//返回我当前这个到我们的这个集合
    }

 因为我们使用高亮的时候他后端会把我们设置的这个标签进行传递到前端,那么我们在前端就需要进行解析,在解析的时候我们可以利用vue的这个"v-html"来进行解析,代码如下

<!-- 商品详情 -->
<div class="view grid-nosku">
    <!--使用for循环来便利后端传过来的集合-->
    <div class="product" v-for="content in resource">
        <div class="product-iWrap" >
            <!--商品封面-->
            <div class="productImg-wrap">
                <a class="productImg">
                    <img :src="content.img">
                </a>
            </div>
            <!--价格-->
            <p class="productPrice">
                <em><b>¥</b>{{content.price}}</em>
            </p>
            <!--标题-->
            <p class="productTitle">
                <a v-html='content.title'></a>
            </p>
            <!-- 店铺名 -->
            <div class="productShop">
                <span>店铺: GJH说Java </span>
            </div>
            <!-- 成交信息 -->
            <p class="productStatus">
                <span>月成交<em>999笔</em></span>
                <span>评价 <a>3</a></span>
            </p>
        </div>
    </div>
</div>

 demo的gitee地址:

Gong/elasticsearch

项目的gitee地址:

elasticsearch-jd: 实现模仿京东的搜索引擎商品信息,前提需要按照elasticSearch以及ik分词器等等

        

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 一个简易的网上书店项目可以包括以下功能:用户注册、用户登录、图书分类浏览、商品搜索、商品详情展示、购物车管理、下订单、支付、订单查询等模块。其中,用户注册和登录模块可以使用Spring Security等框架实现账户的安全控制;图书分类和搜索模块可以使用SolrCloud或Elasticsearch搜索引擎技术实现高效的全文检索和分类浏览;商品详情展示模块可以使用SpringMVC等框架实现前后端的交互;购物车管理和下订单等模块可以使用Mycat等数据库中间件实现高可用的数据库管理。整个项目需要考虑性能、可扩展性、安全性等方面的问题,可以运用常用的设计模式和架构思想进行优化和改进。 ### 回答2: javaweb网上书店简易项目是一个典型的MVC模型应用的案例,主要涵盖了前后端的一些技术和知识,如JSP、Servlet、JDBC等。下面将对该项目做一些简要的介绍。 1. 项目需求 该项目的需求是构建一个简单的在线书店,用户可以通过网站在书店进行购物、查找并购买书籍。管理员可以对书籍进行管理和维护。 2. 系统分析 在系统分析中,需要确定项目的范围和功能,进行数据建模,分析整个计划的技术实现途径,并完成 functional requirements document(FRD)和technical design document(TDD)。 3. 技术选型 在技术选型方面,该项目主要使用了JSP、Servlet、JDBC等技术。对于前端页面,通过JSP技术来实现数据的显示和页面的交互。后端通过Servlet来处理请求,并且使用JDBC对MySQL中的数据进行管理和维护。 4. 数据库设计 该项目主要使用MySQL数据库,并进行了适当的数据模型设计。数据表包括书籍信息表、用户信息表、订单信息表等。在设计表结构时,需要考虑到数据之间的一些关系及数据的完整性。 5. 开发测试 在开发过程中,需要先完成基本的代码架构和数据库的连接。其次,先实现用户注册、登录等基本功能。然后实现书籍的添、修改和删除等管理员功能。最后实现用户和管理员购买、查询和管理订单等功能。 在开发测试阶段,可以使用JUnit对代码进行单元测试,并使用Postman进行API测试。以结果为中心的开发可以最大程度地减少错误和改进工作。 6. 部署上线 最后,需要将开发好的项目部署到服务器上。通常情况下,根据项目复杂程度和实际场景,可以选择Tomcat、Nginx等服务器软件进行部署,以保证网站的可用性和性能。 总之,javaweb网上书店简易项目完整案例中包含了前端和后端一些知识点和技术,需要具备Java EE相关的知识和技能,并掌握一定的数据库设计和操作知识。同时,具备良好的编程思维和团队协作能力也是实现项目成功的必要条件。 ### 回答3: JavaWeb网上书店是一个完整的案例,主要目的是为了展示用JavaWeb开发一个前后端完整的电子商务网站的流程和步骤。该项目使用JavaWeb的核心技术,如Servlet、JSP、JDBC和Tomcat等,以及MySQL数据库。该项目采用了MVC设计模式,分为模型层、视图层和控制层。 该项目的主要功能模块包括:用户管理、商品管理、购物车、订单管理和支付等。用户可以注册账号、登录系统,在商品模块中浏览商品信息,将商品入购物车,提交订单并完成支付。管理员可以添、删除和修改商品信息,查看订单信息并进行管理。 该项目采用了Bootstrap前端框架和JQuery库,使得Web页面看起来更美观、简洁、易用。在数据库设计上,使用了关系型数据库MySQL,利用JDBC连接数据库,并使用DAO层进行数据访问操作。 该项目的开发涵盖了从需求分析到设计、编码和测试的全过程,是初学JavaWeb的程序员进行代码学习和开发的好工具。通过学习该项目,程序员可以了解到JavaWeb的基本架构和API,熟悉JavaWeb的开发流程和工具,掌握了基本的MVC开发模式、前后端分离和数据持久化等技术,能够从中获得更深入的JavaWeb开发经验。 总之,JavaWeb网上书店项目是一个完整的电子商务案例,包含了JavaWeb开发的全部流程和技术,为初学者提供了一个完整的学习教程,同时也为对JavaWeb开发感兴趣的开发人员提供了一个优秀的参考案例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值