Elasticsearch-06 Spring Boot 2.0.9整合ElasticSearch5.6.16

简介: Elasticsearch-06 Spring Boot 2.0.9整合ElasticSearch5.6.16

20190806092132811.jpg


概述


前面几篇,学习了ES的基本操作,那我们这里集成到代码中吧。 我们这里没有使用Spring 提供的 spring-boot-starter-data-elasticsearch,使用的是ES原生的API 。


官方JAVA API文档


当前7.0


https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/index.html


5.6


https://www.elastic.co/guide/en/elasticsearch/client/java-api/5.6/index.html


工程

20190421025047810.png

ES服务端的版本 5.6.16 ,工程里es客户端的版本最好和服务端保持一致 。 正好Spring Boot 2.0.9RELEASE版本搭配transport里es是5.6.16版本。


pom.xml

<?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 http://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.0.9.RELEASE</version>
    <relativePath /> <!-- lookup parent from repository -->
  </parent>
  <groupId>masterSpringMvc</groupId>
  <artifactId>springBootElasticSearch</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>springBootElasticSearch</name>
  <description>masterSpringMvc project for Spring Boot</description>
  <properties>
    <java.version>1.8</java.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.elasticsearch.client</groupId>
      <artifactId>transport</artifactId>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
</project>

20190421103432489.png

es配置文件

# Elasticsearch
elasticsearch.ip=127.0.0.1
#9200端口是RESTFul API来访问ElasticSearch的端口,9300端口是es节点通讯的默认端口,给java程序用的配置9300
elasticsearch.port=9300
elasticsearch.pool=5
# 集群的名字,和elasticsearch.yml中的cluster.name保持一致
elasticsearch.cluster.name=artisan


Es配置类

package com.artisan.config;
import java.net.InetAddress;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ESConfig {
  private static final Logger logger = LoggerFactory.getLogger(ESConfig.class);
  @Value("${elasticsearch.ip}")
  private String hostName;
  @Value("${elasticsearch.port}")
  private String port;
  @Value("${elasticsearch.cluster.name}")
  private String clusterName;
  @Value("${elasticsearch.pool}")
  private String poolSize;
  @Bean
  public TransportClient transportClient()  {
    logger.info("Elasticsearch begin to init ");
    TransportClient transportClient = null;
    try {
      // 地址信息
      InetSocketTransportAddress transportAddress = new InetSocketTransportAddress(
          InetAddress.getByName(hostName), Integer.valueOf(port));
      // 配置信息
      Settings esSetting = Settings.builder().put("cluster.name", clusterName) // 集群名字
          .put("client.transport.sniff", true)// 增加嗅探机制,找到ES集群
          .put("thread_pool.search.size", Integer.parseInt(poolSize))// 线程池个数
          .build();
      // 配置信息Settings自定义
      transportClient = new PreBuiltTransportClient(esSetting);
      transportClient.addTransportAddresses(transportAddress);
    } catch (Exception e) {
      logger.error("TransportClient create error", e);
    }
    return transportClient;
  }
}


控制层

简单起见,我们直接在Controller层操作ES吧,仅仅是为了测试下功能。

简单查询

先写个简单的根据id获取数据的方法来测试下班


package com.artisan.controller;
import java.util.Map;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ESController {
  @Autowired
  private TransportClient client;
  @GetMapping("/book/novel/{id}")
  public ResponseEntity<Map<String, Object>> getByIdFromES(@PathVariable String id){
    GetResponse response = this.client.prepareGet("book", "novel", id).get();
    if (!response.isExists()) {
      return new ResponseEntity<>(HttpStatus.NOT_FOUND);
    }
    return new ResponseEntity<Map<String, Object>>(response.getSource(),HttpStatus.OK);
  }
}

启动下服务,在浏览器或者postman中访问下吧


20190421104052922.png

我们通过head插件来看下id=11的数据

20190421104229293.png


OK,可以访问到正确的数据。


新增数据

ESController新增add方法

