【SpringBoot学习】44、SpringBoot 集成 Elasticsearch-7.6 实战

@

  • 1、相关文档、链接

  • 2、软件安装

    • (1)安装 Elasticsearch

    • (2)安装 Head

    • (3)安装 IK 分词器

    • (4)安装 Kibana

  • 1、SpringBoot 集成 ES

  • 2、概念入门思想

  • 1、索引 API

    • (1)创建索引

    • (2)索引是否存在

    • (3)获取索引

    • (4)删除索引

  • 2、文档 API

    • (1)添加文档

    • (2)文档是否存在

    • (3)获取文档

    • (4)更新文档

    • (4)删除文档

  • 3、批量 API

    • (1)批量导入数据

    • (2)查询数据

    • (3)查询数据-分页

    • (3)查询数据-高亮


Hello,各位小伙伴们,最近忙于公司项目,没有太多的时间分享技术文档,今天抽空学习一下 Elasticsearch 这门搜索引擎技术。在大数据时代,不会搜索引擎确实有点说不过去,下面我们通过简单的实战,让各位小伙伴上手这个 elasticsearch 搜索引擎,能达到企业级的实战水准

一、环境搭建

1、相关文档、链接

有部分地址是使用的华为镜像地址下载的,国内的速度快,https://mirrors.huaweicloud.com

官方文档

  • 官方所有文档:https://www.elastic.co/guide/en/elasticsearch/reference/index.html
  • 官方 7.9.x 文档:https://www.elastic.co/guide/en/elasticsearch/reference/7.6/index.html
  • Java REST Client (deprecated):https://www.elastic.co/guide/en/elasticsearch/client/java-rest/index.html
  • elasticsearch 官方文档的 API 列表:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.6/java-rest-high-supported-apis.html

下载地址,找到对应的版本,直接点击下载即可,我这里统一使用的是 7.6.1

  • elasticsearch 下载地址:https://repo.huaweicloud.com/elasticsearch/
  • IK 分词器下载地址:https://github.com/medcl/elasticsearch-analysis-ik
  • kibana 下载地址:https://mirrors.huaweicloud.com/kibana/
  • elasticsearch-head 下载地址:https://github.com/mobz/elasticsearch-head
  • logstash 下载地址:https://mirrors.huaweicloud.com/logstash/

也有最新版本,但是为了稳定长时间使用,建议还是使用同一个版本,有哪些坑,哪些潜在问题,用多了自然就熟练了,有时间再多研究新版本

2、软件安装

本片文章讲解 Windows 环境下的操作,Linux 环境下搭建 ES 环境,会在 Linux 系列文章中说明。下载完所有软件之后,如下所示

【SpringBoot学习】44、SpringBoot 集成 Elasticsearch-7.6 实战

(1)安装 Elasticsearch

Elasticsearch 安装很简单,直接解压,找到 bin/elasticsearch.bat 双击启动就可以了

【SpringBoot学习】44、SpringBoot 集成 Elasticsearch-7.6 实战

日志中有这么一句话

[2022-07-27T10:31:20,865][INFO ][o.e.h.AbstractHttpServerTransport] [DESKTOP-ITMR1G0] publish_address {127.0.0.1:9200}, bound_addresses {127.0.0.1:9200}, {[::1]:9200}

也就是说发布的地址是:http://127.0.0.1:9200,浏览器直接访问这个地址即可,如下所示

【SpringBoot学习】44、SpringBoot 集成 Elasticsearch-7.6 实战

Elasticsearch 就安装完成啦

  • 如果电脑配置不是很高,可以修改一下 ES 使用的内存,默认是 1G,修改 elasticsearch/confi/jvm.options 文件
-Xms1g
-Xmx1g

(2)安装 Head

Github 地址是:https://github.com/mobz/elasticsearch-head,通过上面的地址直接下载了之后解压,有多种运行 elasticsearch-head 的方法。

下载依赖慢的,可以使用淘宝镜像地址,也就是 cnpm 下载,这里我就不做过多阐述

  • 使用内置服务器运行,访问地址:http://localhost:9100/
