면책 조항 :
이것은 꽤 긴 게시물입니다. 먼저 내가 다루는 데이터와이 데이터로 무엇을하고 싶은지 설명합니다.
그런 다음 숙제를 시도했기 때문에 고려한 세 가지 가능한 해결책을 자세히 설명합니다 (저는 맹세합니다 :]). 나는 첫 번째 솔루션의 변형 인 "최상의 추측"으로 끝납니다.
내 궁극적 인 질문은 : 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?!
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] 삭제
몇 마디 만하겠습니다