Elasticsearch에서 관계 관리

7554 단어 elasticsearch
Elasticsearch 내부 관리 관계 | Elastic
현실 세계에서 데이터는 매우 적고 간단하며 통상적인 상황은 모두 혼란스러운 교차 관계를 가지고 있다.
우리는 어떻게 Elasticsearch에서 문서(데이터) 간의 관계를 표현해야 합니까?여기에는 문서 간의 관계에 대한 지원을 제공할 수 있는 메커니즘이 있다.이러한 메커니즘은 각자의 우세와 열세를 가지고 있으므로 반드시 서로 다른 장면에 따라 적절하게 사용해야 한다.

Inner Objects


가장 간단한 메커니즘은 내부 대상이라고 불린다.다음은 상위 객체에 포함된 JSON 객체입니다.
{
    "name":"Zach",
    "car":{
        "make":"Saturn",
        "model":"SL"
    }
}

간단하죠?car 필드는 makemodel 두 속성을 가진 내부 객체입니다.루트 대상과 내부 대상 간에 일대일 관계에 속할 때 이런 내부 대상의 매핑 관계는 효과적이다.예를 들어 사람마다 최대 1개car가 함유되어 있다.
그러나 Zach 두 개car를 가지고 있고 Bob 한 개car만 있을 때는?
{
    "name" : "Zach",
    "car" : [
        {
            "make" : "Saturn",
            "model" : "SL"
        },
        {
            "make" : "Subaru",
            "model" : "Imprezza"
        }
    ]
}
{
    "name" : "Bob",
    "car" : [
        {
          "make" : "Saturn",
          "model" : "Imprezza"
        }
    ]
}

Saturn사가 Imprezza형 자동차를 생산한 적이 없다는 문제를 무시하고 우리가 ES에서 검색을 시도할 때 어떤 일이 일어날지 고려해 보십시오.Bob만 소유하고 있으므로 다음과 같은 질의를 작성할 수 있습니다.
query: car.make=Saturn AND car.model=Imprezza

이게 맞나?좋아, 이런 조회 결과는 결코 우리가 원하는 대로 되지 않을 거야.만약 이 조회 문장을 실행한다면, 우리는 모든 두 개의 문서를 얻을 것이다.이것은 Elasticsearch가 내부에서 내부 대상을 하나의 대상으로 낮추었기 때문이다.따라서 Saturn Imprezza 이 문서는 실제로 다음과 같습니다.
{
    "name" : "Zach",
    "car.make" : ["Saturn", "Subaru"]
    "car.model" : ["SL", "Imprezza"]
}

이것은 왜 상술한 조회가 그런 결과를 되돌려 주는지 설명한다.ELasticsearch는 근본적으로 납작하게 처리되기 때문에 문서는 내부에서 납작한 필드로 간주됩니다.

Nested


내부 대상의 또 다른 선택으로 Elasticsearch는 플러그인 유형의 개념을 제공했다.중첩된 문서는 문서 차원과 내부 대상은 같지만 내부 대상에 없는 기능을 제공합니다.
중첩된 문서의 예는 다음과 같습니다.
{
    "name" : "Zach",
    "car" : [
        {
            "make" : "Saturn",
            "model" : "SL"
        },
        {
            "make" : "Subaru",
            "model" : "Imprezza"
        }
    ]
}

내포된 유형은 맵 차원에서 명시적으로 선언해야 합니다(내부 객체와 달리 자동으로 감지할 수 있음).
{
    "person":{
        "properties":{
            "name" : {
                "type" : "string"
            },
            "car":{
                "type" : "nested"
            }
        }
    }
}

