Cassandra에서 버전이 지정된 계층의 효율적인 모델링

올리비에 랜스

면책 조항 :
이것은 꽤 긴 게시물입니다. 먼저 내가 다루는 데이터와이 데이터로 무엇을하고 싶은지 설명합니다.
그런 다음 숙제를 시도했기 때문에 고려한 세 가지 가능한 해결책을 자세히 설명합니다 (저는 맹세합니다 :]). 나는 첫 번째 솔루션의 변형 인 "최상의 추측"으로 끝납니다.

내 궁극적 인 질문은 : Cassandra를 사용하여 내 문제를 해결하는 가장 현명한 방법 무엇입니까? 내 시도 중 하나입니까, 아니면 다른 것입니까?
숙련 된 Cassandra 사용자로부터 조언 / 피드백을 찾고 있습니다.

내 데이터 :
트리 구조 (제목, 부제목, 섹션,…)의 문서를 소유하는 많은 SuperDocuments가 있습니다.

각 SuperDocument 구조는 시간이 지남에 따라 변경 될 수 있으므로 (대부분 제목의 이름 변경) 아래와 같이 여러 버전의 구조를 제공합니다.

수퍼 문서 버전

내가 찾는 것 :
각 SuperDocument에 대해 위와 같이 날짜별로 해당 구조의 타임 스탬프를 지정해야하며 주어진 날짜에 대해 가장 가까운 이전 버전의 SuperDocument 구조를 찾고 싶습니다. (예 : 가장 최근 버전 version_date < given_date)

이러한 고려 사항은 문제를보다 쉽게 ​​해결하는 데 도움이 될 수 있습니다.

  • 버전은 불변입니다. 변경은 거의 없으며 변경 될 때마다 전체 구조의 새로운 표현을 만들 수 있습니다.
  • 구조의 하위 트리에 액세스 할 필요가 없습니다.
  • 주어진 잎의 모든 조상을 찾을 필요가없고 나무 안의 특정 노드 / 잎에 접근 할 필요도 없다고 말하는 것이 괜찮다고 말하고 싶습니다. 전체 트리를 확보하면 클라이언트 코드에서이 모든 작업을 수행 할 수 있습니다.

좋아, 해보자. 나는 정말 카산드라를 사용하기 시작했다는 것을 명심 해라
. 데이터 모델링에 대한 많은 리소스를 읽거나 봤지만 현장에서 많은 (아무것도!) 경험이 없습니다!
그것은 또한 모든 것이 CQL3로 작성된다는 것을 의미합니다 ... 죄송합니다 Thrift 애호가!

이 문제를 해결하기위한 첫 번째 시도는 다음 표를 만드는 것이 었습니다.

CREATE TABLE IF NOT EXISTS superdoc_structures (
    doc_id varchar,
    version_date timestamp,
    pre_pos int,
    post_pos int,
    title text,

    PRIMARY KEY ((doc_id, version_date), pre_pos, post_pos)

) WITH CLUSTERING ORDER BY (pre_pos ASC);

그러면 다음과 같은 구조가됩니다.

여기에 이미지 설명 입력

여기 내 나무에 Nested Sets 모델사용하고 있습니다. 나는 구조를 순서대로 유지하는 것이 잘 작동 할 것이라고 생각했지만 다른 제안에 열려 있습니다.

이 솔루션이 마음에 듭니다. 각 버전에는 고유 한 행이 있으며 각 열은 계층 수준을 나타냅니다.
하지만 문제는 내가 (솔직히) 내 데이터를 다음과 같이 쿼리하려고한다는 것입니다.

SELECT * FROM superdoc_structures 
    WHERE doc_id="3399c35...14e1" AND version_date < '2014-03-11' LIMIT 1

카산드라는 내가 그렇게 할 수 없다는 것을 재빨리 상기시켰다! (파티 셔 너가 클러스터 노드에서 행 순서를 유지하지 않기 때문에 파티션 키를 통해 스캔 할 수 없습니다)

그럼 ...?
글쎄, Cassandra는 파티션 키에 부등식을 사용하도록 허용하지 않기 때문에 그렇게하십시오! 클러스터링 키를
만들면 version_date모든 문제가 사라질 것입니다. 그래,별로 ...

첫 시도:

CREATE TABLE IF NOT EXISTS superdoc_structures (
    doc_id varchar,
    version_date timestamp,
    pre_pos int,
    post_pos int,
    title text,

    PRIMARY KEY (doc_id, version_date, pre_pos, post_pos)

) WITH CLUSTERING ORDER BY (version_date DESC, pre_pos ASC);

