前言

最近写的一个个人项目(传送门:全终端云书签)中需要用到全文检索功能,目前 mysql,es 都可以做全文检索,mysql 胜在配置方便很快就能搞定上线(参考这里),不考虑上手难度,es 在全文检索方面是完胜 mysql 的。

最后决定使用 es。使用最新的 7.2 版本。java 客户端使用 es 官方的 high level client(官方文档),为什么用这个有以下几点原因:

  • jest 毕竟不是官方的,更新速度较慢
  • transportClient,速度太慢,连官方都嫌弃它了。在 7.x 中已经被弃用,8.x 中将完全删除
  • high level client 的官方文档写的很清楚明了,虽然目前相关的中文资料还很少,也能够上手用起来

本文主要内容如下:

  • docker 部署 es(支持 ik 中文分词)
  • 在 springboot 中进行增删改查

docker 部署 es(基于 linux)

es 的中文分词目前比较流行的分词插件为 ik(github 地址)。由于手写 docker 命令太繁杂,这里用 docker-compose 来管理。假定当前在/root 目录下

  1. 下载 ik release 到/root/es/ik 目录下,并解压到当前文件夹。

  2. 创建/root/es/data 目录,并将读写权限给所有用户.本目录用于存放 es 数据。由于 es 不能以 root 用户执行,所以对于此目录需要将读写权限给其他用户。

  3. 编写 es 配置文件,7.2 的配置文件变化还是较大的(之前用的是 2.x 版本),一个简单的配置如下:

    1. cluster.name: elasticsearch
    2. # 配置的集群名称,默认是 elasticsearch,es 服务会通过广播方式自动连接在同一网段下的 es 服务,通过多播方式进行通信,同一网段下可以有多个集群,通过集群名称这个属性来区分不同的集群。
    3. node.name: bookmark-world
    4. # 当前配置所在机器的节点名,你不设置就默认随机指定一个 name 列表中名字,该 name 列表在 es 的 jar 包中 config 文件夹里 name.txt 文件中,其中有很多作者添加的有趣名字。
    5. node.master: true
    6. # 指定该节点是否有资格被选举成为 node(注意这里只是设置成有资格, 不代表该 node 一定就是 master),默认是 true,es 是默认集群中的第一台机器为 master,如果这台机挂了就会重新选举 master。
    7. node.data: true
    8. # 指定该节点是否存储索引数据,默认为 true。
    9. bootstrap.memory_lock: false
    10. # 设置为 true 来锁住内存不进行 swapping。因为当 jvm 开始 swapping 时 es 的效率 会降低,所以要保证它不 swap,可以把 ES_MIN_MEM 和 ES_MAX_MEM 两个环境变量设置成同一个值,并且保证机器有足够的内存分配给 es。 同时也要允许 elasticsearch 的进程可以锁住内存,linux 下启动 es 之前可以通过`ulimit -l unlimited`命令设置。
    11. # 设置为 true,会导致报警告实际未锁定内存,进而退出进程(es在生产模式下有警告就会退出)
    12. network.bind_host: 0.0.0.0
    13. # 设置绑定的 ip 地址,可以是 ipv4 或 ipv6 的,默认为 0.0.0.0,绑定这台机器的任何一个 ip。
    14. # 集群配置
    15. discovery.seed_hosts:
    16. - bookmark-es
    17. cluster.initial_master_nodes:
    18. - bookmark-world
  4. 编写/root/docker-compose.yml

    1. version: "2"
    2. services:
    3. bookmark-es:
    4. image: docker.elastic.co/elasticsearch/elasticsearch:7.2.0
    5. container_name: bookmark-es
    6. volumes:
    7. - /etc/localtime:/etc/localtime
    8. - ./es/data:/usr/share/elasticsearch/data
    9. - ./es/ik:/usr/share/elasticsearch/plugins/ik
    10. - ./es/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
    11. ports:
    12. - 9200:9200
    13. - 9300:9300
  5. 执行 docker-compose up -d启动 es

详细可参考这里:云书签 docker 部署

springboot 整合

创建 springboot 项目

