Java 入门

Java 版本的客户端有两个,一个是 Java REST Client,一个是 Java API。 Java API 在 Elasticsearch 7 版本就废弃了,将来的 8 版本中会删除。

Deprecated in 7.0.0.

The TransportClient is deprecated in favour of the Java High Level REST Client and will be removed in Elasticsearch 8.0. The migration guide describes all the steps needed to migrate.

另外,Java REST Client 包括低级版,和高级版。

The Java REST Client comes in 2 flavors:

  • Java Low Level REST Client: the official low-level client for Elasticsearch. It allows to communicate with an Elasticsearch cluster through http. Leaves requests marshalling and responses un-marshalling to users. It is compatible with all Elasticsearch versions.
  • Java High Level REST Client: the official high-level client for Elasticsearch. Based on the low-level client, it exposes API specific methods and takes care of requests marshalling and responses un-marshalling.

简单的说,两个都是官方的客户端。低级版客户端会展现更多的细节,高级本客户端是对低级版的封装,使用起来更方便。这里先使用低级版客户端做简单的展示。

新建 Maven 项目

这里使用知名的集成开发环境 IntelliJ IDEA,idea 能够极大的提高 Java 开发效率,这里使用 idea 社区版,如果是 Java 程序员推荐订阅 idea 旗舰版。

idea start page
启动 idea

点击 Create New Project

idea new project
新建项目

如果提示 No SDK,可以点击 Download JSK 下载新的 JDK,或者点击 Add JDK 使用之前安装的 JDK。点击左侧菜单栏中的 Maven ,新建 Maven 项目。

new maven project
新建 Maven 项目

点击 Next

set project name
设置项目名称

name 中输入项目名称,GroupId 一般使用反向的域名,如果没有就使用 org.example 也可以。点击 Finish ,项目创建完成。

new project home
一个新的项目
配置 Maven

打开 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>

    <groupId>org.example</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>1.0-SNAPSHOT</version>

</project>

在项目中加上 Ealsticsearch 依赖库,这里使用低级版客户端。

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-client</artifactId>
    <version>7.7.1</version>
</dependency>

另外推荐使用阿里云的 Maven 服务,速度快很多。

<repository>
    <id>aliyun</id>
    <name>阿里云公共仓库</name>
    <url>https://maven.aliyun.com/repository/public</url>
</repository>

最终得到的 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>

    <groupId>org.example</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>1.0-SNAPSHOT</version>

    <repositories>
        <repository>
            <id>aliyun</id>
            <name>阿里云公共仓库</name>
            <url>https://maven.aliyun.com/repository/public</url>
        </repository>
    </repositories>

    <dependencies>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-client</artifactId>
            <version>7.7.1</version>
        </dependency>
    </dependencies>

</project>
创建 Java 类

在 src -> main -> java 文件夹上右击,选择 New,然后点击 Java Class

rigth click, new java class
右击,选择创建 Java 文件
input java file name
输入 Java 文件名

输入 Java 文件名 Main。得到 Main.java 的内容如下:

public class Main {
}

在类中添加 main 方法。

public static void main(String[] args) {
}
实例化一个 client

如果设置了密码

final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
        new UsernamePasswordCredentials("elastic", "password"));

RestClientBuilder builder = RestClient.builder(
        new HttpHost("localhost", 9200))
        .setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
            @Override
            public HttpAsyncClientBuilder customizeHttpClient(
                    HttpAsyncClientBuilder httpClientBuilder) {
                return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
            }
        });
RestClient restClient = builder.build();

如果没有设置密码

RestClient restClient = RestClient.builder(
        new HttpHost("127.0.0.1", 9200, "http")).build();
编写代码,操作 Elasticsearch
Request request = new Request("GET", "/");
request.addParameter("pretty", "true");
Response response = restClient.performRequest(request);
String responseBody = EntityUtils.toString(response.getEntity());
System.out.println(responseBody);

第一行表示创建实例化一个请求对象,第二行表示这个请求对象添加参数 pretty ,返回的数据格式要优化。

第三行表示用 restClient 发送请求,并且获取结果。

第四行表示获取结果中的内容实体,并转化问字符串。第五行表示在控制台输出这些字符串。

此时,Main.java 文件内容如下:

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.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.apache.http.util.EntityUtils;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;

import java.io.IOException;


public class Main {

    public static void main(String[] args) throws IOException {
        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY,
                new UsernamePasswordCredentials("elastic", "vf41EwoSzt6dy4z0"));

        RestClientBuilder builder = RestClient.builder(
                new HttpHost("localhost", 9200))
                .setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
                    @Override
                    public HttpAsyncClientBuilder customizeHttpClient(
                            HttpAsyncClientBuilder httpClientBuilder) {
                        return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
                    }
                });
        RestClient restClient = builder.build();

        Request request = new Request("GET", "/");
        request.addParameter("pretty", "true");
        Response response = restClient.performRequest(request);
        String responseBody = EntityUtils.toString(response.getEntity());
        System.out.println(responseBody);

        restClient.close();
    }
}
debug java code
运行 Java 文件

点击 Debug 'Main.main()' 用 debug 模式运行 java 文件。在控制台中会得到如下信息:

{
  "name" : "MacBook-Pro.local",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "zTr3Oy4XQqKfumywlDkBOA",
  "version" : {
    "number" : "7.7.1",
    "build_flavor" : "default",
    "build_type" : "tar",
    "build_hash" : "ad56dce891c901a492bb1ee393f12dfff473a423",
    "build_date" : "2020-05-28T16:30:01.040088Z",
    "build_snapshot" : false,
    "lucene_version" : "8.5.1",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

这就表示项目运行成功了,java 代码成功的连接上 Elasticsearch 服务器,并且获得了返回信息。

插入数据

默认使用刚刚创建的 restClient,只替换操作 Elasticsearch 代码部分。

var data = "{\n" +
        "        \"name\":\"东方明珠广播电视塔\",\n" +
        "        \"Description\":\"东方明珠广播电视塔,位于上海市浦东陆家嘴的未来主义建筑,与外滩隔黄浦江相望,原名上海广播电视塔,上海市民也常简称其为东方明珠。东方明珠由当时华东建筑设计研究院设计,1991年动工,1994年落成,总高468米。在1994年至2007年间,是中国大陆地区的最高建筑,2007年被上海环球金融中心超越。东方明珠自落成以后便成为上海天际线的组成部分之一,是上海的地标性建筑,同时也是中国国家5A级旅游景区。 \",\n" +
        "        \"tags\":[\n" +
        "            \"东方明珠\",\n" +
        "            \"景点\"\n" +
        "        ],\n" +
        "        \"location\":{\n" +
        "            \"lat\":31.239886,\n" +
        "            \"lon\":121.499673\n" +
        "        }\n" +
        "    }";
Request request = new Request("PUT", "/locale/_doc/1");
request.addParameter("pretty", "true");
request.setJsonEntity(data);
Response response = restClient.performRequest(request);
String responseBody = EntityUtils.toString(response.getEntity());
System.out.println(responseBody);

运行一下,得到结果:

{
  "_index" : "locale",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}

结果表明,创建了一个索引 locale,ID是 1;版本是 1;结果是 "创建完成";total 的值大于 successful 的值,这个不是表示运行失败,而是表示分片一共有两个,成功创建 1 个分片,这是因为 Elasticsearch 在单节点上运行,主分片没有创建副本,如果在多节点运行 total 和 successful 的值就应该一样。

如果重新运行当前程序,就会发现,版本增加成 2,结果变成 updated ,表示数据更新完成。

另外,由于 type 已经废弃了,不需要制定 type 了,直接使用 _doc 替代。

查询数据
Request request = new Request("GET", "/locale/_doc/1");
request.addParameter("pretty", "true");
Response response = restClient.performRequest(request);
String responseBody = EntityUtils.toString(response.getEntity());
System.out.println(responseBody);

运行代码,会得到结果:

{
  "_index" : "locale",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 1,
  "_seq_no" : 0,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "name" : "东方明珠广播电视塔",
    "Description" : "东方明珠广播电视塔,位于上海市浦东陆家嘴的未来主义建筑,与外滩隔黄浦江相望,原名上海广播电视塔,上海市民也常简称其为东方明珠。东方明珠由当时华东建筑设计研究院设计,1991年动工,1994年落成,总高468米。在1994年至2007年间,是中国大陆地区的最高建筑,2007年被上海环球金融中心超越。东方明珠自落成以后便成为上海天际线的组成部分之一,是上海的地标性建筑,同时也是中国国家5A级旅游景区。 ",
    "tags" : [
      "东方明珠",
      "景点"
    ],
    "location" : {
      "lat" : 31.239886,
      "lon" : 121.499673
    }
  }
}

除了插入的数据之外,还获得了索引等信息。

搜索数据
var data = "{\n" +
        "  \"query\": { \"match_all\": {} }" +
        "}";
Request request = new Request("GET", "/locale/_search");
request.addParameter("pretty", "true");
request.setJsonEntity(data);
Response response = restClient.performRequest(request);
String responseBody = EntityUtils.toString(response.getEntity());
System.out.println(responseBody);

执行一下,得到结果:

{
  "took" : 73,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "locale",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "name" : "东方明珠广播电视塔",
          "Description" : "东方明珠广播电视塔,位于上海市浦东陆家嘴的未来主义建筑,与外滩隔黄浦江相望,原名上海广播电视塔,上海市民也常简称其为东方明珠。东方明珠由当时华东建筑设计研究院设计,1991年动工,1994年落成,总高468米。在1994年至2007年间,是中国大陆地区的最高建筑,2007年被上海环球金融中心超越。东方明珠自落成以后便成为上海天际线的组成部分之一,是上海的地标性建筑,同时也是中国国家5A级旅游景区。 ",
          "tags" : [
            "东方明珠",
            "景点"
          ],
          "location" : {
            "lat" : 31.239886,
            "lon" : 121.499673
          }
        }
      }
    ]
  }
}
  • took – 消耗的时间,单位是毫秒;
  • timed_out – 是否超时;
  • _shards – 搜索了多少分片,以及多少分片执行成功、失败、或者跳过;
  • max_score – 相关性得分;
  • hits.total.value - 找到多少文件;
  • hits.hits - 查找到的内容。

使用 Java 版本客户端体验了一下插入、查找、搜索数据的过程,后面会详细介绍 Java 高级版客户端的使用方法。