Join Query
Elasticsearch에서 JOIN은 문서 간의 관계를 설정하고 이를 통해 문서를 연결하여 검색할 수 있는 기능입니다. 단, Elasticsearch의 JOIN은 RDBMS와 달리 성능에 영향을 미칠 수 있습니다. 특히, has_child or has_parent 쿼리는 성능에 부담을 줄 수 있으므로, 데이터 모델링 시 신중히 고려해야 합니다.
Parent-Child 관계
Parent-Child 관계는 한 문서가 부모가 되고, 다른 문서가 자식이 되는 구조입니다. 이 관계는 인덱스 내에서 설정되며, 부모와 자식 문서는 반드시 같은 샤드에 저장되어야 합니다.
- has_child 쿼리: 자식 문서가 특정 조건을 만족할 때 부모 문서를 반환합니다.
- has_parent 쿼리: 부모 문서가 특정 조건을 만족할 때 자식 문서를 반환합니다.
Join 데이터 타입
Elasticsearch 6.x부터는 Join 데이터 타입을 사용하여 Parent-Child 관계를 설정할 수 있습니다. 이 타입은 문서 내에서 가능한 관계 집합을 정의하며, 각 관계는 부모 이름과 자식 이름으로 구성됩니다.
다음 library 인덱스는 부모(author)-자식(book) 관계를 가집니다.
PUT /library
{
"mappings": {
"properties": {
"my_join_field": {
"type": "join",
"relations": {
"author": "book" // Define 'author' as parent and 'book' as child
}
},
"name": { "type": "text" }, // Common field for names
"title": { "type": "text" }, // Field for book titles
"genre": { "type": "keyword" }, // Field for book genres
"year": { "type": "integer" } // Field for publication year
}
}
}
부모 Documents를 생성합니다.
POST /library/_doc/1
{
"my_join_field": "author", // Indicating this is a parent document
"name": "J.K. Rowling"
}
POST /library/_doc/2
{
"my_join_field": "author", // Indicating this is a parent document
"name": "George R.R. Martin"
}
자식 Documents를 생성합니다. 부모와 자식 문서는 반드시 같은 샤드에 저장되어야 하기 때문에 부모 문서의 ID를 자식 문서의 routing 값으로 사용합니다. (Elasticsearch에서 문서를 저장할 때 기본적으로 문서의 ID를 해싱하여 샤드를 결정합니다. 그러므로 부모 문서를 저장할 때는 별도의 라우팅 값을 지정하지 않아도 됩니다.)
POST /library/_doc/3?routing=1
{
"my_join_field": {
"name": "book",
"parent": "1" // Link to the parent author (J.K. Rowling)
},
"title": "Harry Potter and the Philosopher's Stone",
"genre": "Fantasy",
"year": 1997
}
POST /library/_doc/4?routing=1
{
"my_join_field": {
"name": "book",
"parent": "1" // Link to the parent author (J.K. Rowling)
},
"title": "Harry Potter and the Chamber of Secrets",
"genre": "Fantasy",
"year": 1998
}
POST /library/_doc/5?routing=2
{
"my_join_field": {
"name": "book",
"parent": "2" // Link to the parent author (George R.R. Martin)
},
"title": "A Game of Thrones",
"genre": "Fantasy",
"year": 1996
}
POST /library/_doc/6?routing=2
{
"my_join_field": {
"name": "book",
"parent": "2" // Link to the parent author (George R.R. Martin)
},
"title": "A Clash of Kings",
"genre": "Fantasy",
"year": 1998
}
has_parent 쿼리
GET /library/_search
{
"query": {
"has_parent": {
"parent_type": "author",
"query": {
"match": {
"name": "J.K. Rowling"
}
}
}
}
}
has_child 쿼리
GET /library/_search
{
"query": {
"has_child": {
"type": "book",
"query": {
"match": {
"title": "Game"
}
}
}
}
}
GET /library/_search
{
"query": {
"has_child": {
"type": "book",
"query": {
"term": {
"genre": "Fantasy"
}
}
}
}
}
Parent ID로 Child 문서 검색
GET /library/_search
{
"query": {
"parent_id": {
"type": "book",
"id": 1
}
}
}
Inner Hit
GET /library/_search
{
"query": {
"has_parent": {
"inner_hits": {},
"parent_type": "author",
"query": {
"match": {
"name": "J.K. Rowling"
}
}
}
}
}
GET /library/_search
{
"query": {
"has_child": {
"inner_hits": {},
"type": "book",
"query": {
"match": {
"title": "Game"
}
}
}
}
}
[참고자료]