首先创建一个 springboot 项目,然后引入high level client的依赖,pom 文件如下:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <parent>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-parent</artifactId>
  8. <version>2.1.6.RELEASE</version>
  9. <relativePath/> <!-- lookup parent from repository -->
  10. </parent>
  11. <groupId>com.fanxb</groupId>
  12. <artifactId>es-demo</artifactId>
  13. <version>0.0.1-SNAPSHOT</version>
  14. <name>es-demo</name>
  15. <description>Elasticsearch Demo project for Spring Boot</description>
  16. <properties>
  17. <java.version>1.8</java.version>
  18. </properties>
  19. <!--注意:如果使用了parent那么需要在此定义es版本号,因为spring-boot-start-parent中已经定义了es相关依赖的版本号
  20. ,high-level-client中的部分依赖会被覆盖成低版本的,导出出现莫名其妙的错误-->
  21. <dependencyManagement>
  22. <dependencies>
  23. <dependency>
  24. <groupId>org.elasticsearch.client</groupId>
  25. <artifactId>elasticsearch-rest-high-level-client</artifactId>
  26. <version>7.2.0</version>
  27. </dependency>
  28. <!-- https://mvnrepository.com/artifact/org.elasticsearch/elasticsearch -->
  29. <dependency>
  30. <groupId>org.elasticsearch</groupId>
  31. <artifactId>elasticsearch</artifactId>
  32. <version>7.2.0</version>
  33. </dependency>
  34. <!--&lt;!&ndash; https://mvnrepository.com/artifact/org.elasticsearch.client/elasticsearch-rest-client &ndash;&gt;-->
  35. <dependency>
  36. <groupId>org.elasticsearch.client</groupId>
  37. <artifactId>elasticsearch-rest-client</artifactId>
  38. <version>7.2.0</version>
  39. </dependency>
  40. </dependencies>
  41. </dependencyManagement>
  42. <dependencies>
  43. <dependency>
  44. <groupId>org.springframework.boot</groupId>
  45. <artifactId>spring-boot-starter-web</artifactId>
  46. </dependency>
  47. <dependency>
  48. <groupId>org.elasticsearch.client</groupId>
  49. <artifactId>elasticsearch-rest-high-level-client</artifactId>
  50. <version>7.2.0</version>
  51. </dependency>
  52. <dependency>
  53. <groupId>com.alibaba</groupId>
  54. <artifactId>fastjson</artifactId>
  55. <version>1.2.56</version>
  56. </dependency>
  57. <dependency>
  58. <groupId>org.springframework.boot</groupId>
  59. <artifactId>spring-boot-starter-test</artifactId>
  60. <scope>test</scope>
  61. </dependency>
  62. </dependencies>
  63. <build>
  64. <plugins>
  65. <plugin>
  66. <groupId>org.springframework.boot</groupId>
  67. <artifactId>spring-boot-maven-plugin</artifactId>
  68. </plugin>
  69. </plugins>
  70. </build>
  71. </project>

注意:这里有一个依赖的大坑,要注意!

如果定义了<parent>,就必须在<dependencyManagement>中指定部分依赖的版本,否则会因为依赖版本不对出现各种莫名其妙的错误,上面注释中已经指出。

创建 util/EsUtil.java 工具类

主要功能函数如下:

预创建 index

虽然 es 在插入数据时会自动根据字段类型来创建字段定义,但是自动创建并不总是和需要相符的,比如想让某个字段不分词,或者使用其他的分词器。所以在代码中先判断 index(es7 中已经废弃了 mapping,也就是一个 index 相当于一个表)是否存在,如果不存在就创建 index.

主要代码如下:

  1. //被@PostConstruct注释的方法将会在对应类注入到Spring后调用,确保index的生成
  2. @PostConstruct
  3. public void init() {
  4. try {
  5. if (client != null) {
  6. client.close();
  7. }
  8. client = new RestHighLevelClient(RestClient.builder(new HttpHost(host, port, scheme)));
  9. if (this.indexExist(INDEX_NAME)) {
  10. return;
  11. }
  12. CreateIndexRequest request = new CreateIndexRequest(INDEX_NAME);
  13. request.settings(Settings.builder().put("index.number_of_shards", 3).put("index.number_of_replicas", 2));
  14. request.mapping(CREATE_INDEX, XContentType.JSON);
  15. CreateIndexResponse res = client.indices().create(request, RequestOptions.DEFAULT);
  16. if (!res.isAcknowledged()) {
  17. throw new RuntimeException("初始化失败");
  18. }
  19. } catch (Exception e) {
  20. e.printStackTrace();
  21. System.exit(0);
  22. }
  23. }

