結合型の実装
Spring Data Elasticsearch は、対応するインデックスマッピングを作成し、関連情報を保存するために結合データ型 (英語) をサポートします。
データのセットアップ
エンティティを親子結合関連で使用するには、アノテーションを付ける必要がある型 JoinField
のプロパティが必要です。ステートメントが質問、回答、コメント、投票である Statement
エンティティを仮定します (この例ではビルダーも示されていますが、必須ではありませんが、後ほどサンプルコードで使用されます)。
@Document(indexName = "statements")
@Routing("routing") (1)
public class Statement {
@Id
private String id;
@Field(type = FieldType.Text)
private String text;
@Field(type = FieldType.Keyword)
private String routing;
@JoinTypeRelations(
relations =
{
@JoinTypeRelation(parent = "question", children = {"answer", "comment"}), (2)
@JoinTypeRelation(parent = "answer", children = "vote") (3)
}
)
private JoinField<String> relation; (4)
private Statement() {
}
public static StatementBuilder builder() {
return new StatementBuilder();
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getRouting() {
return routing;
}
public void setRouting(String routing) {
this.routing = routing;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public JoinField<String> getRelation() {
return relation;
}
public void setRelation(JoinField<String> relation) {
this.relation = relation;
}
public static final class StatementBuilder {
private String id;
private String text;
private String routing;
private JoinField<String> relation;
private StatementBuilder() {
}
public StatementBuilder withId(String id) {
this.id = id;
return this;
}
public StatementBuilder withRouting(String routing) {
this.routing = routing;
return this;
}
public StatementBuilder withText(String text) {
this.text = text;
return this;
}
public StatementBuilder withRelation(JoinField<String> relation) {
this.relation = relation;
return this;
}
public Statement build() {
Statement statement = new Statement();
statement.setId(id);
statement.setRouting(routing);
statement.setText(text);
statement.setRelation(relation);
return statement;
}
}
}
1 | ルーティング関連情報については、ルーティング値を参照してください。 |
2 | 質問には回答とコメントを含めることができます |
3 | 回答には投票が可能です |
4 | JoinField プロパティは、リレーションの名前 ( 質問、回答、コメント、投票 ) と親 ID を組み合わせるために使用されます。ジェネリクス型は、@Id アノテーション付きプロパティと同じである必要があります。 |
Spring Data Elasticsearch は、このクラスに対して次のマッピングを構築します。
{
"statements": {
"mappings": {
"properties": {
"_class": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"routing": {
"type": "keyword"
},
"relation": {
"type": "join",
"eager_global_ordinals": true,
"relations": {
"question": [
"answer",
"comment"
],
"answer": "vote"
}
},
"text": {
"type": "text"
}
}
}
}
}
データの保存
このクラスのリポジトリを指定すると、次のコードは質問、2 つの回答、コメント、投票を挿入します。
void init() {
repository.deleteAll();
Statement savedWeather = repository.save(
Statement.builder()
.withText("How is the weather?")
.withRelation(new JoinField<>("question")) (1)
.build());
Statement sunnyAnswer = repository.save(
Statement.builder()
.withText("sunny")
.withRelation(new JoinField<>("answer", savedWeather.getId())) (2)
.build());
repository.save(
Statement.builder()
.withText("rainy")
.withRelation(new JoinField<>("answer", savedWeather.getId())) (3)
.build());
repository.save(
Statement.builder()
.withText("I don't like the rain")
.withRelation(new JoinField<>("comment", savedWeather.getId())) (4)
.build());
repository.save(
Statement.builder()
.withText("+1 for the sun")
.withRouting(savedWeather.getId())
.withRelation(new JoinField<>("vote", sunnyAnswer.getId())) (5)
.build());
}
1 | 質問文を作成する |
2 | 質問に対する最初の答え |
3 | 2 番目の答え |
4 | 質問に対するコメント |
5 | 最初の回答に投票します。これには、ルーティングを気象ドキュメントに設定する必要があります。ルーティング値を参照してください。 |
データの取得
現在、データのクエリにはネイティブクエリを使用する必要があるため、標準のリポジトリメソッドはサポートされていません。代わりにカスタムリポジトリの実装を使用できます。
次のコードは、例として、ElasticsearchOperations
インスタンスを使用して、投票のあるすべてのエントリ (投票できるのは回答のみであるため、回答である必要があります) を取得する方法を示しています。
SearchHits<Statement> hasVotes() {
Query query = NativeQuery.builder()
.withQuery(co.elastic.clients.elasticsearch._types.query_dsl.Query.of(qb -> qb
.hasChild(hc -> hc
.type("answer")
.queryName("vote")
.query(matchAllQueryAsQuery())
.scoreMode(ChildScoreMode.None)
)))
.build();
return operations.search(query, Statement.class);
}