5.x 이전의 도큐먼트 간 parent - child 구조
Elasticsearch 에서는 도큐먼트들 간에 연결을 맺을 수 있는 몇가지 기능들을 제공하고 있습니다. 대표적으로는 nested type 이 있으며, 5.x 이전 버전에서는 parent-child 구조의 정의를 할 수 있었습니다.
5.x 이전의 parent - child 구조는 인덱스 내부의 타입을 parent, 그리고 child 타입으로 나눠서 생성하고 child 에 속한 도큐먼트들이 색인될 때 해당 도큐먼트의 parent 를 명시 해서 저장하는 방식으로 사용했습니다. 자세한 내용은 아래를 문서를 참고하세요.
https://www.elastic.co/guide/en/elasticsearch/reference/5.6/mapping-parent-field.html#_parent_child_restrictions
다음은 stackoverflow
라는 인덱스에 question
타입과 answer
타입을 각각 parent - child 구조로 저장 한 예제 입니다.{
"stackoverflow": {
"mappings": {
"question": {
"properties": {
"accepted_answer_id": {
"type": "long"
}
... 중략 ...
}
},
"answer": {
"_parent": {
"type": "question"
},
"_routing": {
"required": true
},
"properties": {
"id": {
"type": "keyword"
}
}
}
}
}
}
6.x 에서의 join 데이터 타입 설정
6.0 부터는 한 인덱스에 하나의 타입만 생성할 수 있도록 강제됩니다. 그래서 parent - child 구조는 더 이상 사용이 불가능하고, 대신 join 이라는 데이터 타입을 이용해서 도큐먼트들 간의 관계를 정의하게 됩니다. join 데이터 타입에 대해서는 아래 문서를 참고합니다.
https://www.elastic.co/guide/en/elasticsearch/reference/6.1/parent-join.html
먼저 관계를 설정하기 위한 join 필드를 새로 추가합니다. 저는 qna_join
이라는 필드를 join 필드로 설정했습니다.PUT stackoverflow
{
"mappings": {
"doc": {
"properties": {
"qna_join": {
"type": "join",
"relations": {
"question": "answer"
}
}
}
}
}
}
그리고 question 도큐먼트에는 qna_join
필드 안의 name
값을 question
으로, answer 도큐먼트에는 answer
와 parent에 해당하는 question 도큐먼트의 id 값을 넣어줍니다.POST stackoverflow/doc/25691276?routing=25691276
{
"title": "Import CSV into MySQL - Offset by 1 Column",
"accepted_answer_id": 25691509,
... 중략 ...
"id": 25691276,
"view_count": 15,
"qna_join": {
"name": "question"
}
}
POST stackoverflow/doc/25691509?routing=25691276
{
"comment_count": 0,
"owner": {
"location": "Sao Paulo, Brazil",
"id": 3337405,
"display_name": "vinibarr"
},
"comments": [],
"creation_date": "2014-09-05T18:01:23.033",
"id": 25691509,
"body": """
<p>You can load your data specifing the order columns that you're going to use into your table:
... 중략 ...
""",
"qna_join": {
"name": "answer",
"parent":"25691276"
}
}
중요한 것은 parent, child 두개 도큐먼트는 항상 동일한 routing 값을 넣어줘야 합니다. 같은 routing 값을 가진 도큐먼트는 같은 샤드에 저장이 됩니다.
이렇게 저장한 후 has_parent
쿼리를 이용해서 question
도큐먼트의 id 필드 값을 이용해서 그 도큐먼트와 연결된 answer
도큐먼트를 가져오는 쿼리를 실행 해 봅니다.GET stackoverflow/_search
{
"query": {
"has_parent": {
"parent_type": "question",
"query": {
"term": {
"id": {
"value": "25691276"
}
}
}
}
}
}
위 쿼리를 실행하면 아래와 같이 answer
도큐먼트를 결과로 가져옵니다.{
"took": 12,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 1,
"hits": [
{
"_index": "stackoverflow",
"_type": "doc",
"_id": "25691509",
"_score": 1,
"_routing": "1",
"_source": {
"comment_count": 0,
"owner": {
"location": "Sao Paulo, Brazil",
"id": 3337405,
"display_name": "vinibarr"
},
"comments": [],
"creation_date": "2014-09-05T18:01:23.033",
"id": 25691509,
"body": """
<p>You can load your data specifing the order columns that you're going to use into your table:
... 중략 ...
""",
"qna_join": {
"name": "answer",
"parent": "25691276"
}
}
}
]
}
}
Logstash 색인 설정
이제 5.x 에서 parent - child 타입으로 나뉘어 있던 데이터를 6.x 로 재 색인을 해야 합니다. 먼저 데이터를 타입별로 구분해야 하므로 저는 question 타입과 answer 타입의 데이터들을 각각 /Users/kimjmin/elastic/source/stackoverflow/
경로 아래에 question.json
, answer.json
이라는 파일들로 저장 했습니다.
이제 logstash 설정 파일을 작성하겠습니다. path 로 부터 파일 이름에 있는 question
그리고 answer
를 추출하여 qna_join.name
에 해당하는 값을 넣어주도록 했습니다.
우선 파일 이름을 기준으로 question
, answer
태그를 만들도록 합니다.
input { |
현재 구성중인 stackoverflow 는 parent가 question, child 가 answer 구조로 되어 있습니다. 하지만 도큐먼트 내용을 보면 question 도큐먼트에는 answer 도큐먼트와 연결되는 accepted_answer_id
필드가 있지만 answer 에는 question 도큐먼트를 확인하는 필드가 없습니다. answer 도큐먼트가 색인 될 때 연결되는 question 도큐먼트의 id 값을 가져오기 위해 Logstash 의 filter 내부에 elasticsearch
필터를 추가합니다.
https://www.elastic.co/guide/en/logstash/6.1/plugins-filters-elasticsearch.html
filter { |
이제 데이터를 elasticsearch로 저장하도록 output 을 입력합니다. parent - child 구조의 도큐먼트는 같은 샤드에 저장하기 위해 항상 같은 rounting 값을 적어줘야 합니다. routing 값을 question 도큐먼트의 id 값인 question_id
필드 값으로 지정합니다. 만약에 stackoverflow 인덱스에 샤드가 1개만 있다고 하면 routing 에 모든 도큐먼트에 적용되는 임의의 값을 넣어도 됩니다.
output { |
이제 데이터를 색인합니다.
중요! 반드시
question
도큐먼트들을 먼저 색인 한 뒤에answer
도큐먼트들을 색인해야 합니다.
데이터 색인이 끝난 뒤 앞에서 실행했던 has_parent
쿼리를 이용해서 데이터가 정상적으로 나오는지 확인 해 봅니다.
GET stackoverflow/_search |
이처럼 join
타입의 필드를 사용해서 과거처럼 parent-child 구조를 만들 수 있으며, logstash의 elasticsearch
필터를 사용해서 데이터를 색인할 때 elasticsearch 에 있는 데이터를 가져와서 도큐먼트에 추가할 수 있습니다.