ElasticSearch 分布式全文检索

ElasticSearch 分布式全文检索


一、ElasticSearch 概述

在这里插入图片描述

谁在使用:

在这里插入图片描述
ElasticSearch 和 Solr 对比:

ElasticSearch 简介:

在这里插入图片描述
Solr 简介:
在这里插入图片描述
对比:

  1. 当单纯的对已有的数据进行搜索时,Solr 更快。
    在这里插入图片描述
  2. 当实时建立索引时,Solr 会产生io阻塞,查询性能较差,Elasticsearch 具有明显的优势。
    在这里插入图片描述
  3. 随着数据的增加,Solr的搜索效率会变得更低。
    在这里插入图片描述

总结:
在这里插入图片描述

ES 核心概念:
在这里插入图片描述
ElasticSearch 本身就是一个集群:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
核心概念总结:

  1. 索引
  2. 字段类型(mapping)
  3. 文档(documents)

二、ElasticSearch 安装

ElasticSearch 官网

ElasticSearch 官方下载地址

1. Windows 下使用

  1. 解压下载的 windows 版本的 ElasticSearch :
    在这里插入图片描述
  2. 熟悉目录!
bin  # 启动文件
config # 配置文件
	log4j2	日志配置文件
	jvm.options java 虚拟机相关的配置
	elasticsearch.yml	elasticsearch 的配置文件!默认 9200 端口!
lib	# 相关jar 包
logs # 日志
modules # 功能模块
plugins # 插件
  1. 启动 ElasticSearch 服务,双击 该文件
    在这里插入图片描述

  2. 测试访问 localhost:9200
    在这里插入图片描述

  3. 安装 ElasticSearch 可视化界面 head 插件
    下载地址
    在这里插入图片描述

  4. 安装 head 插件需要 node.js 环境,所以先安装 node.js
    Node.js 安装详解

  5. 安装node.js 后再 head 根目录下 执行:cnpm install 命令
    在这里插入图片描述

  6. 运行 head :npm run start
    在这里插入图片描述

  7. 测试访问 localhost:9100,发现无法连接上我们的 localhost:9200(ElasticSearch 服务),需解决跨域问题
    在这里插入图片描述

  8. 修改 ElasticSearch 里的配置在这里插入图片描述
    在这里插入图片描述

  9. 重启 ElasticSearch 发现可以连接了
    在这里插入图片描述

2. 安装 Kibana

什么是Kibana?
在这里插入图片描述
Kibana 官网

Kibana 下载地址
注意:Kibana 版本需和 ElasticSearch 版本一致
在这里插入图片描述

下载后进行解压:
在这里插入图片描述

双击bin 目录下的 kibana.bat 文件 即可启动(同样需要node.js 的环境):
在这里插入图片描述

访问测试:http://localhost:5601
在这里插入图片描述

我们之后的所有操作都从这里编写:
在这里插入图片描述

我们也可以设置成中文的(默认是英文的),编辑此文件
在这里插入图片描述

添加这行配置即可:
在这里插入图片描述
测试重启 kibana,发现切换成中文了!!!
在这里插入图片描述

3. IK 分词器插件

什么是 IK 分词器?
在这里插入图片描述

IK 分词器下载地址
在这里插入图片描述

解压发送到我们的 ElasticSearch 的插件目录下即可:
在这里插入图片描述

重启 ES ,可以看到 IK 可以被加载了
在这里插入图片描述
使用 Kibana 进行测试:

在这里插入图片描述

发现 我们输入的词被自动拆分了,那么我们如何添加 自定义的 分词呢 ? 编辑添加的 ik 插件 下的文件
在这里插入图片描述
在这里插入图片描述

比如我们新建文件 myself.dic
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

重启 ES 测试效果:
在这里插入图片描述

在这里插入图片描述

三、Rest 风格操作

Rest 风格说明:
在这里插入图片描述

1. 索引的命令操作

  1. 创建一个索引:
PUT /索引(可以理解为数据库名)/类型名(未来没有这个了)/文档id
{请求体}

在这里插入图片描述