插入或者更新一个对象

通过指定 id,如果此 id 存在那么就是更新,否则是插入。

  1. public void insertOrUpdateOne(String index, EsEntity entity) {
  2. IndexRequest request = new IndexRequest(index);
  3. request.id(entity.getId());
  4. request.source(JSON.toJSONString(entity.getData()), XContentType.JSON);
  5. try {
  6. client.index(request, RequestOptions.DEFAULT);
  7. } catch (Exception e) {
  8. throw new RuntimeException(e);
  9. }
  10. }

批量插入

high level client 提供了方便的批量操作接口,如下所示:

  1. public void insertBatch(String index, List<EsEntity> list) {
  2. BulkRequest request = new BulkRequest();
  3. list.forEach(item -> request.add(new IndexRequest(index).id(item.getId())
  4. .source(JSON.toJSONString(item.getData()), XContentType.JSON)));
  5. try {
  6. client.bulk(request, RequestOptions.DEFAULT);
  7. } catch (Exception e) {
  8. throw new RuntimeException(e);
  9. }
  10. }

批量删除

和上面一样同样用到了BulkRequest

  1. public <T> void deleteBatch(String index, Collection<T> idList) {
  2. BulkRequest request = new BulkRequest();
  3. idList.forEach(item -> request.add(new DeleteRequest(index, item.toString())));
  4. try {
  5. client.bulk(request, RequestOptions.DEFAULT);
  6. } catch (Exception e) {
  7. throw new RuntimeException(e);
  8. }
  9. }

搜索

通过构建SearchSourceBuilder查询参数

  1. public <T> List<T> search(String index, SearchSourceBuilder builder, Class<T> c) {
  2. SearchRequest request = new SearchRequest(index);
  3. request.source(builder);
  4. try {
  5. SearchResponse response = client.search(request, RequestOptions.DEFAULT);
  6. SearchHit[] hits = response.getHits().getHits();
  7. List<T> res = new ArrayList<>(hits.length);
  8. for (SearchHit hit : hits) {
  9. res.add(JSON.parseObject(hit.getSourceAsString(), c));
  10. }
  11. return res;
  12. } catch (Exception e) {
  13. throw new RuntimeException(e);
  14. }
  15. }

delete by query

es 插入数据容易,删除就比较麻烦了,特别是根据条件删除。

  1. public void deleteByQuery(String index, QueryBuilder builder) {
  2. DeleteByQueryRequest request = new DeleteByQueryRequest(index);
  3. request.setQuery(builder);
  4. //设置批量操作数量,最大为10000
  5. request.setBatchSize(10000);
  6. request.setConflicts("proceed");
  7. try {
  8. client.deleteByQuery(request, RequestOptions.DEFAULT);
  9. } catch (Exception e) {
  10. throw new RuntimeException(e);
  11. }
  12. }

结束

可通过测试类com.fanxb.esdemo.service.BookServiceTest查看运行结果。

源码地址:github

本文原创发布于:https://www.tapme.top/blog/detail/2019-07-29-14-59