Inner Objects의 문제는 모든 중첩된 JSON 객체가 문서의 개별 구성 요소로 간주되지 않는다는 것입니다.반대로 다른 Inner Objects와 통합되어 같은 속성 이름을 공유합니다.
이 문제는 Nested 문서에 나타나지 않습니다.모든 Nested 문서는 독립성을 유지하기 때문에 의외의 문제가 발생하지 않도록 사용할 수 있습니다.
Elasticsearch는 근본적으로 여전히 납작하지만, 내부적으로 Nested 관계를 관리하여 끼워 넣는 차원을 나타낼 수 있다.우리가 Nested 문서를 만들 때, Elasticsearch는 실제로 두 개의 독립된 문서 (루트 대상과 중첩 대상) 를 추가한 다음 내부적으로 연결합니다.상기 두 문서는 모두 같은 Shard의 같은 Lucene 블록에 저장되어 읽기 성능이 여전히 매우 빠르다.
이런 안배도 동시에 약간의 폐단을 가져왔다.가장 뚜렷한 것은 우리가 특수한 플러그인 조회를 통해서만 플러그인 문서에 접근할 수 있다는 것이다.또 다른 문제는 우리가 문서의 루트 대상이나 하위 대상에 대한 업데이트 작업을 시도할 때 나타날 것이다.
Nested 문서는 같은 Lucene 블록에 저장되고, Lucene는 단락에 무작위 쓰기를 허용하지 않기 때문에, Nested 문서의 한 필드에 대한 鞥 업데이트 작업은 전체 문서의 인덱스를 재구성할 수 있습니다.
색인 재구성 대상은 수정되지 않았더라도 루트와 중첩된 하위 대상을 포함합니다.내부적으로, Elasticsearch는 문서를 삭제, 업데이트 필드로 표시하고, 문서의 모든 내용을 색인 값의 새로운 Lucene 블록으로 재구성합니다.Nested 문서 데이터가 자주 업데이트되면 인덱스 재구성으로 인한 성능 소모를 무시할 수 없습니다.
또한 Nested 문서 간에 상호 참조를 사용할 수 없습니다.하나의 Nested 객체의 속성은 다른 Nested 객체에 대해 보이지 않습니다.예를 들어 우리는 Zachcar.make=Saturn AND car.model=Imprezza 을 동시에 필터 조건으로 조회할 수 없습니다.실행 가능한 방법은 A.name 를 사용하는 것이다. 그러면 중첩된 문서를 루트로 효율적으로 복사할 수 있지만, 이렇게 되면 문제는 다시 Inner Objects의 상황으로 돌아간다.

Parent/Child


Elasticsearch가 제공하는 마지막 방법은 Parent/Child 유형을 사용하는 것입니다.이런 모델은 Nested 플러그인에 비해 더욱 느슨한 결합에 속하고 우리에게 더욱 강력한 조회 방식을 제공한다.예를 들어 보자. 이 예에서 한 사람은 여러 가정을 가지고 있다.부모 요소에는 일반적으로 다음과 같은 매핑이 있습니다.
{
    "mappings":{
        "person":{
            "name":{
                "type":"string"
            }
        }
    }
}

하위 원소는 부모 원소 외에 자신의 맵핑이 있고 특수한 B.age 속성 집합을 함유하고 있다
{
    "homes":{
        "_parent":{
            "type" : "person"
        },
        "state" : {
            "type" : "string"
        }
    }
}
include_in_root 필드는 Elasticsearch에 _parent 유형 문서가 _parent 유형의 자체 천둥임을 설명합니다.우리는 문서에 이 유형의 데이터를 매우 쉽게 추가할 수 있다.일반적으로 상위 유형 문서를 추가할 수 있습니다.
$ curl -XPUT localhost:9200/test/person/zach/ -d'
{
   "name" : "Zach"
}

