Elasticsearch 의 데이터 모델링은 관계형 데이터베이스를 다룰 때만큼 명확하지 않습니다. 데이터 정규화 및 SQL 조인에 의존하는 기존 관계형 데이터베이스와 달리 Elasticsearch에는 관계 관리를 위한 대체 접근 방식이 필요합니다.
Elasticsearch에서 관계를 관리하는 데는 네 가지 일반적인 해결 방법이 있습니다.
애플리케이션 측 조인
데이터 비정규화
중첩된 필드 유형 및 중첩된 쿼리
부모-자식 관계
이 블로그에서는 중첩 필드 유형과 상위-하위 관계를 사용하여 관계를 처리하도록 데이터 모델을 설계하는 방법에 대해 설명합니다. 우리는 이 두 기술의 아키텍처, 성능 영향 및 사용 사례를 다룰 것입니다.
Elasticsearch는 객체가 다른 객체를 포함할 수 있는 중첩 구조를 지원합니다. 중첩된 필드 유형은 기본 문서 내의 JSON 개체로, 고유한 필드와 유형을 가질 수 있습니다. 이러한 중첩 개체는 중첩 쿼리를 통해서만 액세스할 수 있는 별도의 숨겨진 문서로 처리됩니다.
중첩 필드 유형은 데이터 무결성, 긴밀한 결합 및 계층 구조가 중요한 관계에 매우 적합합니다. 여기에는 하나의 주요 엔터티가 있는 일대일 관계와 일대다 관계가 포함됩니다. 예를 들어, 단일 문서 내에서 한 사람과 그 사람의 여러 주소 및 전화번호를 나타냅니다.
중첩된 필드 유형을 사용하면 Elasticsearch는 전체 문서는 물론 상위 개체와 중첩 개체도 단일 Lucene 블록 및 세그먼트에 저장합니다. 관계가 문서에 포함되어 있으므로 쿼리 속도가 더 빨라질 수 있습니다.
댓글이 달린 블로그 게시물의 예를 살펴보겠습니다. 동일한 문서에서 쉽게 함께 쿼리할 수 있도록 블로그 게시물 아래에 댓글을 중첩하려고 합니다.
{ "post_id": "1", "title": "Introduction to Elasticsearch Data Modeling", "content": "Exploring various data modeling options in Elasticsearch.", "comments": [ { "comment_id": "101", "text": "Great overview of data modeling!" }, { "comment_id": "102", "text": "Looking forward to more content." } ] }
중첩된 개체 관계의 이점은 다음과 같습니다.
업데이트 비효율성 : 중첩된 개체가 있는 문서의 일부를 업데이트, 삽입 및 삭제 하려면 전체 문서를 다시 색인화해야 하며, 이는 특히 문서가 크거나 업데이트가 빈번한 경우 메모리를 많이 소모할 수 있습니다.
큰 중첩 필드가 있는 쿼리 성능 : 특히 큰 중첩 필드가 있는 문서가 있는 경우 이는 성능에 영향을 미칠 수 있습니다. 이는 검색 요청이 전체 문서를 검색하기 때문입니다.
여러 수준의 중첩이 복잡해질 수 있음 : 여러 수준의 중첩 구조에서 쿼리를 실행하는 것은 여전히 복잡할 수 있습니다. 이는 쿼리가 중첩된 쿼리 내에 중첩된 쿼리를 포함할 수 있어 읽기 어려운 코드로 이어질 수 있기 때문입니다.
상위-하위 매핑에서는 문서가 상위 및 하위 유형으로 구성됩니다. 각 하위 문서는 상위 문서와 직접적인 연관이 있습니다. 이 관계는 상위 ID와 일치하는 하위 문서의 특정 필드 값을 통해 설정됩니다. 상위-하위 모델은 상위 및 하위 문서가 독립적으로 존재하는 분산형 접근 방식을 채택합니다.
상위-하위 조인은 엔터티 간의 일대다 또는 다대다 관계에 적합합니다. 회사와 연락처 간의 관계를 생성하고 회사와 연락처는 물론 특정 회사의 연락처를 검색하려는 애플리케이션을 상상해 보십시오.
Elasticsearch는 어떤 상위가 어떤 하위에 연결되어 있는지 추적하고 두 엔터티가 모두 동일한 샤드에 상주하도록 하여 상위-하위 조인의 성능을 향상시킵니다. Elasticsearch는 조인 작업을 현지화함으로써 성능 병목 현상이 발생할 수 있는 광범위한 샤드 간 통신의 필요성을 방지합니다.
블로그 게시물과 댓글에 대한 부모-자식 관계의 예를 들어보겠습니다. 각 블로그 게시물(즉, 상위 항목)에는 여러 댓글(즉, 하위 항목)이 있을 수 있습니다. 부모-자식 관계를 생성하려면 다음과 같이 데이터를 색인화해 보겠습니다.
PUT my-index-000001 { "mappings": { "properties": { "post_id": { "type": "keyword" }, "post_id": { "type": "join", "relations": { "post": "comment" } } } } }
상위 문서는 다음과 같은 게시물입니다.
{ "post_id": "1", "title": "Introduction to Elasticsearch Data Modeling", "content": "Exploring various data modeling options in Elasticsearch." }
그러면 하위 문서는 상위 문서에 연결되는 post_id가 포함된 주석이 됩니다.
{ "comment_id": "101", "text": "Great overview of data modeling!", "post_id": "1" }
부모-자식 모델링의 이점은 다음과 같습니다.
관계형 데이터 모델과 유사 : 상위-하위 관계에서 상위 및 하위 문서는 분리되어 있으며 고유한 상위 ID로 연결됩니다. 이 설정은 관계형 데이터베이스 모델에 더 가깝고 이러한 개념에 익숙한 사람들에게는 더 직관적일 수 있습니다.
업데이트 효율성 : 상위 문서나 다른 하위 문서에 영향을 주지 않고 하위 문서를 추가, 수정, 삭제할 수 있습니다. 이는 자주 업데이트해야 하는 다수의 하위 문서를 처리할 때 특히 유용합니다. 하위 문서를 다른 상위 문서와 연결하는 것은 새 상위 문서가 다른 샤드에 있을 수 있으므로 더 복잡한 프로세스입니다.
이질적인 하위 항목에 더 적합 : 하위 문서는 별도로 저장되므로 특히 크기 차이가 큰 하위 문서가 많은 경우 메모리 및 저장 효율성이 더 높을 수 있습니다.
부모-자식 관계의 단점은 다음과 같습니다.
비용이 많이 들고 느린 쿼리 : 별도의 인덱스에 걸쳐 문서를 결합하면 쿼리 실행 중에 계산 작업이 추가되어 성능에 다시 영향을 미칩니다. Elasticsearch에서는 상위-하위 쿼리가 중첩된 개체를 쿼리하는 것보다 5~10배 느릴 수 있다고 지적합니다.
매핑 오버헤드 : 상위-하위 관계는 더 많은 메모리와 캐시 리소스를 소비할 수 있습니다. Elasticsearch는 특히 대용량 문서의 경우 규모가 커지고 상당한 메모리를 소비할 수 있는 상위-하위 관계 맵을 유지 관리합니다.
샤드 크기 관리 : 상위 문서와 하위 문서가 모두 동일한 샤드에 상주하므로 클러스터 전체에 데이터가 고르지 않게 분산될 위험이 있습니다. 특히 하위 문서가 많은 상위 문서가 있는 경우 일부 샤드가 다른 샤드보다 상당히 커질 수 있습니다. 이는 Elasticsearch 클러스터를 관리하고 확장하는 데 어려움을 겪을 수 있습니다.
재인덱싱 및 클러스터 유지 관리 : 데이터를 재인덱싱하거나 샤딩 전략을 변경 해야 하는 경우 상위-하위 관계로 인해 이 프로세스가 복잡해질 수 있습니다. 그러한 작업 중에 관계 무결성이 유지되는지 확인해야 합니다. 샤드 재분배 또는 노드 업그레이드와 같은 일상적인 클러스터 유지 관리 작업은 더욱 복잡해질 수 있습니다. 이러한 과정에서 부모-자녀 관계가 중단되지 않도록 특별한 주의를 기울여야 합니다.
Elasticsearch를 지원하는 회사인 Elastic은 항상 상위-하위 관계 경로를 따라가기 전에 애플리케이션 측 조인, 데이터 비정규화 및/또는 중첩 개체를 수행할 것을 권장합니다.
아래 표에서는 데이터 모델링 접근 방식을 나란히 비교할 수 있도록 중첩된 필드 유형과 쿼리 및 상위-하위 관계의 특성을 요약하여 제공합니다.
| 중첩된 필드 유형 및 중첩된 쿼리 | 부모-자식 관계 |
---|---|---|
정의 | 다른 개체 내에 개체를 중첩합니다. | 상위 문서와 하위 문서를 함께 연결합니다. |
관계 | 일대일, 일대다 | 일대다, 다대다 |
쿼리 속도 | 데이터가 동일한 블록 및 세그먼트에 저장되므로 일반적으로 상위-하위 관계보다 빠릅니다. | 쿼리 시 상위 문서와 하위 문서가 결합되므로 일반적으로 중첩된 개체보다 5~10배 느립니다. |
쿼리 유연성 | 쿼리 범위를 중첩된 각 개체의 범위 내로 제한하므로 부모-자식 쿼리보다 유연성이 떨어집니다. | 상위 또는 하위 문서를 함께 또는 별도로 쿼리할 수 있으므로 쿼리에 더 많은 유연성을 제공합니다. |
데이터 업데이트 | 중첩된 개체를 업데이트하려면 전체 문서를 다시 색인화해야 합니다. | 모든 문서를 다시 색인화할 필요가 없으므로 하위 문서 업데이트가 더 쉽습니다. |
관리 | 모든 것이 하나의 문서에 포함되므로 관리가 더욱 간편해집니다. | 상위 문서와 하위 문서 간의 관계를 별도로 인덱싱하고 유지 관리하기 때문에 관리가 더욱 복잡해졌습니다. |
사용 사례 | 여러 수준의 계층 구조로 복잡한 데이터를 저장하고 쿼리합니다. | 제품, 상품평 등 부모는 적고 자녀는 많은 관계 |
Elasticsearch는 중첩 쿼리 및 상위-하위 관계를 포함하여 SQL 스타일 조인 에 대한 여러 가지 해결 방법을 제공하지만 이러한 모델은 확장이 잘 되지 않는 것으로 확인되었습니다. 대규모 애플리케이션을 설계할 때 기본 SQL 조인 기능을 갖춘 대체 접근 방식인 Rockset을 고려하는 것이 합리적일 수 있습니다.
Rockset은 깊게 중첩된 JSON 데이터를 포함하여 모든 데이터에 대한 SQL 검색, 집계 및 조인을 위해 설계된 검색 및 분석 데이터베이스입니다. 데이터가 Rockset으로 스트리밍되면 빠른 검색을 위해 데이터를 저장하고 색인화하는 데 사용되는 데이터베이스의 핵심 데이터 구조로 인코딩됩니다. Rockset은 SQL 기반 쿼리 최적화 프로그램을 사용하여 조인을 포함한 빠른 쿼리를 허용하는 방식으로 데이터를 인덱싱합니다. 결과적으로 SQL 조인을 지원하는 데 필요한 사전 데이터 모델링이 없습니다.
Elasticsearch의 과제 중 하나는 데이터가 업데이트될 때 효율적인 방식으로 관계를 유지하는 방법입니다. 그 이유 중 하나는 Elasticsearch가 Apache Lucene을 기반으로 구축되었기 때문입니다. Apache Lucene은 데이터를 변경할 수 없는 세그먼트에 저장하므로 모든 문서를 다시 색인화해야 합니다. Rockset은 Meta에서 오픈 소스로 제공하고 데이터 변형을 위해 구축된 키-값 저장소인 RocksDB를 사용하여 전체 문서를 다시 색인화할 필요 없이 필드 수준 업데이트를 효율적으로 지원할 수 있습니다.
Elasticsearch의 부모-자식 관계 접근 방식을 Rockset의 SQL 쿼리 와 비교해 보겠습니다.
위의 상위-하위 관계 예에서는 두 가지 문서 유형을 생성하여 여러 댓글이 있는 게시물을 모델링했습니다.
게시물 또는 상위 문서 유형
주석 또는 하위 문서 유형
우리는 상위 문서와 하위 문서 간의 관계를 설정하기 위해 고유 식별자인 상위 ID를 사용했습니다. 쿼리 시 Elasticsearch DSL을 사용하여 특정 게시물에 대한 댓글을 검색합니다.
Rockset에서는 게시물이 포함된 데이터가 관계형 세계의 테이블인 하나의 컬렉션에 저장되는 반면, 댓글이 포함된 데이터는 별도의 컬렉션에 저장됩니다. 쿼리 시 SQL 쿼리를 사용하여 데이터를 결합합니다.
다음은 두 가지 접근 방식을 나란히 나열한 것입니다.
POST /blog/posts/1 { "title": "Elasticsearch Modeling", "content": "A post about data modeling in Elasticsearch" } POST /blog/comments/2?parent=1 { "text": "Great post!" } POST /blog/comments/3?parent=1 { "text": "I learned a lot from this." }
제목과 모든 댓글을 기준으로 게시물을 검색하려면 다음과 같이 쿼리를 만들어야 합니다.
GET /posts/_search { "query": { "bool": { "must": [ { "match": { "title": "Exploring Elasticsearch Models" } } ] } }, "inner_hits": { "_source": ["text"], "name": "comments", "path": "comments" } }
그런 다음 이 데이터를 쿼리하려면 간단한 SQL 쿼리를 작성하면 됩니다.
SELECT p.title, p.content, c.text FROM posts p JOIN comments c ON p.post_id = c.post_id WHERE p.post_id = 1;
애플리케이션에 결합해야 하는 데이터 세트가 여러 개인 경우 Rockset은 Elasticsearch보다 더 간단하고 확장 가능합니다. 또한 데이터를 리모델링하거나, 업데이트를 관리하거나, 작업을 다시 색인화할 필요가 없으므로 작업이 단순화됩니다.
이 블로그에서는 귀하의 워크로드에 가장 적합한 데이터 모델링 접근 방식을 결정하는 데 도움을 주기 위해 Elasticsearch의 중첩 필드 유형, 중첩 쿼리, 상위-하위 관계에 대한 개요를 제공했습니다.
중첩된 필드 유형 및 쿼리는 단일 문서 내에서 관계가 유지되는 일대일 또는 일대다 관계에 유용합니다. 이는 관계 관리에 대한 더 간단하고 확장 가능한 접근 방식으로 간주됩니다.
상위-하위 관계 모델은 일대다 대 다대다 관계에 더 적합하지만 특히 관계가 특정 분할에 포함되어야 하기 때문에 복잡성이 증가합니다.
애플리케이션의 주요 요구 사항 중 하나가 관계 모델링이라면 Rockset을 고려하는 것이 합리적일 수 있습니다. Rockset은 데이터 모델링을 단순화하고 SQL 조인을 사용하여 관계 관리에 대한 보다 확장 가능한 접근 방식을 제공합니다. 지금 $300 크레딧으로 무료 평가판을 시작 하면 Elasticsearch와 Rockset의 성능을 비교하고 대조할 수 있습니다.