Я довольно n00b в Cassandra (в основном я работаю с РСУБД с некоторыми NoSQL здесь и там, такими как Google BigTable и MongoDB), и я борюсь с моделированием данных для вариантов использования, которые я пытаюсь удовлетворить. Я просмотрел это и это и даже это, но это не совсем то, что мне нужно.
У меня есть эта основная таблица:
CREATE TABLE documents (
itemid_version text,
xml_payload text,
insert_time timestamp,
PRIMARY KEY (itemid_version)
);
itemid
на самом деле является UUID (и уникальным для всех документов), а version
— это int (версия 0 — это «первая» версия). xml_payload
— это полный XML-документ, который может стать довольно большим. Да, по сути, я создаю хранилище документов с версиями.
Как видите, я объединил их для создания первичного ключа, и я объясню, почему я это сделал, позже, когда объясню требования и/или варианты использования:
- пользователю нужно получить один (1) документ, который он хочет, он знает идентификатор элемента и версию (не обязательно самую последнюю)
- пользователю нужно получить один (1) документ, который он хочет, он знает идентификатор элемента, но не знает последнюю версию
- пользователю нужна история версий одного (1) документа.
- пользователю нужно получить список (1 или более) документов, которые он хочет, он знает идентификатор элемента И версию (не обязательно самую последнюю)
Я буду писать клиентский код, который будет выполнять варианты использования, извините за синтаксис, поскольку я пытаюсь быть независимым от языка.
первый простой:
$itemid_version = concat($itemid, $version)
$doc = csql("select * from documents where itemid_version = {0};"
-f $itemid_version)
теперь, чтобы удовлетворить 2-й и 3-й варианты использования, я добавляю следующую таблицу:
CREATE TABLE document_versions (
itemid uuid,
version int,
PRIMARY KEY (itemid, version)
) WITH clustering order by (version DESC);
новые записи будут добавляться по мере создания новых документов и новых версий существующих документов
теперь у нас есть это (вариант использования № 2):
$latest_itemid, $latest_version = csql("select itemid,
version from document_versions where item_id = {0}
order by version DESC limit 1;" -f $itemid)
$itemid_version = concat($latest_itemid, $latest_version)
$doc = csql("select * from documents where itemid_version = {0};"
-f $itemid_version)
и это (вариант использования № 3):
$versions = csql("select version from document_versions where item_id = {0}"
-f $itemid)
для третьего требования я добавляю еще одну таблицу:
CREATE TABLE latest_documents (
itemid uuid,
version int,
PRIMARY KEY (itemid, version)
)
записи вставляются для новых документов, записи обновляются для существующих документов
и теперь у нас есть это:
$latest_itemids, $latest_versions = csql("select itemid, version
from latest_documents where item_id in ({0})" -f $itemid_list.toCSV())
foreach ($one_itemid in $latest_itemids, $one_version in $latest_versions)
$itemid_version = concat($latest_itemid, $latest_version)
$latest_docs.append(
cql("select * from documents where itemid_version = {0};"
-f $itemid_version))
Теперь, надеюсь, понятно, почему я объединил itemid
и version
для создания индекса для documents
, а не для создания составного ключа: у меня не может быть OR
в предложении WHERE
в SELECT
Вы можете предположить, что только один процесс будет выполнять вставки/обновления, поэтому вам не нужно беспокоиться о проблемах согласованности или изоляции.
Я на правильном пути здесь? есть довольно много вещей, которые меня не устраивают... но в основном потому, что я еще не понимаю Кассандру:
- Я чувствую, что первичный ключ для
documents
должен быть составным из (itemid, version), но я не могу удовлетворить вариант использования № 4 (возврат списка из запроса)... Я не могу использовать отдельный оператор SELECT для каждый документ из-за падения производительности (накладные расходы сети)... или можно (должно)? - 2 поездки за документом, если версия неизвестна заранее. возможно, это компромисс, с которым мне приходится жить, или, может быть, есть лучший способ.