git clone git://github.com/mobz/elasticsearch-head.git
cd elasticsearch-head
npm install
npm run start
open http://localhost:9100/

这将启动一个在端口 9100 上运行的本地网络服务器,服务于 elasticsearch-head

【SpringBoot学习】44、SpringBoot 集成 Elasticsearch-7.6 实战点击上面的连接,发现连接不上,打开 F12 控制台,发现疯狂报错跨域【SpringBoot学习】44、SpringBoot 集成 Elasticsearch-7.6 实战找到 elasticsearch-7.6.1/config/elasticsearch.yml 配置文件,在末尾添加跨域支持,然后重启 Elasticsearch

# 支持跨域访问
http.cors.enabled: true
http.cors.allow-origin: "*"

再次连接,发现状态变成绿色,说明连接成功

【SpringBoot学习】44、SpringBoot 集成 Elasticsearch-7.6 实战

(3)安装 IK 分词器

Elasticsearch 安装插件的方式安装 IK 分词器,在 Elasticsearch 的目录下面有个叫 plugins 的,就是用来存放插件的目录,所以直接解压 IK 分词器复制过去即可

【SpringBoot学习】44、SpringBoot 集成 Elasticsearch-7.6 实战

重启 Elasticsearch 之后,观察一下日志,发现多了一个加载插件【SpringBoot学习】44、SpringBoot 集成 Elasticsearch-7.6 实战如果启动报错:Plugin [analysis-ik] was built for Elasticsearch version 8.2.3 but version7.6.1,只需要将 IK 插件的 plugin-descriptor.properties 配置文件的 ES 版本修改为安装版本即可

【SpringBoot学习】44、SpringBoot 集成 Elasticsearch-7.6 实战

(4)安装 Kibana

安装 Kibana 不需要技巧,解压找到 bin 目录下的 kibana.bat,双击启动即可,浏览器访问:http://localhost:5601/

【SpringBoot学习】44、SpringBoot 集成 Elasticsearch-7.6 实战
  • Kibana 设置中文,找到 kibana-7.6.1/config/kibana.yml 的,最后增加一个语言配置
i18n.locale: "zh-CN"

汉化效果如下所示

【SpringBoot学习】44、SpringBoot 集成 Elasticsearch-7.6 实战

启动完成之后,可以观察一下 Head 插件的变化,是不是多了 Kibana 的信息

【SpringBoot学习】44、SpringBoot 集成 Elasticsearch-7.6 实战

二、SpringBoot 搭建 ES 环境

1、SpringBoot 集成 ES

直接干货,SpringBoot 基础不好的同学,建议先学习一下 SpringBoot,下面文章内容的分享,直接是在熟练使用 SpringBoot 的前提下进行的

导入依赖到 SpringBoot,我这里使用的是 springboot 提供的

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>

顺着官方文档看一下,需要先注入一个 Bean,RestHighLevelClient 是用来执行请求命令的客户端

package cn.tellsea.config;

import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Bean;

/**
 * ES 配置
 *
 * @author Tellsea
 * @date 2022/7/28
 */

@Configurable
public class ElasticSearchConfig {

    @Bean
    public RestHighLevelClient restHighLevelClient() {
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost("localhost"9200"http")
                ));
        return client;
    }
}

到这里就集成完成了,SpringBoot 的自动装配,还是一样的轻松自如,导入依赖,加个配置就 OK 了

2、概念入门思想

集群,节点,索引,类型,文档,分片,映射

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

【SpringBoot学习】44、SpringBoot 集成 Elasticsearch-7.6 实战直接转换到 Navicat 里面,一张图更好理解

三、Elasticsearch 官方文档 API

Java 高级 REST 客户端支持以下文档 API:单文档 API、多文档 API

  • 官方文档 7.6 API:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.6/java-rest-high-supported-apis.html

假设我们的单元测试类,已经做了如下操作,注入可客户端 Bean(restHighLevelClient),创建了一个全局常量,也就是索引名称

