9
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Java High Level REST Client Tips

Last updated at Posted at 2019-12-10

Elastic Stack (Elasticsearch) Advent Calendar 2019の11日目の記事です

はじめに

「Java High Level REST Client」を使用することで、Javaアプリからhttpを介してElasticsearchへアクセスできる

以前は「TransportClient」が使用されていたが8.0で廃止されているため、
Java High Level REST Client Tips」 もしくは「Java Low Level REST Client」の使用が推奨されている

今回は、検索(Search API)に絞った使用例を紹介します

注意点

  • Java High Level REST ClientはJava 1.8が必要
  • Elasticsearchとの接続は、マイナーバージョンの通信保証する

例)
Elasticsearch(7.0) Java High Level REST(7.0) → OK
Elasticsearch(7.0) Java High Level REST(6.8) → NG

※通信を保証するだけで、バージョンアップ時の新機能は対応してないことが多い

準備

Elasticsearchの環境 → ElasticCloud
Java8(JDK1.8.0)

インデックス「qiita」を作成

PUT /qiita
{
  "mappings": {
    "properties": {
      "user":    { "type": "keyword" },  
      "post_date":  { "type": "date"  }, 
      "active":  { "type": "boolean"  },
      "message":   { "type": "text"  }     
    }
  }
}

POST qiita/_doc
{
    "user" : "qiita",
    "post_date" : "2019-12-11T00:10:30Z",
    "active":"false",
    "message" : "trying out High Level REST Client"
}

GET qiita/_search
...
      {
        "_index" : "qiita",
        "_type" : "_doc",
        "_id" : "yjDo5m4Bj4TzcUq3pmoX",
        "_score" : 1.0,
        "_source" : {
          "user" : "qiita",
          "post_date" : "2019-12-11T00:10:30Z",
          "active" : "false",
          "message" : "trying out High Level REST Client"
        }
      }
...

pon.xml

    <dependencies>
        ...
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>7.5.0</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-client</artifactId>
            <version>7.5.0</version>
        </dependency>
        ...
    </dependencies>

接続用Clinent作成

基本的には、Initializationの例で問題ない

RestHighLevelClient client = new RestHighLevelClient(
        RestClient.builder(
                new HttpHost("localhost", 9200, "http"),
                new HttpHost("localhost", 9201, "http")));

client.close();

ElasticCloudの場合

ElasticCloudなど認証機能を導入している場合は、下記の設定が必要がある

String username = "elastic";
String password = "pass";
String host = "host";
int port = 9243;
int nextPort = 9244;
String protocol = "https";


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

RestClientBuilder client = RestClient.builder(
                new HttpHost(host, port, protocol),
                new HttpHost(host, nextPort, protocol))
                .setHttpClientConfigCallback((h) -> h.setDefaultCredentialsProvider(credentialsProvider));

RestHighLevelClient client = new RestHighLevelClient(client);

client.close();

データ取得

先ほど作成したclientを使用することで「GET qiita/_search」と似た取得ができます

try (RestHighLevelClient client = new RestHighLevelClient(client)) {

            SearchSourceBuilder searchBuilder = SearchSourceBuilder.searchSource();
            // quite*のようにワイルドカード指定できる
            SearchRequest request = new SearchRequest("qiita").source(searchBuilder);
            // データ取得
            SearchHits hits = client.search(request, RequestOptions.DEFAULT).getHits();
            for(SearchHit hit : hits) {
                Map<String, Object> sourceAsMap = hit.getSourceAsMap();

          // 1レコードごとの値を設定 
                String user = (String) sourceAsMap.get("user");
                String post_date = (String) sourceAsMap.get("post_date");
                String message = (String) sourceAsMap.get("message");
    
                System.out.println(String.format("user:%s data:%s message:%s",user , post_date, message));
            }
}catch (IOException io) {}

参考: Search API

サイズの設定

「SearchSourceBuilder」に設定する
サイズはデフォルトは10件しか取得しない

// default 10
SearchSourceBuilder searchBuilder = SearchSourceBuilder.searchSource();
searchBuilder.size(100);
            

ソート

「SearchSourceBuilder」に設定する
SortOrderでASCとDESCを切り替える

SearchSourceBuilder searchBuilder = SearchSourceBuilder.searchSource();
searchBuilder.sort(new FieldSortBuilder("_id").order(SortOrder.DESC));

検索クエリ(フィルタ)

Building Queriesに書かれているのは一通り使える(全部試したわけではない)が簡単なものを紹介する
基本、「SearchSourceBuilder」に設定する

Range Query(期間指定)

日本時刻の「2019-12-12T00:10:30」から「2019-12-13T00:10:31」まで取得している

