elasticsearch7.8父子结构设计以及mapping映射
设计父子结构
建立index1索引,父:parent,子:child
父包含id, parentName字段(数据:父亲1,父亲2)
子包含id, childName, parentId字段(数据:父亲1有一儿一女,父亲2有一儿)
relation表示关系,名称自定义,type:join 表示父子结构
PUT index1
PUT index1/_mapping
{
"properties": {
"parent": {
"properties": {
"id": {
"type": "integer"
},
"parentName": {
"type": "text"
}
}
},
"child": {
"properties": {
"id": {
"type": "integer"
},
"childName": {
"type": "text"
},
"parentId": {
"type": "integer"
}
}
},
"relation": {
"type": "join",
"relations": {
"parent": [
"child"
]
}
}
}
}
建立父 parent 数据
POST index1/_doc/1
{
"parent.id":1,
"relation":"parent",
"parent.parentName":"父亲1"
}
POST index1/_doc/2
{
"parent.id":2,
"relation":"parent",
"parent.parentName":"父亲2"
}
建立父亲1的子数据
POST index1/_doc/101?routing=1
{
"child.id":101,
"relation":
{
"name":"child",
"parent":1
},
"child.childName":"父亲1的儿子",
"child.parentId":1
}
POST index1/_doc/102?routing=1
{
"child.id":101,
"relation":
{
"name":"child",
"parent":1
},
"child.childName":"父亲1的女儿",
"child.parentId":1
}
建立父亲2的子数据
POST index1/_doc/201?routing=2
{
"child.id":201,
"relation":
{
"name":"child",
"parent":2
},
"child.childName":"父亲2的儿子",
"child.parentId":2
}
测试
#以子查父
GET index1/_search
{
"query": {
"has_child": {
"type": "child",
"query": {
"term": {
"child.parentId": "1"
}
}
}
}
}
#带inner_hits 以子查父,查出父子级联信息
GET index1/_search
{
"query": {
"has_child": {
"type": "child",
"query": {
"term": {
"child.parentId": 1
}
},
"inner_hits": {}
}
}
}
#以父查子
GET index1/_search
{
"query": {
"has_parent": {
"parent_type": "parent",
"query": {
"term": {
"parent.id": "1"
}
}
}
}
}
查询结果:
使用RestHighLevelClient代码查询
// 带子级查询
@Test
public void test1() throws IOException{
SearchRequest searchRequest = new SearchRequest();
searchRequest.indices("index1");
HasChildQueryBuilder qb = JoinQueryBuilders.hasChildQuery(
"child", //要查询的子类型
QueryBuilders.termQuery("child.parentId","1"),
ScoreMode.None
).innerHit(new InnerHitBuilder());
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().query(qb);
searchRequest.source(searchSourceBuilder);
SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
response.getHits().forEach(message->{
System.out.println(message.getSourceAsString());
message.getInnerHits().get("child").forEach(e ->{
System.out.println(e.getSourceAsString());
});
});
}
要注意的细节挺多,父子数据要在一个分配,索引建立子数据,必须设定routing为父id
注意父子结构容易出现的问题是,添加数据时,要注意带上 parent.id 这种关系,否则不会用我们自定义的映射mapping关系,es会自动匹配字段类型,添加完数据一定要 GET index1/_mapping查看结构是否变化了。