@SpringBootTest
class SpringBootElasticsearchApplicationTests {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    /**
     * 索引
     */

    public final static String ES_INDEX = "test_index";

}

1、索引 API

(1)创建索引

    /**
     * 创建索引
     */

    @Test
    public void createIndex() throws IOException {
        CreateIndexRequest createIndexRequest = new CreateIndexRequest(ES_INDEX);
        CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
        if (createIndexResponse.equals(ES_INDEX)) {
            System.out.println("创建索引成功");
        } else {
            System.out.println("创建索引失败");
        }
    }

(2)索引是否存在

    /**
     * 索引是否存在
     */

    @Test
    public void existsIndex() throws IOException {
        GetIndexRequest getIndexRequest = new GetIndexRequest(ES_INDEX);
        boolean exists = restHighLevelClient.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
        if (exists) {
            System.out.println("存在");
        } else {
            System.out.println("不存在");
        }
    }

(3)获取索引

    /**
     * 获取索引
     */

    @Test
    public void getIndex() throws IOException {
        GetIndexRequest getIndexRequest = new GetIndexRequest(ES_INDEX);
        GetIndexResponse getIndexResponse = restHighLevelClient.indices().get(getIndexRequest, RequestOptions.DEFAULT);
        System.out.println(getIndexResponse.getAliases());
    }

(4)删除索引

    /**
     * 删除索引
     */

    @Test
    public void deleteIndex() throws IOException {
        DeleteIndexRequest deleteRequest = new DeleteIndexRequest(ES_INDEX);
        AcknowledgedResponse acknowledgedResponse = restHighLevelClient.indices().delete(deleteRequest, RequestOptions.DEFAULT);
        if (acknowledgedResponse.isAcknowledged()) {
            System.out.println("删除索引成功");
        } else {
            System.out.println("删除索引失败");
        }
    }

2、文档 API

(1)添加文档

    /**
     * 添加文档
     */

    @Test
    public void addDocument() throws IOException {
        User user = new User().setUserName("张三").setAge(24);
        IndexRequest indexRequest = new IndexRequest(ES_INDEX);
        indexRequest.source(JSON.toJSONString(user), XContentType.JSON);
        IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
        System.out.println(indexResponse.toString());
        if ("CREATED".equals(indexResponse.status())) {
            System.out.println("新增文档");
        } else if ("UPDATE".equals(indexResponse.status())) {
            System.out.println("更新文档");
        }
    }

(2)文档是否存在

    /**
     * 文档是否存在
     */

    @Test
    public void existsDocument() throws IOException {
        GetRequest getRequest = new GetRequest(ES_INDEX, "1");
        boolean exists = restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT);
        if (exists) {
            System.out.println("存在");
        } else {
            System.out.println("不存在");
        }
    }

(3)获取文档

    /**
     * 获取文档
     */

    @Test
    public void getDocument() throws IOException {
        GetRequest getRequest = new GetRequest(ES_INDEX, "1");
        GetResponse documentFields = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
        System.out.println(documentFields.getSourceAsString());
    }

(4)更新文档

    /**
     * 更新文档
     */

    @Test
    public void updateDocument() throws IOException {
        UpdateRequest updateRequest = new UpdateRequest(ES_INDEX, "1");
        updateRequest.timeout("1s");
        User user = new User().setUserName("李四").setAge(25);
        updateRequest.doc(JSON.toJSONString(user), XContentType.JSON);
        UpdateResponse updateResponse = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
        if (updateResponse.status().getStatus() == 200) {
            System.out.println("更新文档成功");
        } else {
            System.out.println("更新文档失败");
        }
    }

(4)删除文档

    /**
     * 删除文档
     */

    @Test
    public void deleteDocument() throws IOException {
        DeleteRequest deleteRequest = new DeleteRequest(ES_INDEX, "1");
        deleteRequest.timeout("1s");
        DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
        if (deleteResponse.status().getStatus() == 200) {
            System.out.println("删除文档成功");
        } else {
            System.out.println("删除文档失败");
        }
    }