springboot整合elasticsearch(基于es7.2和官方high level client)的更多相关文章

  1. SpringBoot整合ElasticSearch实现多版本的兼容

    前言 在上一篇学习SpringBoot中,整合了Mybatis.Druid和PageHelper并实现了多数据源的操作.本篇主要是介绍和使用目前最火的搜索引擎ElastiSearch,并和Spring ...

  2. ElasticSearch(2)---SpringBoot整合ElasticSearch

    SpringBoot整合ElasticSearch 一.基于spring-boot-starter-data-elasticsearch整合 开发环境:springboot版本:2.0.1,elast ...

  3. springboot整合elasticsearch入门例子

    springboot整合elasticsearch入门例子 https://blog.csdn.net/tianyaleixiaowu/article/details/72833940 Elastic ...

  4. Springboot整合elasticsearch以及接口开发

    Springboot整合elasticsearch以及接口开发 搭建elasticsearch集群 搭建过程略(我这里用的是elasticsearch5.5.2版本) 写入测试数据 新建索引book( ...

  5. SpringBoot整合Elasticsearch详细步骤以及代码示例(附源码)

    准备工作 环境准备 JAVA版本 java version "1.8.0_121" Java(TM) SE Runtime Environment (build 1.8.0_121 ...

  6. Springboot整合Elasticsearch报错availableProcessors is already set to [4], rejecting [4]

    Springboot整合Elasticsearch报错 今天使用SpringBoot整合Elasticsearch时候,相关的配置完成后,启动项目就报错了. nested exception is j ...

  7. Springboot整合ElasticSearch进行简单的测试及用Kibana进行查看

    一.前言 搜索引擎还是在电商项目.百度.还有技术博客中广泛应用,使用最多的还是ElasticSearch,Solr在大数据量下检索性能不如ElasticSearch.今天和大家一起搭建一下,小编是看完 ...

  8. 😊SpringBoot 整合 Elasticsearch (超详细).md

    SpringBoot 整合 Elasticsearch (超详细) 注意: 1.环境搭建 安装es Elasticsearch 6.4.3 下载链接 为了方便,环境使用Windows 配置 解压后配置 ...

  9. SpringBoot整合elasticsearch

    在这一篇文章开始之前,你需要先安装一个ElasticSearch,如果你是mac或者linux可以参考https://www.jianshu.com/p/e47b451375ea,如果是windows ...

随机推荐

  1. 简单介绍几种Java后台开发常用框架组合

    01 前言 Java框架一直以来都是面试必备的知识点,而掌握Java框架,不管在成熟的大公司,快速发展的公司,还是创业阶段的公司,都能对当前正在开发中的系统有整体的认知,从而更好的熟悉和学习技术,这篇 ...

  2. 【React】react学习笔记02-面向组件编程

    react学习笔记02-面向组件编程 面向组件编程,直白来说,就是定义组件,使用组件. 以下内容则简单介绍下组建的声明与使用,直接复制demo观测结果即可. 步骤: 1.定义组件   a.轻量组件-函 ...

  3. zphp源码分析(一)

    zphp是一款轻量级的php服务端框架,是swoole官方开发的.可以用来开发web应用和网络服务. 安装: 可以通过composer安装, { "require": { &quo ...

  4. Cisco packet tracer下dhcp的配置的vlan的应用

    话不多说,先上拓扑图. pc0和pc1分别接在三层交换机的F0/1.F0/2接口,ser接在F0/24接口,用ser用作dhcp的服务器. 0x01:配置server0 先配置server的IP地址. ...

  5. Web自动化测试 一

    Web自动化测试 一.为什么要进行web自动化测试 接口测试只能测试后端返回的数据,定位的是后端开发工程师的问题.如果前段出现了问题,我们要使用web测试去发现错误. 具体定位的问题有: 显示的数据: ...

  6. RQNOJ193 造路行动

    题目转移 详见最小生成树讲解 Kruskal #include<cstdio> #include<algorithm> using namespace std; ; int n ...

  7. 设计模式-外观模式(Facade)

    外观模式又称为门面模式,为一组类似功能的集群,比如类库.子系统等,提供一致的入口供client调用 角色和职责: 1.门面(Facade)-Computer: 外观模式的核心.它被客户角色调用,它熟悉 ...

  8. HDU 3065:病毒侵袭持续中(AC自动机)

    http://acm.hdu.edu.cn/showproblem.php?pid=3065 题意:中文题意. 思路:直接插入然后用一个数组记录id和cnt,因为n只有1000,可以开一个数组判断第几 ...

  9. vim与系统剪切板之间的复制粘贴

    背景 vim各种快捷建溜得飞起,然而与系统剪切板之间的复制粘贴一直都是我的痛. 每次需要从vim中拷贝些文字去浏览器搜索,都需要用鼠标选中vim的文字后,Ctrl+c.Ctrl+v,硬生生掐断了纯键盘 ...

  10. 计算机组成原理第五章(中央处理器CPU)

    ---恢复内容开始--- 指令周期(取指令.分析指令到执行完该指令所需的全部时间) 机器周期通常又称CPU周期 通常把一条指令周期分成若干个机器周期,每个机器周期完成一个基本操作 以主存的工作周期(存 ...