在访问我们的head,发现多了个 test1,表示索引 test1 创建成功
在这里插入图片描述
在这里插入图片描述

点击数据浏览,查看test1,发现多了我们创建的这条数据了
在这里插入图片描述
那么 name 这个字段用不用指定类型呢,毕竟在我们关系型数据库是要指定类型的。
ElasticSearch 的数据类型有:
在这里插入图片描述

  1. 新建索引规则:
    在这里插入图片描述
    在这里插入图片描述

  2. 获取索引命令:GET [ 索引 ]
    在这里插入图片描述

  3. 创建索引中的默认类型:PUT [索引名称]type名称(可以不写,默认_doc)[][文档名称]
    在这里插入图片描述
    在这里插入图片描述
    同时可以看出,如果自己的文档字段没有指定类型,那么es会给我们默认配置字段类型!!

  4. 通过 GET /_cat/indices?v 可以看到所有索引的详细信息
    在这里插入图片描述

  5. 如何修改数据呢?

    1. 通过 PUT 直接覆盖(弊端:如果里面有某个字段数据漏了,那个字段也会消失)
      在这里插入图片描述
    2. 使用 POST …/update 来修改(只会修改传输的字段值,没有传输的字段不会改变)
      在这里插入图片描述
  6. 删除索引;DELETE [ 索引 ]
    在这里插入图片描述

2. 文档的命令操作

  1. 添加一条数据:这里的索引若没有则新建
    在这里插入图片描述
    在这里插入图片描述
    创建第二条数据:如果id 还会 1 就会对已有 id = 1 的那条数据进行更新
    在这里插入图片描述

  2. 获取数据:GET /索引/TYPE/文档
    在这里插入图片描述

  3. 根性数据,除了上述说的用PUT 的可以更新外,最好用 PST _update 进行更新:只会更新传输的字段,没有传输的字段保持原值。
    在这里插入图片描述

  4. 搜索:

    1. 根据 id 搜索
    GET test1/user/1
    
    1. 根据条件搜索:这里的name 后面没有加 " " 则会分词查询,加了 “ ” 则为精准查询
      在这里插入图片描述

    我们的查询结果中有一个分数栏,表示匹配度,匹配度越高,分数越高。
    在这里插入图片描述

    1. 复杂查询:查询请求 + 参数体
      在这里插入图片描述

6.查询结构解析:
在这里插入图片描述

  1. 查询出来的结果,只显示我们想要的字段信息:
    在这里插入图片描述

  2. 排序查询
    在这里插入图片描述

  3. 分页查询(数据下标还是从0开始的,和学的所有数据结构是一样的!)
    在这里插入图片描述

  4. 布尔值查询:must(and),所有的条件都要符合 where id = 1 and name = xxx
    在这里插入图片描述

  5. 布尔值查询:should(or),所有的条件都要符合 where id = 1 or name = xxx
    在这里插入图片描述

  6. 布尔值查询:must_not
    在这里插入图片描述

  7. 过滤器
    在这里插入图片描述
    在这里插入图片描述

    -	gt		大于
    -	gte		大于等于
    -	lt		小于
    -	lte	小于等于
    
  8. 一个字段,多个条件查询
    在这里插入图片描述

  9. 精确查找
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    总结:term 只支持精确查询,match 模糊查询(分词),match + keyword 类型支持精确查询

  10. 精确查询多个值:
    在这里插入图片描述

  11. 高亮查询
    在这里插入图片描述

  12. 高亮查询 使用我们自定义标签
    在这里插入图片描述

四、集成SpringBoot

1. 项目继承过程

  1. 创建 maven 项目 elasticsearch-study 项目
  2. 添加 pom 依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.study</groupId>
    <artifactId>elasticsearch-study</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>elasticsearch-study</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.72</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>
  1. 主启动类
package com.study.elasticsearchstudy;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ElasticsearchStudyApplication {

    public static void main(String[] args) {
        SpringApplication.run(ElasticsearchStudyApplication.class, args);
    }

}
  1. 添加 RestHighLevelClient 配置类(配置连接信息)
