kagamihogeの日記

kagamihogeの日記です。

Elasticsearch 6.6 + Spring Data Elasticsearch 3.1.5うごかす

やったこと

Elasticsearch + docker

上記URLを参考にElasticsearchをdockerで動かす環境を作る。

docker-compose.xml

version: '2'
services:
  elasticsearch:
    build: elasticsearch
    volumes:
        - elasticsearch-data:/usr/share/elasticsearch/data
        - ./elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.ymlig/elasticsearch.yml
    ports:
        - 9200:9200
        - 9300:9300
  kibana:
    build: kibana
    ports:
        - 5601:5601

volumes:
    elasticsearch-data:
        driver: local

elasticsearch/Dockerfile

FROM docker.elastic.co/elasticsearch/elasticsearch:6.6.1

RUN elasticsearch-plugin install analysis-kuromoji

kibana/Dockerfile

FROM docker.elastic.co/kibana/kibana:6.6.1

elasticsearch/config/elasticsearch.yml

cluster.name: docker-cluster

Spring Data Elasticsearch

pom.xml

<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.1.3.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

    <groupId>kagamihoge</groupId>
    <artifactId>spring-erasticsearch-sample</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>spring-erasticsearch-sample</name>
    <url>http://maven.apache.org</url>

    <properties>
        <java.version>10</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </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-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

java

package kagamihoge.springerasticsearchsample;

import java.net.InetAddress;
import java.net.UnknownHostException;

import org.elasticsearch.client.Client;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;

import kagamihoge.springerasticsearchsample.repository.SampleDataRepository;

@SpringBootApplication
@EnableElasticsearchRepositories(basePackages = "kagamihoge.springerasticsearchsample.repository")
public class App implements CommandLineRunner {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }

    @Bean
    public Client client() throws UnknownHostException {
        Settings elasticsearchSettings = Settings.builder().put("cluster.name", "docker-cluster").build();
        TransportClient client = new PreBuiltTransportClient(elasticsearchSettings);
        client.addTransportAddress(new TransportAddress(InetAddress.getByName("127.0.0.1"), 9300));
        return client;
    }

    @Autowired
    ElasticsearchOperations elasticsearchTemplate;

    @Autowired
    SampleDataRepository repository;

    @Override
    public void run(String... args) throws Exception {
        elasticsearchTemplate.createIndex(SampleData.class);

        SampleData d = new SampleData();
        d.id = "id0002";
        d.title = "title-bbbb";

        repository.save(d);
    }
}

"cluster.name"elasticsearch/config/elasticsearch.ymlで指定したのと同じ名前を使用する。hostとportを指定するところでは、hostはともかく、portはデフォルトではelasticsearchが9300で公開するポートを使用する。なのでdocker-compose.xmlで9300をフォワーディングしている。

package kagamihoge.springerasticsearchsample.repository;

import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;

import kagamihoge.springerasticsearchsample.SampleData;

@Repository
public interface SampleDataRepository extends ElasticsearchRepository<SampleData, String> {

}

repositoryはこんな感じ。spring-data-jpa触った事あればなんとなく分かる。

package kagamihoge.springerasticsearchsample;

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

@Document(indexName = "sample", type = "data")
public class SampleData {
    @Id
    String id;
     
    String title;
}

実行結果

これを実行したあとkibanaのdevtoolsで、

GET /sample/data/_search

すると、こんな感じに結果が返ってくる。

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "sample",
        "_type" : "data",
        "_id" : "id0002",
        "_score" : 1.0,
        "_source" : { }
      },
      {
        "_index" : "sample",
        "_type" : "data",
        "_id" : "id0001",
        "_score" : 1.0,
        "_source" : { }
      }
    ]
  }
}

その他

elasticsearchとspring data elasticsearchの対応バージョン

https://github.com/spring-projects/spring-data-elasticsearch を見ると、両者の対応バージョン表がある。今回使ってみたのは6.6 + 3.1.5なので微妙にマッチしていないのだが、なんか動いている。この表はあくまでもspringのライブラリ対応表ってだけなんだろうか? ただ、ぐぐってみるとバージョン違いで動作しないケースも結構あるようなので、その辺は事前に調べておくのが良い気がする。

はまった点

None of the configured nodes are available

なんかこんな感じのエラーが出て接続できなかった。

Caused by: org.elasticsearch.client.transport.NoNodeAvailableException: None of the configured nodes are available: [{#transport#-1}{zRBMC1NWSPeowkxoa2bIpQ}{localhost}{127.0.0.1:9200}]
    at org.elasticsearch.client.transport.TransportClientNodesService.ensureNodesAreAvailable(TransportClientNodesService.java:349) ~[elasticsearch-6.4.3.jar:6.4.3]
    at org.elasticsearch.client.transport.TransportClientNodesService.execute(TransportClientNodesService.java:247) ~[elasticsearch-6.4.3.jar:6.4.3]
    at org.elasticsearch.client.transport.TransportProxyClient.execute(TransportProxyClient.java:60) ~[elasticsearch-6.4.3.jar:6.4.3]

9200はhttpで、TransportClientで接続する場合は9300(elasticsearchのデフォルト)を使う必要がある。加えて、dockerの場合これをポートフォワーディングしとく必要がある。