나는 이것이 덜 우아하다고 생각합니다. 모든 버전 구조 수준은 이전 솔루션과 비교하여 이제 매우 넓은 행의 열로 만들어집니다.

두 번째 모델링 시도

Problem: with the same request, using LIMIT 1 will only return the first heading. And using no LIMIT would return all versions structure levels, which I would have to filter to only keep the most recent ones.

Second try:

there's no second try yet... I have an idea though, but I feel it's not using Cassandra wisely.

The idea would be to cluster by version_date only, and somehow store whole hierarchies in each column values. Sounds bad doesn't it?

I would do something like this:

CREATE TABLE IF NOT EXISTS superdoc_structures (
    doc_id varchar,
    version_date timestamp,
    nested_sets map<int, int>,
    titles list<text>,

    PRIMARY KEY (doc_id, version_date)

) WITH CLUSTERING ORDER BY (version_date DESC);

The resulting row structure would then be:

세 번째 모델링 시도

It looks kind of all right to me in fact, but I will probably have more data than the level title to de-normalize into my columns. If it's only two attributes, I could go with another map (associating titles with ids for instance), but more data would lead to more lists, and I have the feeling it would quickly become an anti-pattern.
Plus, I'd have to merge all lists together in my client app when the data comes in!

ALTERNATIVE & BEST GUESS
After giving it some more thought, there's an "hybrid" solution that might work and may be efficient and elegant:

I could use another table that would list only the version dates of a SuperDocument & cache these dates into a Memcache instance (or Redis or whatever) for real quick access.
That would allow me to quickly find the version I need to fetch, and then request it using the composite key of my first solution.

That's two queries, plus a memory cache store to manage. But I may end up with one anyway, so maybe that'd be the best compromise?
Maybe I don't even need a cache store?

All in all, I really feel the first solution is the most elegant one to model my data. What about you?!

Christopher Smith

First, you don't need to use memcache or redis. Cassandra will give you very fast access to that information. You could certainly have a table that was something like:

create table superdoc_structures {
    doc_id varchar;
    version_date timestamp;
    /* stuff */
    primary key (doc_id, version_date)
} with clustering order by (version_date desc);

which would give you a quick way to access a given version (this query may look familiar ;-):

select * from superdoc_structures 
    where doc_id="3399c35...14e1" and
        version_date < '2014-03-11'
    order by version_date desc
    limit 1;

Since nothing about the document tree structure seems to be relevant from the schema's point of view, and you are happy as a clam to create the document in its entirety every time there is a new version, I don't see why you'd even bother breaking out the tree in to separate rows. Why not just have the entire document in the table as a text or blob field?

create table superdoc_structures {
    doc_id varchar;
    version_date timestamp;
    contents text;
    primary key (doc_id, version_date)
} with clustering order by (version_date desc);

So to get the contents of the document as existed at the new year, you'd do:

select contents from superdoc_structures
where doc_id="...." and 
    version_date < '2014-01-1'
order by version_date > 1

Now, if you did want to maintain some kind of hierarchy of the document components, I'd recommend doing something like a closure table table to represent it. Alternatively, since you are willing to copy the entire document on each write anyway, why not copy the entire section info on each write, why not do so and have a schema like:

create table superdoc_structures {
    doc_id varchar;
    version_date timestamp;
    section_path varchar;
    contents text;
    primary key (doc_id, version_date, section_path)
) with clustering order by (version_date desc, section_path asc);

Then have section path have a syntax like, "first_level next_level sub_level leaf_name". As a side benefit, when you have the version_date of the document (or if you create a secondary index on section_path), because a space is lexically "lower" than any other valid character, you can actually grab a subsection very cleanly:

select section_path, contents from superdoc_structures
where doc_id = '....' and
    version_date = '2013-12-22' and
    section_path >= 'chapter4 subsection2' and
    section_path < 'chapter4 subsection2!';

또는 컬렉션에 대한 Cassandra의 지원을 사용하여 섹션을 저장할 수 있지만 다시 한 번 ... 하나의 큰 덩어리가 잘 작동하기 때문에 섹션을 분리하는 데 왜 신경 쓰는지 모르겠습니다.

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

서비스 계층과 도메인 모델 계층의 차이점은 무엇입니까

목록에서 연결된 모든 정수 쌍의 합계를 찾는 효율적인 알고리즘

Java에서 이미지의 효율적인 색상 순환

유형 계층 구조에 대한 언어 지원없이 관련 항목의 계층 구조 모델링