SearchSourceBuilder searchBuilder = SearchSourceBuilder.searchSource();

QueryBuilder query = QueryBuilders
       .rangeQuery("post_date")
       .from("2019-12-12T00:10:30")
       .to("2019-12-13T00:10:31")
       .timeZone("+09:00");

searchBuilder.query(query);

注意が必要なのは、下記のように指定すると
「2019-12-09T00:00:00.000」〜「2019-12-13T23:59:59.999」まで取得する

QueryBuilder query = QueryBuilders
       .rangeQuery("post_date")
       .from("2019-12-12")
       .to("2019-12-13")
       .timeZone("+09:00");

searchBuilder.query(query);

12日のみのデータを取得するには下記のようになる

fromを含める場合は「includeLower」:true
toを含める場合は「includeUpper」 :true

QueryBuilder query = QueryBuilders
       .rangeQuery("post_date")
       .from("2019-12-12")
       .to("2019-12-13")
    .includeLower(true)
    .includeUpper(false)
       .timeZone("+09:00");

searchBuilder.query(query);

Match Query

全文検索のクエリは下記

SearchSourceBuilder searchBuilder = SearchSourceBuilder.searchSource();

QueryBuilder query = QueryBuilders.matchQuery("message", "REST Level ");
QueryBuilder query = QueryBuilders.matchQuery("message", "Level REST");
QueryBuilder query = QueryBuilders.matchPhraseQuery("message", "REST Level");
// フレーズ検索なので取得0件
QueryBuilder query = QueryBuilders.matchPhraseQuery("message", "Level REST");

searchBuilder.query(query);

Term Query

完全一致で検索される、Termクエリは下記

QueryBuilder query = QueryBuilders.termQuery("user", "qiita");

Bool Query(AND OR NOT)

Elastic Elastic SQL 説明
must AND
filter AND スコアを無視する
should OR
mustnot NOT
※スコアを使用しない検索の場合はなるべくfilterを使う
Elasticsearchのbool queryを利用してAND OR NOTを書いてみるがとても分かりやすい

AND

「must」「filter」どちらでも良い

「filter」の例はこんな感じ

SearchSourceBuilder searchBuilder = SearchSourceBuilder.searchSource();

BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
QueryBuilder query1 = QueryBuilders.matchQuery("message", "JAVA");
QueryBuilder query2 = QueryBuilders.matchQuery("message", "REST");
boolQuery.filter(query1);
boolQuery.filter(query2);

searchBuilder.query(boolQuery);

OR

BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
QueryBuilder query1 = QueryBuilders.matchQuery("message", "JAVA");
QueryBuilder query2 = QueryBuilders.matchQuery("message", "REST");
boolQuery.should(query1);
boolQuery.should(query2);

NOT

BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
QueryBuilder query = QueryBuilders.termQuery("user", "qiita");
boolQuery.mustNot(query);

JSON形式で検索するには?

下記のようにJSON形式でも取得することができる
Search Template API

SearchTemplateRequest request = new SearchTemplateRequest();
request.setRequest(new SearchRequest("qiita"));

request.setScriptType(ScriptType.INLINE);
request.setScript(
                    "{" +
                            "  \"query\": { \"match\" : { \"{{field}}\" : \"{{value}}\" } }," +
                            "  \"size\" : \"{{size}}\"" +
                            "}");

Map<String, Object> scriptParams = new HashMap<>();
scriptParams.put("field", "message");
scriptParams.put("value", "REST");
scriptParams.put("size", 5);
request.setScriptParams(scriptParams);

SearchTemplateResponse response = client.searchTemplate(request, RequestOptions.DEFAULT);
SearchResponse searchResponse = response.getResponse();
SearchHit[] results = searchResponse.getHits().getHits();

Frozen indices

6.8.1の「Java High Level REST Client」より使用することができる
Elasticsaerchに「Frozen indices」の実装された時には反映されていないため注意が必要

How to Search Freeze Index using Java High Level REST Client

SearchRequest request = new SearchRequest("qiita").source(searchBuilder);
request.indicesOptions(IndicesOptions.fromOptions(
                true,
                true,
                true,
                false,
                request.indicesOptions().allowAliasesToMultipleIndices(),
                request.indicesOptions().forbidClosedIndices(),
                request.indicesOptions().ignoreAliases(),
                true // ←ここでfrozen indexを検索できるか設定 true:検索可能
        ));

参考資料

終わりに

「Java High Level REST Client」の日本語記事が少なく、英語・中国記事を読むことが多いです。
ドキュメントに大体書いてあるのですが、新機能追加後は「Java High Level REST Client」では対応していないみたいなことがありソースやリリースノートを読まないといけないこともあります。

明日は@NAO_MK2さんです。

9
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?