ページ

2016/12/31

Spring Data JPAで複数テーブルを結合した結果を返すクエリを作る

|

少し前に検証したものだが、改めて整理。

テーブルAとテーブルBを結合した結果を取得したい場合に、普通にSpring DataのRepositoryを作って@Query のメソッドを定義してもうまくいかない。
例えば以下のようなクエリは表現できない。

select a.id, b.id, b.name from a join b on b.id = a.b_id;

これを何とかRepositoryで表現するための方法について。

ElasticsearchのBouncing Results問題

|

Boucing Resultsという問題がある。検索結果に重複・欠落が起きる問題。

ソートのキーに使われる項目の値が同じdocumentがあると、検索結果の順序が一定にならない可能性がある。
Elasticsearchのクエリでページネーションを行う場合、各ページへのリクエストは独立しているので、それぞれのアクセスで別のシャードにアクセスする可能性がある。

  • 対象のElasticsearchクラスタがレプリカを持っている
  • ソート対象項目の値が同一の複数documentがページを跨っている
  • それらのページへのリクエストが別のシャードに割り当てられる
  • それぞれのシャードが対象のdocumentを返す順番が異なる

といった条件が揃うと、1ページ目で返された検索結果が次のページでも返ってくる、という事象が起きる。

これは、Elasticsearch: The Definitive Guide でも説明されている Bouncing Results という問題とのこと。

この問題と思われる事象に遭遇したため、事象の再現と対策の検証を行なった。

Thymeleafの部品化

|

th:fragment によって部品を作るのは比較的簡単にできるが、
類似の部品が出てきた時に、その中の一部を変更したい場合にどうするか?

例えば以下のようなイメージ。
barタグとbazタグだけが差分であり、その他は同じ構成になっている。

<foo id="foo1">
  <div></div>
  <bar></bar>
</foo>

<foo id="foo2">
  <div></div>
  <baz></baz>
</foo>

それぞれのfooタグを部品として定義するのも良いが、それでは重複コードが多すぎる。

Gradleプラグインのup-to-dateを確認するテスト

|

GradleプラグインのTaskにInputとOutputを設定して、いずれかが変化した時にだけタスクが再実行されるようにしたいとき。
実装は簡単でも、テストはどうするか。
up-to-dateがきちんと判定できないと、変更が入った時に処理が実行されないなど致命的な不具合になる。
※Gradleのバージョンが古い(2.x)ので、最新では少し話が違うかもしれない。

Spockで複数ステップのテストを書く

|

Spockでテストを書くとき、setup:, when:, then: という流れで書けば良いが
複数の処理を実行し、最後の結果だけでなく途中の経過も含めてassertする場合にどうすればいいか。

単純に when:then: を繰り返して書けばいい。
and: などが一見それっぽいもののようにも思えてしまうが、and: はこの用途ではないので注意。

def ...() {
    setup:
    // 初期設定

    when:
    // 最初の処理

    then:
    // 最初の処理の結果をassert

    when:
    // 2つ目の処理

    then:
    // 2つ目の処理の結果をassert
}

Spring Data Elasticsearchが実行するクエリを確認する

|

Spring Data ElasticsearchのElasticsearchTemplateなどを使って
最終的に実行されたクエリを確認するには以下を application.yml に設定すれば良い。

spring:
    data:
        elasticsearch:
            properties:
                index:
                    search:
                        slowlog:
                            threshold:
                                query:
                                    info: "0s"

Spring Data ElasticsearchのローカルのノードにHTTPでアクセスする

|

忘れがちなのでメモ。
Spring Data ElasticsearchのローカルのノードにHTTPでアクセスするには、application.yml に以下を追加すればいい。

spring:
    data:
        elasticsearch:
            properties:
                http:
                    enabled: true

http://localhost:9200/ でアクセスできる。