Cassandra의 계층 적 엔티티 모델링

데이터 프레임의 특정 값 합계에 대한 효율적인 리샘플링

icCube에서 계층 구조 멤버의 누적 % 계산 | TopPercent이지만 다름

이항 실험의 베이지안 계층 적 모델링을위한 rstanarm

Python에서 특정 값의 이미지의 모든 픽셀을 계산하는 효율적인 방법은 무엇입니까?

Stan에서 비선형 성장 곡선 모델의 계층 적 버전 개발

모델의 훈련 된 계층에서 추출 된 특징 벡터를 이미지로 표시

Mongoose 모델, 효율적인 어레이 정리 / 파싱

파이썬의 베타 이항 분포에서 효율적인 샘플링

람다 계층에서로드 될 때 서버리스 오프라인 정의되지 않은 모듈

PySide2 / QML 지정된 루트 인덱스에서 계층 적 데이터 필터링

긴 배열의 모든 회전에 대한 메모리 및 시간 효율적인 정렬

사전 훈련 된 DistilBERT 모델의 여러 계층 출력에 액세스

Django에서 관련 모델의 효율적인 개수

단일 지점에서 많은 지점의 모든 지점까지의 거리를 측정하는 효율적인 방법이 있습니까?

Java에서 메모리 효율적인 파일 / 이미지 업로드?

지정된 셀의 이웃을 찾는 효율적인 방법?

회전 된 이미지의 모든 360도에 대해 (높이에서) 노멀 맵을 생성하는 효율적인 방법

부울 대수와 전달 된 인수를 사용하여 CUDA에서 유사한 커널의 두 버전을 구현하는 것이 효율적입니까?

Laravel의 BLADE 컬렉션에서 특정 모델을 얻는 가장 효율적인 방법

이전에 정의 된 문자열 집합과 일치하는 문자열의 모든 접두사를 가져 오는 효율적인 구조

지정된 경계 내에서 무작위 목록을 만드는 효율적인 방법이 있습니까?

반복 측정에서 데이터를 집계하는 효율적인 방법

R의 모집단 데이터 프레임에서 비율 샘플링(계층화된 샘플링의 무작위 샘플링)

SQL이 아닌 데이터베이스에서 관계를 효율적으로 모델링

TOP 리스트

  1. 1

    PrematureCloseException : 연결이 너무 일찍 닫혔습니다.

  2. 2

    MDRotatingPieChart를 회전하면 각도 대신 x / y 위치가 변경됩니다.

  3. 3

    c # 웹 사이트에서 텍스트를 복사하는 방법 (소스 코드 아님)

  4. 4

    jfreecharts에서 x 및 y 축 선을 조정하는 방법

  5. 5

    ArrayBufferLike의 typescript 정의의 깊은 의미

  6. 6

    Ionic 2 로더가 적시에 표시되지 않음

  7. 7

    복사 / 붙여 넣기 비활성화

  8. 8

    Google Play Console에서 '예기치 않은 오류가 발생했습니다. 나중에 다시 시도해주세요. (7100000)'오류를 수정하는 방법은 무엇입니까?

  9. 9

    정점 셰이더에서 카메라에서 개체까지의 XY 거리

  10. 10

    QT Designer를 사용하여 GUI에 이미지 삽입

  11. 11

    java Apache POI Word 기존 테이블 셀 스타일 및 서식이있는 행 삽입

  12. 12

    Kubernetes Horizontal Pod Autoscaler (HPA) 테스트

  13. 13

    Android Kotlin은 다른 활동에서 함수를 호출합니다.

  14. 14

    C # HttpWebRequest 기본 연결이 닫혔습니다. 전송시 예기치 않은 오류가 발생했습니다.

  15. 15

    어떻게 같은 CustomInfoWindow 다른 이벤트를 할 수 있습니다

  16. 16

    rclone으로 원격 디렉토리의 모든 파일을 삭제하는 방법은 무엇입니까?

  17. 17

    dataSnapShot.getValue () 반환 데이터베이스에 그겁니다 데이터 종료 널 (null)

  18. 18

    ORA-12557 TNS : 프로토콜 어댑터를로드 할 수 없습니다

  19. 19

    JNDI를 사용하여 Spring Boot에서 다중 데이터 소스 구성

  20. 20

    다음 컨트롤이 추가되었지만 사용할 수 없습니다.

  21. 21

    C # Asp.net 웹 API-JSON / XML 변환기 API 만들기

뜨겁다태그

보관