하위 유형 문서를 추가하는 것은 일반적인 것과 약간 다릅니다. 요청 매개 변수에서 이 하위 문서가 속하는 상위 문서를 지정해야 합니다(이 예에서는 Employers. 이 값은 위에서 상위 문서를 추가할 때 지정한 문서 ID입니다.
$ curl -XPOST localhost:9200/homes?parent=zach -d'
{
    "state" : "Ohio"
}
$ curl -XPOST localhost:9200/test/homes?parent=zach -d'
{
    "state" : "South Carolina"
}

위의 두 문서는 현재 Person 부모 문서와 연결되어 있습니다. 이로써 다음과 같은 조회를 사용할 수 있습니다.
  • Has Parent 필터링/Has Parent 쿼리, 상위 문서에서 작동하고 하위 문서로 돌아가기
  • Has Child 필터링/Has Child 쿼리, 하위 문서에서 작동하고 상위 문서로 돌아가기
  • Top Children 쿼리, 일치하는 이전 X개의 문서를 반환할 수 있음
  • 하위 요소나 부모 요소는 모두 일등 유형이기 때문에, 우리는 일반적인 상황처럼 단독으로 그것들을 요청할 수 있다. (단지 관계 값을 사용할 수 없다.)
    Nested의 가장 큰 문제는 그 저장에 있다. 같은 요소의 모든 내용은 같은 Lucene 블록에 저장된다.Parent/Child 방식은 양자를 분리하여 느슨하게 결합시켜 이 제한을 제거합니다.이런 방식은 이익도 있고 폐단도 있다.느슨한 결합 방식은 부모 문서나 다른 하위 문서에 영향을 주지 않기 때문에 부모 문서를 자유롭게 업데이트하거나 삭제할 수 있습니다.
    Parent/Child의 단점은 표현 성능이 Nested보다 약간 떨어진다는 것이다.하위 문서는 상위 문서와 같은Shard로 배치되기 때문에 슬라이스 수준의 캐시와 메모리 필터 덕분입니다.그러나 같은 Lucene 블록에 놓여 있지 않기 때문에 Nested 방식에 비해 Parent/Child 방식은 여전히 느리다.이 밖에 이런 방식은 일정한 메모리 부하를 증가시킬 수 있다. 왜냐하면 Elasticsearch는 메모리에 관리 관계의'join table'를 저장해야 하기 때문이다.
    마지막으로, 우리는 정렬과 평점 계산이 상대적으로 어렵다는 것을 발견할 것이다.예를 들어 필터링 조건과 일치하는 문서가 무엇인지 알기 어렵고 부모 문서가 일치하는 문서만 얻을 수 있습니다.어떤 상황에서 이 문제는 상당히 까다로울 것이다.

    역규범화


    때때로 가장 좋은 방법은 적당한 때에 간단하게 데이터의 역규범화를 하는 것이다.Elasticsearch는 특정 상황에서 효과적인 관계 구조 지원을 제공했지만 이것은 우리가 유사한 관계형 데이터베이스 관리 시스템이 제공하는 강한 관계 특성을 사용할 수 있다는 것을 의미하지는 않는다.
    Elasticsearch는 본질적으로 납작한 데이터 구조이기 때문에 관계형 데이터를 사용하려고 시도하는 것은 위험하다.일부 상황에서 데이터를 역규범화(반범식)하고 2차 조회 방식으로 데이터를 얻는 것이 가장 현명한 선택이다.역규범화는 가장 강력하고 유연하다고 할 수 있다.
    물론 이것은 관리 원가를 가져올 것이다.우리는 데이터 간의 관계를 수동으로 관리하고 필요한 조회나 필터 조건을 이용하여 다양한 유형을 연결해야 한다.

    결론과 회고


    이 문서의 내용은 상대적으로 지루하다. 다음은 간단한 회고이다.

    Inner Object

  • 단순성, 신속성, 고성능
  • 일대일 관계에만 작용
  • 추가 조회 불필요
  • Nested

  • Nested 문서는 동일한 Lucene 블록에 저장되므로 동일한 조건에서 Nested의 읽기 성능은 Parent/Child 유형
  • 보다 높음
  • Nested 문서의 루트 요소나 하위 요소를 업데이트하면 ES가 전체 문서를 업데이트할 수 있습니다.내용이 많은 문서의 경우 이 과정의 대가가 크다
  • 교차 참조를 사용할 수 없음
  • 자주 변경되지 않는 문서에 적합
  • Parent/Child

  • 하위 문서는 부모 문서와 별도로 저장되지만 여전히 같은 조각에 있습니다.따라서 Nested보다 조회 효율이 약간 떨어진다
  • ES는 메모리에서 "join"목록을 관리해야 하기 때문에 일부 메모리 부하가 증가합니다
  • 하위 문서 업데이트는 상위 문서나 다른 하위 문서에 영향을 주지 않으며, 이는 큰 문서에서 대량의 인덱스 소모를 잠재적으로 절약할 수 있다
  • Has Child/Has Parent 작업이 보이지 않을 때가 있기 때문에 정렬 및 채점 작업이 어렵습니다
  • 역규범화

  • 모든 관계를 스스로 관리해야 한다
  • 보다 유연하지만 최대 관리 비용
  • 구체적인 설정을 바탕으로 성능이 다소 손실될 수 있음
  • 좋은 웹페이지 즐겨찾기