3、批量 API

(1)批量导入数据

    /**
     * 批量导入数据
     */

    @Test
    public void bulkAdd() throws IOException {
        BulkRequest bulkRequest = new BulkRequest(ES_INDEX);
        bulkRequest.timeout("10s");
        List<User> userList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            userList.add(new User().setUserName("用户" + (i + 1)).setAge((i + 1) * 10));
        }
        for (int i = 0; i < userList.size(); i++) {
            bulkRequest.add(new IndexRequest(ES_INDEX)
                    .id(String.valueOf(i + 1))
                    .source(JSON.toJSONString(userList.get(i)), XContentType.JSON));
        }
        BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        if (bulkResponse.hasFailures()) {
            System.out.println("批量导入数据成功");
        } else {
            System.out.println("批量导入数据失败");
        }
    }

(2)查询数据

    /**
     * 查询数据
     */

    @Test
    public void search() throws IOException {
        SearchRequest searchRequest = new SearchRequest(ES_INDEX);

        // 精准查询
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("userName.keyword""Tellsea");
        searchSourceBuilder.query(termQueryBuilder);

        // 超时
        searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));

        // 分页
        searchSourceBuilder.from(1);
        searchSourceBuilder.size(10);

        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        // 解析结果
        List<User> userList = new ArrayList<>();
        for (SearchHit hit : searchResponse.getHits().getHits()) {
            userList.add(JSON.parseObject(hit.getSourceAsString(), User.class));
        }

        // 打印结果
        userList.forEach(item -> System.out.println(item));
    }

(3)查询数据-分页

    /**
     * 查询数据-分页
     */

    @Test
    public void searchPage() throws IOException {
        SearchRequest searchRequest = new SearchRequest(ES_INDEX);

        // 精准查询
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("userName.keyword""Tellsea");
        searchSourceBuilder.query(termQueryBuilder);

        // 超时
        searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));

        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        // 解析结果
        List<User> userList = new ArrayList<>();
        for (SearchHit hit : searchResponse.getHits().getHits()) {
            userList.add(JSON.parseObject(hit.getSourceAsString(), User.class));
        }

        // 打印结果
        userList.forEach(item -> System.out.println(item));
    }

(3)查询数据-高亮

    /**
     * 查询数据-高亮
     */

    @Test
    public void searchHighlight() throws IOException {
        SearchRequest searchRequest = new SearchRequest(ES_INDEX);

        // 精准查询
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("userName.keyword""Tellsea");
        searchSourceBuilder.query(termQueryBuilder);

        // 超时
        searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));

        // 分页
        searchSourceBuilder.from(1);
        searchSourceBuilder.size(10);

        // 高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("userName");
        highlightBuilder.preTags("<span style='color: red;'>");
        highlightBuilder.postTags("</span>");
        searchSourceBuilder.highlighter(highlightBuilder);

        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        // 解析结果
        List<User> userList = new ArrayList<>();
        for (SearchHit hit : searchResponse.getHits().getHits()) {
            // 如果没有高亮,直接解析JSON放到list即可
            // userList.add(JSON.parseObject(hit.getSourceAsString(), User.class));

            // 解析高亮
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            HighlightField userName = highlightFields.get("userName");
            // 原来的结果
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();
            if (userName != null) {
                Text[] fragments = userName.fragments();
                String n_userName = "";
                for (Text text : fragments) {
                    n_userName += text;
                }
                sourceAsMap.put("userName", n_userName);
            }
            userList.add(JSON.parseObject(JSON.toJSONString(sourceAsMap), User.class));
        }

        // 打印结果
        userList.forEach(item -> System.out.println(item));
    }

到此 ES 的基本操作,已经学习完了!后续有空会整理更多高级的操作


原文始发于微信公众号(花海里):【SpringBoot学习】44、SpringBoot 集成 Elasticsearch-7.6 实战

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/69553.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!