elasticsearch 關聯查詢

父-子關係文檔html

父-子關係文檔 在實質上相似於 nested model :容許將一個對象實體和另一個對象實體關聯起來。 而這兩種類型的主要區別是:在 nested objects 文檔中,全部對象都是在同一個文檔中,而在父-子關係文檔中,父對象和子對象都是徹底獨立的文檔。java

父-子關係的主要做用是容許把一個 type 的文檔和另一個 type 的文檔關聯起來,構成一對多的關係:一個父文檔能夠對應多個子文檔 。與 nested objects 相比,父-子關係的主要優點有:es6

更新父文檔時,不會從新索引子文檔。
建立,修改或刪除子文檔時,不會影響父文檔或其餘子文檔。這一點在這種場景下尤爲有用:子文檔數量較多,而且子文檔建立和修改的頻率高時。
子文檔能夠做爲搜索結果獨立返回。
Elasticsearch 維護了一個父文檔和子文檔的映射關係,得益於這個映射,父-子文檔關聯查詢操做很是快。可是這個映射也對父-子文檔關係有個限制條件:父文檔和其全部子文檔,都必需要存儲在同一個分片中。app

我使用的是es5.6,es6.0版本以上一個索引對應一個type
1.在es中查詢父子級關係elasticsearch

建立父子級關係ide

PUT user_test
{
  "mappings": {
    "dept": {
      "properties": {
        "dname":{
          "type": "text"
        }
      }
    },
    "user":{
      "_parent": {
        "type": "dept"
      }, 
      "properties": {
        "deptId":{
          "type": "text"
        },
        "username":{
          "type": "text"
        },
        "age":{
          "type": "integer"
        }
      }
    }
  }
}

 

建立了一個公司的索引 包括部門和用戶兩個類型ui

新增一個父級數據es5

POST company/dept/2
{
  "dname":"開發部"
}

新增一個子級數據spa

POST company/user?parent=2
{
  "uid":"1",
  "uname":"王五",
  "age":10  
  
}

以子級查code

GET company/user/_search
{
  "query": {
    "has_parent": {
      "parent_type": "dept",
      "query": {
        "term": {
          "dname":""
        }
      },"inner_hits":{}
    }
  }
}

以父級查

GET company/dept/_search
{
  "query": {
    "has_child": {
      "type": "user",
      "query": {
        "match": {
          "uname":"里斯"
        }
      },"inner_hits":{}
    }
  }
}
用inner_hits則能夠把父子文檔同時返回——既返回,不加inner_hits只返回一個type裏的數據。inner_hits默認只查詢3條數據,能夠自定義設置from 和size。
若是父子級同時有查詢條件,用bool做爲複合查詢
GET company/dept/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "dname": {
              "value": ""
            }
          }
        },{
          "has_child": {
            "type": "user",
            "query": {
              "match": {
                "uname":""
              }
            },"inner_hits":{}
          }
        }
        
      ]
    }
  }
}

 

2.java項目中查詢

實體類

1.部門

@Document(indexName = "user_test",type = "dept")
public class Department {
    @Id
    private String id;
    private String dname;
}

2.用戶

@Document(indexName = "user_test",type = "user")
public class User {
    @Id
    private String id;
    @Parent(type = "dept")
    private String deptId;
    private String uname;
    private Integer age;
}

 

 

使用ElasticsearchTemplate

1查詢父級數據

QueryBuilder qb=JoinQueryBuilders.hasChildQuery("user",QueryBuilders.matchAllQuery(),ScoreMode.None);
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withIndices("user_test")
                .withQuery(qb)
                .build();
        List<Department> depts= elasticsearchTemplate.queryForList(searchQuery,Department.class);
ScoreMode:評分模式,,,或minmaxsumavgnone

2.查詢子級數據

QueryBuilder qb=JoinQueryBuilders.hasParentQuery("dept",QueryBuilders.matchQuery("dname","開"),false);
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withIndices("user_test")
                .withQuery(qb)
                .build();
        List<User> users= elasticsearchTemplate.queryForList(searchQuery,User.class);

 評分功能:這has_parent也有得分支持。默認值是false忽略父文檔的分數

 官方參考:https://www.elastic.co/guide/en/elasticsearch/reference/5.6/query-dsl-has-parent-query.html

查詢父子級所有數據

 QueryBuilder qb = JoinQueryBuilders.hasChildQuery(
                "user",                         //要查詢的子類型
                QueryBuilders.matchQuery("uname.keyword","張三"),
                ScoreMode.None
        ).innerHit(new InnerHitBuilder());
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withIndices("user_test")
                .withQuery(qb)
                .build();
        List<DeptVO> depts= elasticsearchTemplate.query(searchQuery, searchResponse -> {
            SearchHits hits = searchResponse.getHits();
            List<DeptVO> list = new ArrayList<>();
            Arrays.stream(hits.getHits()).forEach(h -> {
                Map<String, Object> source = h.getSource();
                SearchHits innerHitsMap=h.getInnerHits().get("user");//獲取子級數據
                List<User> user1s=Arrays.stream(innerHitsMap.getHits()).map(innerH -> {
                    Map<String, Object> innerSource = innerH.getSource();
                    return new User(innerSource.get("uname").toString(),Integer.valueOf(innerSource.get("age").toString()));
                }).collect(Collectors.toList());
                list.add(new DeptVO(source.get("dname").toString(),user1s));
            });
            return list;
        });
JoinQueryBuilders.hasChildQuery().innerHit(new InnerHitBuilder())的.innerHit(new InnerHitBuilder())與es查詢同樣
相關文章
相關標籤/搜索