daisuzz.log

Spring BootでElasticsearch Java API Clientを使ってみる

Elasticsearchの勉強の一環で公式ドキュメントを読んでいたところ、

deprecated[7.15.0, The High Level REST Client is deprecated in favour of the Java API Client.

と書かれていて、Java High Level REST Client が7.15.0でdeprecatedになっていました。 代わりにElasticsearch Java API Clientというクライアントライブラリが提供されていたので、今回はこのクライアントライブラリをSpring Bootで利用する方法を書いていきます。

Elasticsearch Java API Client について

Elasticsearch Java API Clientは、7系の段階ではまだベータ版として提供されている機能です。 公式ドキュメントにもその旨が記載されています。

This functionality is in beta and is subject to change. The design and code is less mature than official GA features and is being provided as-is with no warranties. Beta features are not subject to the support SLA of official GA features.

Introduction | Elasticsearch Java API Client [7.16] | Elastic

特徴としては、以下のようなものがあります。

  • 強く型付けされたElasticsearch API用のリクエストとレスポンスクラスを提供
  • 同期/非同期処理に対応
  • ネストした構造を表現しやすくするためにBuilderパターンとラムダをサポート
  • HTTPコネクションプールや再接続やノードの検出などトランスポートレベルの処理についてはJava Low Level REST Clientに処理を委譲

Spring BootでElasticsearch Java API Clientを使う

実際にElasticsearch Java API Clientを使ってみます。 それぞれのライブラリのバージョンなどは、以下にサンプルコードを置いてあるので参照してください。

pom.xmlにライブラリを追加

Elasticsearch Java API ClientとJava Low Level REST Clientの依存をpom.xmlに追加します。

    <dependencies>
        ...
        <dependency>
            <groupId>co.elastic.clients</groupId>
            <artifactId>elasticsearch-java</artifactId>
            <version>7.15.0</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-client</artifactId>
            <version>7.15.0</version>
        </dependency>
    </dependencies>

ElasticsearchClientの設定

Spring Bootで動かしているので、Elasticsearch Java API ClientをBeanとして登録して使うようにします。

import co.elastic.clients.base.RestClientTransport;
import co.elastic.clients.base.Transport;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ElasticsearchConfig {

    @Bean
    public ElasticsearchClient elasticsearchClient(RestClientBuilder builder) {

        RestClient restClient = builder.build();

        Transport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());

        return new ElasticsearchClient(transport);
    }
}

Java Low Level REST Clientに含まれているRestClientBuilderがクラスパス上にある場合かつ、RestClientBuilderがBeanとして登録されていない場合、Spring BootのAutoConfigurationによってRestClientBuilderが自動でBeanとして登録されます。

(参考)

今回はElasticsearchの認証機能を有効にしており、その認証情報をSpringが提供している設定プロパティを介して使いたかったため、Beanとして登録されたRestClientBuilderを使ってElasticsearch Java API Clientのインスタンスを生成しています。

RestClientBuilderのインスタンスをSpring Bootが作成する際に、application.propertiesに書かれた以下の設定プロパティを読み込んで、RestClientBuilderのインスタンスを作成しているので、明示的に設定プロパティを読み込むコードを書かずに済みます。

spring.elasticsearch.username=hoge
spring.elasticsearch.password=hoge
spring.elasticsearch.uris=http://localhost:9200

ElasticsearchClientを使ってみる

作成したElasticsearchClientを使って、実際にElasticsearchからデータを取得してみます。 詳細は割愛しますが、事前にElasticsearchのプロセスをローカルに9200ポートで立てておき、テストデータを登録してあります。

@RestController
@RequestMapping("elasticsearch")
public class SampleElasticsearchController {

    private final ElasticsearchClient elasticsearchClient;

    public SampleElasticsearchController(final ElasticsearchClient elasticsearchClient) {
        this.elasticsearchClient = elasticsearchClient;
    }

    @GetMapping("books")
    public List<Book> searchBooks(@RequestParam("query") String query) {
        try {
            SearchResponse<Book> search = elasticsearchClient.search(s -> s
                            .index("books")
                            .query(q -> q.match(m -> m
                                    .field("title")
                                    .query(query)
                            ))
                    , Book.class);

            return search.hits().hits().stream()
                    .map(Hit::source)
                    .toList();
        } catch (IOException e) {
            throw new RuntimeException("検索処理で例外が発生しました。");
        }
    }
}

上のコードでは、あらかじめ登録しておいた本の情報を検索して、Bookクラスに詰めてその情報を返しています。 Elasticsearch Java API Clientでは、取得対象のインデックスや、対象のフィールドやクエリをBuilderパターンとラムダを使って表現することができます。 それぞれのメソッドの命名や、どういった機能を提供しているかの詳細は、以下が参考になります。

API conventions | Elasticsearch Java API Client [7.16] | Elastic

実際に作成したコードを起動して、ブラウザで localhost:8080/elasticsearch/book?query=本 と叩いてみると、以下のようなレスポンスが返ってくることが確認できます。 f:id:dais39:20211127124009p:plain