package com.study.elasticsearchstudy.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 client = new RestHighLevelClient(
                RestClient.builder(new HttpHost("127.0.0.1", 9200, "http")
                )
        );
        return client;
    }

}

  1. 编写测试类:创建索引 kuang_index
package com.study.elasticsearchstudy;

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.boot.test.context.SpringBootTest;

import java.io.IOException;

@SpringBootTest
class ElasticsearchStudyApplicationTests {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Test
    void contextLoads() throws IOException {

        CreateIndexRequest request = new CreateIndexRequest("kuang_index");

        CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);

        System.out.println(createIndexResponse);
    }

}

6.测试结果:控制台打印输出 和 head 页面出现新建的索引
在这里插入图片描述
在这里插入图片描述

2. 索引的API操作

  1. 创建索引
/**
 *	RestHighLevelClient 配置信息
 *
 */
@Configuration
public class ElasticSearchConfig {

    @Bean
    public RestHighLevelClient restHighLevelClient(){

        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(new HttpHost("127.0.0.1", 9200, "http")
                )
        );
        return client;
    }
}

@SpringBootTest
class ElasticsearchStudyApplicationTests {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Test
    void contextLoads() throws IOException {

        CreateIndexRequest request = new CreateIndexRequest("kuang_index");

        CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);

        System.out.println(createIndexResponse);
    }

}
  1. 获取索引
	/**
     * 获取索引
     */
    @Test
    public void testExisIndex() throws IOException {

        GetIndexRequest request = new GetIndexRequest("kuang_index");

        boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);

        System.out.println(exists);
    }
  1. 删除索引
	/**
     * 删除索引
     */
    @Test
    public void testDeleteIndex() throws IOException{
        DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest("test13");

        AcknowledgedResponse delete = restHighLevelClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
        //delete.isAcknowledged() 为 true 为删除成功
        System.out.println(delete.isAcknowledged());
    }

2. 文档的API操作

添加实体类:User

package com.study.elasticsearchstudy.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class User {
    private String name;
    private int age;

} 
  1. 添加文档
/**
     *  添加文档
     */
    @Test
    public void testAddDocument() throws IOException {
        User user = new User("狂神",3);
        IndexRequest request = new IndexRequest("kuang_index");
        request.id("1");
        request.timeout(TimeValue.timeValueSeconds(1));

        // 将我们的数据放入请求 json
        request.source(JSON.toJSONString(user), XContentType.JSON);

        // 客户端发送请求,获取相应结果
        IndexResponse index = restHighLevelClient.index(request, RequestOptions.DEFAULT);

        System.out.println(index.toString());
        System.out.println(index.status());

    }

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

  1. 判断文档是否存在
/**
     * 获取文档,判断是否存在  get /index/doc/1
     */
    @Test
    public void testIsExists() throws IOException {
        GetRequest getRequest = new GetRequest("kuang_index", "1");
        // 不获取返回的 _source 的上下文
        getRequest.fetchSourceContext(new FetchSourceContext(false));
        //不做排序
        getRequest.storedFields("_none_");

        boolean exists = restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT);

        System.out.println(exists);

    }
  1. 获取文档信息
/**
     * 获取文档,判断是否存在  get /index/doc/1
     */
    @Test
    public void testGetDocument() throws IOException {
        GetRequest getRequest = new GetRequest("kuang_index", "1");
        GetResponse getResponse = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
        System.out.println(getResponse.getSourceAsString());//打印文档的内容
        System.out.println(getRequest);

    }

在这里插入图片描述

  1. 更新文档
 /**
     *  更新文档
     */
    @Test
    public void testUpdateDocument(){
        UpdateRequest updateRequest = new UpdateRequest("kuang_index", "1");
        updateRequest.timeout("1s");

        User user = new User("狂神说Java", 18);
        updateRequest.doc(JSON.toJSONString(user),XContentType.JSON);

        UpdateResponse update = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
        System.out.println(update.status());
    }
  1. 删除文档
