#1、Elasticsearch简介

我们的应用经常需要添加检索功能,更或者是大量日志检索分析等,Spring Boot通过整合Spring Data ElasticSearch为我们提供了非常便捷的检索功能支持;
Elasticsearch是一个分布式搜索服务,提供Restful API,底层基于Lucene,采用多shard的方式保证数据安全,并且提供自动resharding的功能,github等大型的站点也是采用了Elasticsearch作为其搜索服务;

1.1 相关的概念

以员工文档的形式存储为例:一个文档代表一个员工数据。存储数据到Elasticsearch 的行为叫做索引,但在索引一个文档之前,需要确定将文档存储在哪里。

  • 一个Elasticsearch 集群可以包含多个索引,相应的每个索引可以包含多个类型。这些不同的类型存储着多个文档,每个文档又有多个属性
  • 类似MySQL的关系:
    索引—数据库
    类型—表
    文档—表中的记录
    属性—列

spring data 查询es spring search_spring

参考官方指南:https://www.elastic.co/guide/cn/elasticsearch/guide/current/index.html

2、安装Elasticsearch

Spring Data ElasticsearchSpr

Elasticsearch

3.2.x

6.7.2

3.1.x

6.2.2

3.0.x

5.5.0

2.1.x

2.4.0

2.0.x

2.2.0

1.3.x

1.5.2

而我们使用的是2.2.6的SpringBoot版本,它对应的Spring Data Elasticsearch的版本是3.2.6,所以Elasticsearch要按照6.7.2及以上的,而我们导入的es的jar包是6.8.7 ,所以我们就拉取6.8.7的镜像

使用docker来安装Elasticsearch:

  • docker search elasticsearch:搜索镜像
  • docker pull elasticsearch:6.8.7:拉取镜像

ElasticSearch默认启动会占用两个G的内存,所以启动的时候,需要使用 -e ES_JAVA_OPTS="-Xms256m -Xmx256m" 来限制占用的内存大小;

  • docker run -e ES_JAVA_OPTS="-Xms256m -Xmx256m" -d -p 9200:9200 -p 9300:9300 --name ES01 5acf0e8da90b:运行镜像(9200是浏览器访问端口,9300是Java访问端口)

浏览器访问:http://10.254.14.56:9200/ ,能看到下面的信息就说明成功了:

name	"ckaUxfg"
cluster_name	"docker-cluster"
cluster_uuid	"5Rj6tcpTTDqQFYPNTtJqAg"
version	
	number	"6.8.7"
	build_flavor	"default"
	build_type	"docker"
	build_hash	"c63e621"
	build_date	"2020-02-26T14:38:01.193138Z"
	build_snapshot	false
	lucene_version	"7.7.2"
	minimum_wire_compatibility_version	"5.6.0"
	minimum_index_compatibility_version	"5.0.0"
tagline	"You Know, for Search"

如果访问不成功,docker ps -a 可以看到启动就退出了,就可以尝试下面的操作:

  • 修改配置文件:vi /etc/sysctl.conf
  • 添加下面配置:vm.max_map_count=655360
  • 并执行命令:sysctl -p

然后要docker rm 容器id,先删除容器,再执行docker run重新启动,浏览器访问:http://10.254.14.56:9200/

3、SpringBoot整合Elasticsearch

使用SpringBoot的向导创建项目,选中web模块和Spring Data Elasticsearch模块:

Spring Data Elasticsearch和elasticsearch的版本对应关系:

Spring Data Elasticsearch

Elasticsearch

3.2.x

6.7.2

3.1.x

6.2.2

3.0.x

5.5.0

2.1.x

2.4.0

2.0.x

2.2.0

1.3.x

1.5.2

