Join-Type implementation
Spring Data Elasticsearch 支持 Join data type以创建相应的索引映射并存储相关信息。
Setting up the data
实体用于父子连接关系中,它必须具有类型为 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(Routing 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 | 有关路由相关的信息,请参阅 Routing values |
2 | 一个问题可以有答案和评论 |
3 | 一个答案可以有投票 |
4 | JoinField 属性用于把关系的名称 (question, answer, comment 或 vote) 和父 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"
}
}
}
}
}
Storing data
给定此类的存储库,以下代码将插入一个问题、两个答案、一个注释和一个投票:
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 | create a question statement |
2 | 该问题的第一答案 |
3 | the second answer |
4 | 该问题的评论 |
5 | 对第一个答案投赞成票,这需要将路由设置到 weather 文档,请参阅 Routing values。 |
Retrieving data
当前必须使用 native 查询来查询数据,因此不支持标准存储库方法。可以改用 repositories/custom-implementations.adoc。
以下代码展示了一个示例,说明如何使用 ElasticsearchOperations
实例来检索所有具有 投票 的条目(必须是 答案,因为只有答案才可能获得投票):
SearchHits<Statement> hasVotes() {
Query query = NativeQuery.builder()
.withQuery(co.elastic.clients.elasticsearch._types.query_dsl.Query.of(qb -> qb
.hasChild(hc -> hc
.queryName("vote")
.query(matchAllQueryAsQuery())
.scoreMode(ChildScoreMode.None)
)))
.build();
return operations.search(query, Statement.class);
}