java整合ElasticSearch上

2024/7/12 语法

# 一、ES概述

  • ES是一个使用Java语言并且基于Lucene编写的搜索引擎框架,他提供了分布式的全文搜索功能,提供了一个统一的基于RESTful风格的WEB接口,官方客户端也对多种语言都提供了相应的API。

  • Lucene:Lucene本身就是一个搜索引擎的底层。

  • 分布式:ES主要是为了突出他的横向扩展能力。

  • 全文检索:将一段词语进行分词,并且将分出的单个词语统一的放到一个分词库中,在搜索时,根据关键字去分词库中检索,找到匹配的内容。(倒排索引)

  • RESTful风格的WEB接口:操作ES很简单,只需要发送一个HTTP请求,并且根据请求方式的不同,携带参数的同,执行相应的功能。

  • 应用广泛:Github.com,WIKI,Gold Man用ES每天维护将近10TB的数据。

# 二、Java操作ElasticSearch

# 2.1 导入依赖

<!-- ElasticSearch -->
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>${elasticsearch.version}</version>
</dependency>

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-client</artifactId>
    <version>${elasticsearch.version}</version>
</dependency>

<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>${elasticsearch.version}</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 2.2 连接工具类

import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Arrays;

@Configuration
public class ElasticSearchConfig {
    // 连接超时时间
    @Value("${elasticsearch.connectTimeOut}")
    private int connectTimeOut;
    // 连接超时时间
    @Value("${elasticsearch.socketTimeOut}")
    private int socketTimeOut;
    // 获取连接的超时时间
    @Value("${elasticsearch.connectionRequestTimeOut}")
    private int connectionRequestTimeOut;
    // 最大连接数
    @Value("${elasticsearch.maxConnTotal}")
    private int maxConnTotal;
    // 最大路由连接数
    @Value("${elasticsearch.maxConnPerRoute}")
    private int maxConnPerRoute;
    // 使用协议
    @Value("${elasticsearch.scheme:http}")
    private String scheme;
    // 服务节点
    @Value("${elasticsearch.nodes}")
    private String[] nodes;
    // 鉴权账号
    @Value("${elasticsearch.username}")
    private String username;
    // 账号密码
    @Value("${elasticsearch.password}")
    private String password;

    @Bean(name = "restHighLevelClient")
    public RestHighLevelClient restHighLevelClient() {
        final CredentialsProvider credentialsProvider =
                new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY,
                new UsernamePasswordCredentials(username, password));

        RestClientBuilder builder = RestClient.builder(hosts())
                .setHttpClientConfigCallback(httpClientBuilder -> {
                    httpClientBuilder.setMaxConnTotal(maxConnTotal)
                            .setMaxConnPerRoute(maxConnPerRoute)
                            .setDefaultCredentialsProvider(credentialsProvider);
                    return httpClientBuilder;
                })
                .setRequestConfigCallback(requestConfigBuilder -> {
                    requestConfigBuilder.setConnectTimeout(connectTimeOut)
                            .setSocketTimeout(socketTimeOut)
                            .setConnectionRequestTimeout(connectionRequestTimeOut);
                    return requestConfigBuilder;
                });