如果版本不对应,执行的时候会报错:NoNodeAvailableException[None of the configured nodes are available

3.1 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.2.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.springboot.es</groupId>
    <artifactId>springboot-03-es</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-03-es</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-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

##3.2 application.properties

配置:Client 节点信息clusterNodes;clusterName

spring.data.elasticsearch.cluster-name=docker-cluster
spring.data.elasticsearch.cluster-nodes=192.168.0.103:9300

注意:spring.data.elasticsearch.cluster-name=docker-cluster 对应的是我们浏览器访问 http://10.254.14.56:9200/ 的cluster_name,默认是elasticsearch,这个好像根据版本不同有差别,要注意。

3.3 定义book类

package com.springboot.es.bean;

import org.springframework.data.elasticsearch.annotations.Document;

import java.util.Date;

/**
 * @Document:表明这是一个Elasticsearch的一个文档类
 * indexName指定索引名称
 * type:指定类型名称
 */
@Document(indexName = "zxh",type = "book")
public class Book {
    private Integer id;
    private String name;
    private boolean isSuccess;
    private Date publishDate;

    public Book() {//无参构造不能省
    }

    public Book(Integer id, String name, boolean isSuccess, Date publishDate) {
        this.id = id;
        this.name = name;
        this.isSuccess = isSuccess;
        this.publishDate = publishDate;
    }

    @Override
    public String toString() {
        return "Book{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", isSuccess=" + isSuccess +
                ", publishDate=" + publishDate +
                '}';
    }
	//get/set方法
}
  • @Document:表明这是一个Elasticsearch的一个文档类:indexName指定索引名称,type:指定类型名称

##3.4 测试

3.4.1 方式一:继承ElasticsearchRepository接口

定义个接口:

  • 类似JPA的开发方式,编写一个继承 ElasticsearchRepository 的子接口,其他地方就能注入它
  • 并且拥有了分页以及增删改查功能了,同时也支持像JPA那样的自定义方法,但是不用写任何的实现
  • ElasticsearchRepository 的第一个泛型是 JavaBean的类型,第二个泛型是主键类型
package com.springboot.es.repository;

import com.springboot.es.bean.Book;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

/**
 * 类似JPA的开发方式,编写一个继承 ElasticsearchRepository 的子接口,其他地方就能注入它
 * 并且拥有了分页以及增删改查功能了,同时也支持像JPA那样的自定义方法,但是不用写任何的实现
 * ElasticsearchRepository 的第一个泛型是 JavaBean的类型,第二个泛型是主键类型
 */
public interface BookElasticsearch extends ElasticsearchRepository<Book,Integer> {

    Book findBookByNameLike(String name);
}

使用:

import com.springboot.es.bean.Book;
import com.springboot.es.repository.BookElasticsearch;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.client.Client;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.elasticsearch.core.query.IndexQueryBuilder;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Date;

@RunWith(SpringRunner.class)
@SpringBootTest
public class Springboot03EsApplicationTests {

    @Autowired
    BookElasticsearch bookElasticsearch;

    //测试往es索引文档
    @Test
    public void contextLoads() {
        bookElasticsearch.index(new Book(1001,"zdw的elasticsearch",true,new Date()));
    }

    //测试从 es索引文档
    @Test
    public void getIndex() {
        /*Book book = new Book();
        book.setId(1001);
        Book save = bookElasticsearch.save(book);
        System.out.println(save.getName()+"--"+book.getPublishDate());*/

        Book zdw = bookElasticsearch.findBookByNameLike("zdw");
        System.out.println(zdw);
    }
}

3.4.2 方式二:使用ElasticsearchTemplate

直接使用@Autowired注入即可,SpringBoot已经帮我们配置了好,添加到了容器中:

@Autowired
ElasticsearchTemplate elasticsearchTemplate;

//测试往es索引文档
@Test
public void templateIndex() {
    /*Integer documentId = 1001;
        Book book = new Book();
        book.setId(documentId);
        book.setName("zdw的elasticsearch");
        IndexQuery indexQuery = new IndexQueryBuilder().withId(book.getId()+"").withObject(book).build();

        String index = elasticsearchTemplate.index(indexQuery);
        System.out.println(index);*/

    Client client = elasticsearchTemplate.getClient();
    GetResponse response = client.prepareGet("zxh", "book", "1001").get();
    System.out.println(response.getSource());

}

简单的整合完成,具体使用还需要参照官方文档,后续继续学习。