/**
     * 删除文档
     */
    @Test
    void testDeleteRequest(){
        DeleteRequest request = new DeleteRequest("kuang_index", "1");
        request.timeout("1s");

        DeleteResponse delete = restHighLevelClient.delete(request, RequestOptions.DEFAULT);
        System.out.println(delete.status());

    }
  1. 批量导入数据
/**
     * 批量导入数据
     */

    @Test
    void testBulkRequest() throws IOException {
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout("10s");

        ArrayList<User> users = new ArrayList<>();
        users.add(new User("kaungsheng",3));
        users.add(new User("kaungsheng",3));
        users.add(new User("kaungsheng",3));
        users.add(new User("kaungsheng",3));
        users.add(new User("kaungsheng",3));
        users.add(new User("kaungsheng",3));
        users.add(new User("kaungsheng",3));
        users.add(new User("kaungsheng",3));
        users.add(new User("kaungsheng",3));

        for (int i = 0 ; i < users.size();i++) {
            // 批量更新和批量删除,就在这里修改对应的请求就可以了
            bulkRequest.add(new IndexRequest("kuang_index")
                    .id(""+(i+1))//不设置id,会自动给一个随机的id,不会重复
                    .source(JSON.toJSONString(users.get(i)),XContentType.JSON));

        }
        BulkResponse bulkItemResponses = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);

        //是否失败 false=成功/true=失败
        System.out.println(bulkItemResponses.hasFailures());

    }
  1. 条件查询
    /**
     * 条件查询
     *
     * SearchRequest 搜索请求
     * SearchSourceBuilder 条件构造
     * HighlighBuilder 构造高亮
     * TermQueryBuilder 精确查询
     * MatchAllQueryBuilder
     * xxx QueryBuilder 对应一个个命令
     */
    @Test
    void testSearch() throws IOException {
        SearchRequest searchRequest = new SearchRequest("kuang_index");
        // 构建搜索条件
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 查询条件,我们可以使用 QueryBuilders 工具来实现
        // QueryBuilders.termQuery 精确
        // QueryBuilders.matchAllQuery() 匹配所有
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", "kaungsheng");
//        MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
        searchSourceBuilder.query(termQueryBuilder);
        searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));

        searchRequest.source(searchSourceBuilder);

        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        System.out.println(JSON.toJSONString(search.getHits()));
        System.out.println("====================================");
        for (SearchHit documentFields : search.getHits().getHits()) {
            System.out.println(documentFields.getSourceAsMap());
        }
    }

在这里插入图片描述

五、京东搜索(实战)

  1. 创建 maven 项目 elasticsearch.jd
  2. pom
<dependencies>
        <!--解析网页-->
        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.10.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.76</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
  1. properties
server.port=9090
#关闭 thymeleaf 缓存
spring.thymeleaf.cache=false
  1. 主启动类
package com.study.elasticsearchjd;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ElasticsearchJdApplication {

    public static void main(String[] args) {
        SpringApplication.run(ElasticsearchJdApplication.class, args);
    }
}

  1. 配置类
package com.study.elasticsearchjd.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;
    }
}
  1. pojo
package com.study.elasticsearchjd.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Content {
    private String title;
    private String img;
    private String price;
}

  1. 工具类 (用来爬取网站页面数据)
package com.study.elasticsearchjd.utils;

import com.study.elasticsearchjd.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.URL;
import java.util.ArrayList;
import java.util.List;

public class HtmlParseUtil {