@PostMapping("/book/novel/add")
  public ResponseEntity<String> add(NovelDTO novel) {
    try {
      XContentBuilder builder = XContentFactory.jsonBuilder()
          .startObject()
          .field("title", novel.getTitle())
          .field("author", novel.getAuthor())
          .field("word_count", novel.getWordCount())
          .field("public_date", novel.getPublishDate().getTime())
          .endObject();
      IndexResponse response = this.client.prepareIndex("book", "novel").setSource(builder).get();
      return new ResponseEntity<String>(response.getId(), HttpStatus.OK);
    } catch (IOException e) {
      e.printStackTrace();
      return new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

我们把数据请求参数封装到了NovelDTO 中

package com.artisan.dto;
import java.util.Date;
import org.springframework.format.annotation.DateTimeFormat;
public class NovelDTO {
  private String title;
  private String author;
  private String wordCount;
  @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
  private Date publishDate;
  // set/get方法 省略
}


启动服务,POST http://localhost:8080/book/novel/add



20190421121148434.png

head插件中查看数据 访问 http://localhost:9100/


20190421121444443.png


新增成功



如果要想用JSON传的话,需要在方法入参前加入 @RequestBody ,postman中更改如下

2019042112131939.png

public ResponseEntity<String> add(@RequestBody  NovelDTO novel) {
}

删除数据

@DeleteMapping("/book/novel/del")
  public ResponseEntity<String> delete(String id ){
    DeleteResponse response = this.client.prepareDelete("book", "novel", id).get();
    return new ResponseEntity<String>(response.getResult().toString(),HttpStatus.OK);
  }


把刚才新增的数据删掉


20190421122346789.png


通过head插件查看已经没有该记录了,删除OK


更新数据

举个例子,根据id更新title

/**
   * 根据id 修改title
   * @param id
   * @param title
   * @return
   */
  @PutMapping("/book/novel/update")
  public ResponseEntity<String> update(@RequestParam(name="id")String id ,
      @RequestParam(name="title") String title){
    UpdateRequest updateRequest = new UpdateRequest("book", "novel", id);
    try {
      XContentBuilder builder = XContentFactory.jsonBuilder()
          .startObject()
          .field("title",title)
          .endObject();
      updateRequest.doc(builder);
      UpdateResponse response = this.client.update(updateRequest).get();
      return new ResponseEntity<String>(response.getResult().toString(), HttpStatus.OK);
    } catch (Exception e) {
      e.printStackTrace();
      return new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR);
    } 
  }

20190421123720899.png


head插件查看

20190421123826525.png


复合查询

  /**
   * 综合查询
   * @param title
   * @param author
   * @param gtWordCount
   * @param ltWordCount
   * @return
   */
  @PostMapping("/book/novel/query")
  public ResponseEntity<List<Map<String, Object>>> query(
      @RequestParam(name="title",required=false)String title , 
      @RequestParam(name="author",required=false)String author ,
      @RequestParam(name="gtWordCount",defaultValue="0") Integer gtWordCount ,
      @RequestParam(name="ltWordCount",required=false) Integer ltWordCount  ) {
    BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
    if (title !=null) {
      boolQueryBuilder.must(QueryBuilders.matchQuery("title", title));
    }
    if (author !=null) {
      boolQueryBuilder.must(QueryBuilders.matchQuery("author", author));
    }
    RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("word_count")
        .from(gtWordCount);
    if (ltWordCount != null && ltWordCount > 0) {
      rangeQueryBuilder.to(ltWordCount);
    }
    // 关联
    boolQueryBuilder.filter(rangeQueryBuilder);
    SearchRequestBuilder builder = this.client.prepareSearch("book")
      .setTypes("novel")
      .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
      .setQuery(boolQueryBuilder)
      .setFrom(0)
      .setSize(10);
    System.out.println("请求JSON数据:\n" + builder);
    SearchResponse response = builder.get();
    List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
    for(SearchHit searchHit : response.getHits()) {
      list.add(searchHit.getSource());
    }
    return new ResponseEntity<List<Map<String, Object>>>(list, HttpStatus.OK);
  }


看下控制台输出的

请求JSON数据:

{
  "from" : 0,
  "size" : 10,
  "query" : {
    "bool" : {
      "must" : [
        {
          "match" : {
            "title" : {
              "query" : "Elasticsearch",
              "operator" : "OR",
              "prefix_length" : 0,
              "max_expansions" : 50,
              "fuzzy_transpositions" : true,
              "lenient" : false,
              "zero_terms_query" : "NONE",
              "boost" : 1.0
            }
          }
        }
      ],
      "filter" : [
        {
          "range" : {
            "word_count" : {
              "from" : 500,
              "to" : null,
              "include_lower" : true,
              "include_upper" : true,
              "boost" : 1.0
            }
          }
        }
      ],
      "disable_coord" : false,
      "adjust_pure_negative" : true,
      "boost" : 1.0
    }
  }
}


使用postman测试下 ,返回了3条数据,符合预期。


20190421130525681.png


其他


上面通过代码实现了数据的CRUD操作,那么我们把多索引和type的操作也尝试写下吧

工具类

package com.artisan.utils;
import javax.annotation.PostConstruct;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequest;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class ESUtil {
  private static final Logger logger = LoggerFactory.getLogger(ESUtil.class);
  @Autowired
    private TransportClient transportClient;
    private static TransportClient client;
    @PostConstruct
    public void init() {
        client = this.transportClient;
    }
  /**
   * 创建索引
   *
   * @param index
   * @return
   */
  public static boolean createIndex(String index) {
    if (!isIndexExist(index)) {
      logger.info("Index is not exits!");
      CreateIndexResponse indexresponse = client.admin().indices().prepareCreate(index).execute().actionGet();
      logger.info("执行建立成功?" + indexresponse.isAcknowledged());
      return indexresponse.isAcknowledged();
    }
    return false;
  }
  /**
   * 删除索引
   *
   * @param index
   * @return
   */
  public static boolean deleteIndex(String index) {
    if (!isIndexExist(index)) {
      logger.info("Index is not exits!");
    }
    DeleteIndexResponse dResponse = client.admin().indices().prepareDelete(index).execute().actionGet();
    if (dResponse.isAcknowledged()) {
      logger.info("delete index " + index + "  successfully!");
    } else {
      logger.info("Fail to delete index " + index);
    }
    return dResponse.isAcknowledged();
  }
  /**
   * 判断索引是否存在
   *
   * @param index
   * @return
   */
  public static boolean isIndexExist(String index) {
    IndicesExistsResponse inExistsResponse = client.admin().indices().exists(new IndicesExistsRequest(index))
        .actionGet();
    if (inExistsResponse.isExists()) {
      logger.info("Index [" + index + "] is exist!");
    } else {
      logger.info("Index [" + index + "] is not exist!");
    }
    return inExistsResponse.isExists();
  }
  /**
   * 判断index下指定type是否存在
   * 
   * @param index
   * @param type
   * @return
   */
  public static boolean isTypeExist(String index, String type) {
    return isIndexExist(index)
        ? client.admin().indices().prepareTypesExists(index).setTypes(type).execute().actionGet().isExists()
        : false;
  }
}


新建索引

@SuppressWarnings({ "rawtypes", "unchecked" })
  @PostMapping("/index/create")
  public ResponseEntity create(String index){
    if (ESUtil.createIndex(index)) {
      return new ResponseEntity(Boolean.TRUE,HttpStatus.OK);
    }else {
      return new ResponseEntity(HttpStatus.FOUND);
    }
  }


测试


20190421133347554.png


head查看下


20190421133408413.png


删除索引

  @SuppressWarnings({ "rawtypes", "unchecked" })
  @PostMapping("/index/delete")
  public ResponseEntity deleteIndex(String index){
    if (ESUtil.deleteIndex(index)) {
      return new ResponseEntity(Boolean.TRUE,HttpStatus.OK);
    }else {
      return new ResponseEntity(HttpStatus.NOT_FOUND);
    }
  }


测试下


20190421133425642.png

head查看,已经删除成功


20190421133442200.png

判断index中某个type是否存在

  @SuppressWarnings({ "rawtypes", "unchecked" })
  @PostMapping("/index/isTypeExist")
  public ResponseEntity isTypeExist(String index,String type){
    if (ESUtil.isTypeExist(index,type)) {
      return new ResponseEntity(Boolean.TRUE,HttpStatus.OK);
    }else {
      return new ResponseEntity(HttpStatus.NOT_FOUND);
    }
  }


测试一下


20190421133230663.png

20190421133259802.png

spring-data-elasticsearch 操作ES

https://docs.spring.io/spring-data/

20190421134138985.png


我们也可以用Spring给我们提供的封装好的 ElasticsearchTemplate 更方便的操作ES,这里我就不演示了,和data jpa操作很像,比较简单。


https://spring.io/projects/spring-data-elasticsearch


https://github.com/spring-projects/spring-data-elasticsearch


20190421134803229.png


如果也是使用spring boot集成的话,就用 spring-boot-starter-data-elasticsearch 这个maven的依赖,带有starter的这种。


代码

Github: https://github.com/yangshangwei/springBootElasticSearch

相关实践学习
以电商场景为例搭建AI语义搜索应用
本实验旨在通过阿里云Elasticsearch结合阿里云搜索开发工作台AI模型服务,构建一个高效、精准的语义搜索系统,模拟电商场景,深入理解AI搜索技术原理并掌握其实现过程。
ElasticSearch 最新快速入门教程
本课程由千锋教育提供。全文搜索的需求非常大。而开源的解决办法Elasricsearch(Elastic)就是一个非常好的工具。目前是全文搜索引擎的首选。本系列教程由浅入深讲解了在CentOS7系统下如何搭建ElasticSearch,如何使用Kibana实现各种方式的搜索并详细分析了搜索的原理,最后讲解了在Java应用中如何集成ElasticSearch并实现搜索。 &nbsp;
相关文章
存储 JSON Java
564 0
|
JSON Java API
springboot集成ElasticSearch使用completion实现补全功能
springboot集成ElasticSearch使用completion实现补全功能
241 1
|
Web App开发 JavaScript Java
elasticsearch学习五:springboot整合 rest 操作elasticsearch的 实际案例操作,编写搜索的前后端,爬取京东数据到elasticsearch中。
这篇文章是关于如何使用Spring Boot整合Elasticsearch,并通过REST客户端操作Elasticsearch,实现一个简单的搜索前后端,以及如何爬取京东数据到Elasticsearch的案例教程。
879 0
elasticsearch学习五:springboot整合 rest 操作elasticsearch的 实际案例操作,编写搜索的前后端,爬取京东数据到elasticsearch中。
|
JSON Java 网络架构
elasticsearch学习四:使用springboot整合 rest 进行搭建elasticsearch服务
这篇文章介绍了如何使用Spring Boot整合REST方式来搭建和操作Elasticsearch服务。
397 4
elasticsearch学习四:使用springboot整合 rest 进行搭建elasticsearch服务
|
7月前
|
JSON 安全 数据可视化
Elasticsearch(es)在Windows系统上的安装与部署(含Kibana)
Kibana 是 Elastic Stack(原 ELK Stack)中的核心数据可视化工具,主要与 Elasticsearch 配合使用,提供强大的数据探索、分析和展示功能。elasticsearch安装在windows上一般是zip文件,解压到对应目录。文件,elasticsearch8.x以上版本是自动开启安全认证的。kibana安装在windows上一般是zip文件,解压到对应目录。elasticsearch的默认端口是9200,访问。默认用户是elastic,密码需要重置。
3887 0
|
8月前
|
安全 Java Linux
Linux安装Elasticsearch详细教程
Linux安装Elasticsearch详细教程
1562 64
|
存储 安全 数据管理
如何在 Rocky Linux 8 上安装和配置 Elasticsearch
本文详细介绍了在 Rocky Linux 8 上安装和配置 Elasticsearch 的步骤,包括添加仓库、安装 Elasticsearch、配置文件修改、设置内存和文件描述符、启动和验证 Elasticsearch,以及常见问题的解决方法。通过这些步骤,你可以快速搭建起这个强大的分布式搜索和分析引擎。
485 5
|
存储 JSON Java
elasticsearch学习一:了解 ES,版本之间的对应。安装elasticsearch,kibana,head插件、elasticsearch-ik分词器。
这篇文章是关于Elasticsearch的学习指南,包括了解Elasticsearch、版本对应、安装运行Elasticsearch和Kibana、安装head插件和elasticsearch-ik分词器的步骤。
1256 0
elasticsearch学习一:了解 ES,版本之间的对应。安装elasticsearch,kibana,head插件、elasticsearch-ik分词器。
|
NoSQL 关系型数据库 Redis
mall在linux环境下的部署(基于Docker容器),Docker安装mysql、redis、nginx、rabbitmq、elasticsearch、logstash、kibana、mongo
mall在linux环境下的部署(基于Docker容器),docker安装mysql、redis、nginx、rabbitmq、elasticsearch、logstash、kibana、mongodb、minio详细教程,拉取镜像、运行容器
mall在linux环境下的部署(基于Docker容器),Docker安装mysql、redis、nginx、rabbitmq、elasticsearch、logstash、kibana、mongo
|
JSON 自然语言处理 数据库
Elasticsearch从入门到项目部署 安装 分词器 索引库操作
这篇文章详细介绍了Elasticsearch的基本概念、倒排索引原理、安装部署、IK分词器的使用,以及如何在Elasticsearch中进行索引库的CRUD操作,旨在帮助读者从入门到项目部署全面掌握Elasticsearch的使用。

热门文章

最新文章