        return new RestHighLevelClient(builder);
    }

    private HttpHost[] hosts() {
        return Arrays.asList(nodes).stream().map(node -> {
            String[] array = node.split(":");
            return new HttpHost(array[0], Integer.parseInt(array[1]), scheme);
        }).toArray(HttpHost[]::new);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

# 2.3 Java操作索引

/**
 * es实体类
 */
public class Person {

    //json转换的时候忽略这个id
    @JsonIgnore
    private String id;
    
    //姓名
    private String name;
    
    //年龄
    private Integer age;

    //出生日期, 日期格式必须和ES中这个索引字段的日期格式保持一致
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date birthday;

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 2.3.1 创建索引

import com.tingyi.utils.EsClient;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.junit.Test;

public class TestIndexManage {

    //es连接
    @Autowired     
    private RestHighLevelClient restHighLevelClient;
    
    //索引库名字
    private String index = "person";

    /**
     * 创建分片, 索引以及索引结构
     * @throws Exception
     */
    @Test
    public void testCreateIndex() throws Exception {
        //1. 创建主分片和备份分片
        Settings.Builder settings = Settings.builder()
                .put("number_of_shards", 5)
                .put("number_of_replicas", 1);

        //2. 创建索引结构
        XContentBuilder mapping = JsonXContent.contentBuilder()
                .startObject()
                    .startObject("properties")
                        .startObject("name")
                            .field("type", "text")
                        .endObject()
                        .startObject("age")
                            .field("type", "integer")
                        .endObject()
                        .startObject("birthday")
                            .field("type", "date")
                            .field("format", "yyyy-MM-dd")
                        .endObject()
                    .endObject()
                .endObject();

        //3. 将分片和索引结构封装成一个Request对象
        CreateIndexRequest request = new CreateIndexRequest(index)
                .settings(settings)
                .mapping(mapping);

        //4. 发送请求执行创建并返回响应
        CreateIndexResponse response = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
        System.out.println("========" + response);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

# 2.3.2 检查索引是否存在

import com.tingyi.utils.EsClient;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.junit.Test;

import java.io.IOException;

public class TestIndexManage {

    //es连接
    @Autowired     
    private RestHighLevelClient restHighLevelClient;
    
    //索引库名字
    private String index = "person";

    /**
     * 查看索引是否存在
     * @throws IOException
     */
    @Test
    public void testIndexExists() throws IOException {
        //1. 准备Get请求对象
        GetAliasesRequest request = new GetAliasesRequest();
        //将索引名字加入到请求对象中
        request.indices(index);

        //2. 通过client去操作
        boolean exists = restHighLevelClient.indices().existsAlias(request, RequestOptions.DEFAULT);

        //3. 输出
        System.out.println(exists);
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

# 2.3.3 删除索引

import com.tingyi.utils.EsClient;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.junit.Test;

public class TestIndexManage {

    //es连接
    @Autowired     
    private RestHighLevelClient restHighLevelClient;
    
    //索引库名字
    private String index = "person";

    /**
     * 删除索引
     * @throws Exception
     */
    @Test
    public void testDeleteIndex() throws Exception{
        //1. 准备删除索引请求对象
        DeleteIndexRequest request = new DeleteIndexRequest();
        //将需要删除的索引名字加入到请求对象中
        request.indices(index);

        //2. 通过client对象执行
        AcknowledgedResponse delete = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);

        //3. 获取返回结果
        System.out.println(delete.isAcknowledged());
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

# 2.4 Java操作文档

# 查询所有文档命令
GET book/_search
{
  "query": {
    "match_all": {}
  }
}
1
2
3
4
5
6
7

# 2.4.1 添加文档操作

import com.fasterxml.jackson.databind.ObjectMapper;
import com.tingyi.utils.EsClient;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.Test;
import pojo.Person;

import java.io.IOException;
import java.util.Date;

public class TestSimple {

    //json转换工具对象
    private ObjectMapper mapper = new ObjectMapper();

    //es连接
    @Autowired     
    private RestHighLevelClient restHighLevelClient;

    //索引名字
    private String index = "person";

    /**
     * 添加文档, 存入数据
     * @throws IOException
     */
    @Test
    public void testCreateDoc() throws IOException {
        //1. 准备一个person数据
        Person person = new Person("1", "张三", 23, new Date());
        //2. 将person实体转换成json格式
        String json = mapper.writeValueAsString(person);

        //3. 准备一个request对象, 指定索引名字(手动指定id)
        IndexRequest request = new IndexRequest(index);

        //4. 手动指定id, 将json数据存入请求对象中, XContentType.JSON为存入数据类型
        request.id(person.getId()).source(json, XContentType.JSON);

        //5. 通过client对象执行添加
        IndexResponse resp = restHighLevelClient.index(request, RequestOptions.DEFAULT);

        //6. 输出返回结果
        System.out.println(resp.getResult().toString());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

# 2.4.2 修改文档

import com.fasterxml.jackson.databind.ObjectMapper;
import com.tingyi.utils.EsClient;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.Test;
import pojo.Person;

import java.io.IOException;
import java.util.Date;

public class TestSimple {

    //json转换工具对象
    private ObjectMapper mapper = new ObjectMapper();

    //es连接
    @Autowired     
    private RestHighLevelClient restHighLevelClient;

    //索引名字
    private String index = "person";

    /**
     * 修改文档数据
     */
    @Test
    public void testUpdateDoc() throws Exception {
        //1. 准备一个person数据
        Person person = new Person("1", "青龙", 23, new Date());
        //2. 将person实体转换成json格式
        String json = mapper.writeValueAsString(person);

        //2. 创建修改请求对象, 第一个参数: 索引名字, 第二个参数:修改的文档id
        UpdateRequest request = new UpdateRequest(index, person.getId());
        //设置修改后的内容, 第二个参数: 文档数据类型
        request.doc(json, XContentType.JSON);

        //3. 通过client对象执行
        UpdateResponse update = restHighLevelClient.update(request, RequestOptions.DEFAULT);

        //4. 输出返回结果
        System.out.println(update.getResult().toString());

    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

# 2.4.3 删除文档

import com.fasterxml.jackson.databind.ObjectMapper;
import com.tingyi.utils.EsClient;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.Test;
import pojo.Person;

import java.io.IOException;
import java.util.Date;

public class TestSimple {

    //json转换工具对象
    private ObjectMapper mapper = new ObjectMapper();

    //es连接
    @Autowired     
    private RestHighLevelClient restHighLevelClient;

    //索引名字
    private String index = "person";

    /**
     * 根据id删除文档
     * @throws IOException
     */
    @Test
    public void testDeleteDoc() throws Exception {
        //1. 封装用于删除的请求对象, 第一参数:索引名字, 第二参数:文档id
        DeleteRequest request = new DeleteRequest(index, "1");

        //2. client执行
        DeleteResponse resp = restHighLevelClient.delete(request, RequestOptions.DEFAULT);

        //3. 输出结果
        System.out.println(resp.getResult().toString());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# 2.5 Java批量操作文档

# 2.5.1 批量添加

import com.fasterxml.jackson.databind.ObjectMapper;
import com.tingyi.utils.EsClient;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.Test;
import pojo.Person;

import java.io.IOException;
import java.util.Date;

public class TestSimple {

    //json转换工具对象
    private ObjectMapper mapper = new ObjectMapper();

    //es连接
    @Autowired     
    private RestHighLevelClient restHighLevelClient;

    //索引名字
    private String index = "person";

    /**
     * 批量添加数据
     * @throws IOException
     */
    @Test
    public void testBulkCreateDoc() throws IOException {
        //1. 准备多个person实体数据
        Person p1 = new Person("1", "张三", 23, new Date());
        Person p2 = new Person("2", "李四", 24, new Date());
        Person p3 = new Person("3", "王五", 25, new Date());

        //2. 将实体数据转换成json格式
        String json1 = mapper.writeValueAsString(p1);
        String json2 = mapper.writeValueAsString(p2);
        String json3 = mapper.writeValueAsString(p3);

        //3. 创建批量执行请求对象,将准备好的数据封装进去
        BulkRequest request = new BulkRequest();
        request.add(new IndexRequest(index).id(p1.getId()).source(json1, XContentType.JSON));
        request.add(new IndexRequest(index).id(p2.getId()).source(json2, XContentType.JSON));
        request.add(new IndexRequest(index).id(p3.getId()).source(json3, XContentType.JSON));

        //4. 用client执行
        BulkResponse resp = restHighLevelClient.bulk(request, RequestOptions.DEFAULT);

        //5. 输出结果
        System.out.println(resp.toString());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

# 2.5.2 批量删除

import com.fasterxml.jackson.databind.ObjectMapper;
import com.tingyi.utils.EsClient;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.Test;
import pojo.Person;

import java.io.IOException;
import java.util.Date;

public class TestSimple {

    //json转换工具对象
    private ObjectMapper mapper = new ObjectMapper();

    //es连接
    @Autowired     
    private RestHighLevelClient restHighLevelClient;

    //索引名字
    private String index = "person";

    /**
     * 批量删除文档数据
     * @throws IOException
     */
    @Test
    public void bulkDeleteDoc() throws IOException {
        //1. 封装Request对象
        BulkRequest request = new BulkRequest();
        request.add(new DeleteRequest(index,"1"));
        request.add(new DeleteRequest(index,"2"));
        request.add(new DeleteRequest(index,"3"));

        //2. client执行
        BulkResponse resp = restHighLevelClient.bulk(request, RequestOptions.DEFAULT);

        //3. 输出
        System.out.println(resp);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50