    public static void main(String[] args) throws IOException {
        HtmlParseUtil.parseJD("java").forEach(System.out::println);
    }
    public static List<Content> parseJD(String keyword) throws IOException {
        /// 使用前需要联网
        // 请求url
        String url = "http://search.jd.com/search?keyword=" + keyword;
        // 1.解析网页(jsoup 解析返回的对象是浏览器Document对象)
        Document document = Jsoup.parse(new URL(url), 30000);
        // 使用document可以使用在js对document的所有操作
        // 2.获取元素(通过id)
        Element j_goodsList = document.getElementById("J_goodsList");
        // 3.获取J_goodsList ul 每一个 li
        Elements lis = j_goodsList.getElementsByTag("li");
//        System.out.println(lis);
        // 4.获取li下的 img、price、name
        // list存储所有li下的内容
        List<Content> contents = new ArrayList<Content>();
        for (Element li : lis) {
            // 由于网站图片使用懒加载,将src属性替换为data-lazy-img
            String img = li.getElementsByTag("img").eq(0).attr("data-lazy-img");// 获取li下 第一张图片
            String name = li.getElementsByClass("p-name").eq(0).text();
            String price = li.getElementsByClass("p-price").eq(0).text();
            // 封装为对象
            Content content = new Content(name,img,price);
            // 添加到list中
            contents.add(content);
        }
//        System.out.println(contents);
        // 5.返回 list
        return contents;
    }

}

  1. 业务类
package com.study.elasticsearchjd.service;

import com.alibaba.fastjson.JSON;
import com.study.elasticsearchjd.pojo.Content;
import com.study.elasticsearchjd.utils.HtmlParseUtil;
import org.apache.lucene.util.QueryBuilder;
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.xcontent.XContentType;
import org.elasticsearch.core.TimeValue;
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.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 parseContent(String keywords) throws IOException {
        List<Content> contents = HtmlParseUtil.parseJD(keywords);
        //把查询到的数据放入es中
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout("2m");

        for (int i = 0; i < contents.size(); i++) {
            bulkRequest.add(
                    new IndexRequest("jd_good").source(JSON.toJSONString(contents.get(i)), XContentType.JSON));
        }
        BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        return !bulk.hasFailures();
    }

    /**
     *  获取这些数据实现搜索功能
     */
    public List<Map<String,Object>> searchPage(String keyword,int pageNo,int pageSize) throws IOException {
        if (pageNo<=1){
            pageNo = 1;
        }
        //条件搜索
        SearchRequest searchRequest = new SearchRequest("jd_good");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        //分页
        searchSourceBuilder.from(pageNo);
        searchSourceBuilder.size(pageSize);

        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", keyword);
        searchSourceBuilder.query(termQueryBuilder);
        searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));

        //执行搜索
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        //解析结果
        ArrayList<Map<String,Object>> list = new ArrayList<>();
        for (SearchHit hit : searchResponse.getHits().getHits()) {
            list.add(hit.getSourceAsMap());
        }

        return list;
    }

	/**
     *  获取这些数据实现搜索功能(高亮)
     */
    public List<Map<String,Object>> searchPageForHighLight(String keyword,int pageNo,int pageSize) throws IOException {
        if (pageNo<=1){
            pageNo = 1;
        }
        //条件搜索
        SearchRequest searchRequest = new SearchRequest("jd_good");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        //分页
        searchSourceBuilder.from(pageNo);
        searchSourceBuilder.size(pageSize);

        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", keyword);
        searchSourceBuilder.query(termQueryBuilder);
        searchSourceBuilder.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>");
        searchSourceBuilder.highlighter(highlightBuilder);

        //执行搜索
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        //解析结果
        ArrayList<Map<String,Object>> list = new ArrayList<>();
        for (SearchHit hit : searchResponse.getHits().getHits()) {
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            HighlightField title = highlightFields.get("title");
            Map<String, Object> sourceAsMap = hit.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(hit.getSourceAsMap());
        }

        return list;
    }



}

  1. controller
package com.study.elasticsearchjd.controller;

import com.study.elasticsearchjd.pojo.Content;
import com.study.elasticsearchjd.service.ContentService;
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;

import java.io.IOException;
import java.util.List;
import java.util.Map;

@RestController
public class ContentController {

    @Autowired
    private ContentService contentService;

    @GetMapping("/parse/{keyword}")
    public Boolean parse(@PathVariable("keyword") String keyword) throws IOException {
        return contentService.parseContent(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 IOException {
        return contentService.searchPage(keyword,pageNo,pageSize);
    }
}

  1. 测试结果:
    在这里插入图片描述
    在这里插入图片描述

vue解析高亮字段:

在这里插入图片描述

效果如下:即实现了高亮

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值