2016-05-27 4 views
1

Я хочу создать таблицу с фиксированным количеством строк (скажем, N), где, если добавлена ​​N + 1-я строка, тогда 1-я строка будет удалена.Cassandra: Исправлено количество строк в таблице

Это таблица, я использую для хранения последних N лучших результатов анализа графика:

CREATE TABLE IF NOT EXISTS lp_registry.best (
    value float, // best value for current graph 
    verts int, // number of vertices in graph 
    edges int, // number of edges in graph 
    wid text, // worker id  
    id timeuuid, // timeuuid 
    PRIMARY KEY (wid, id) 
) WITH CLUSTERING ORDER BY (id ASC); 

Я читал о expiring data at DataStax, но нашел только TTL истечение срока. Поэтому я решил сделать это следующим образом.

Мой подход:

Everytime новый результат хотел добавить, идентификатор старейшей строки извлекается ..

SELECT wid, id FROM lp_registry.best LIMIT 1; 

..as также текущее число строк ..

SELECT COUNT(*) FROM FROM lp_registry.best; 

Следовательно, если число> = N, то самая старая строка удаляется, а новейший добавляются ...

BEGIN BATCH 
    INSERT INTO lp_registry.best (value, verts, edges, wid, id) VALUES (?, ?, ?, ? now()); 
    DELETE FROM lp_registry.best WHERE wid = ? AND id = ?; 
APPLY BATCH; 

Этот подход имеет проблему с тем, что первые селекции не являются атомарными операциями вместе со следующей партией. Поэтому, если какой-либо другой рабочий удалил старую строку между select и batch или N был превышен, это не сработает.

Мой подход B:

Те же первые шаги ...

SELECT wid, id FROM lp_registry.best LIMIT 1; 
SELECT COUNT(*) FROM FROM lp_registry.best; 

Затем попытайтесь не удалить старую строку снова и снова, пока успех ..

if count < N { 
    INSERT INTO lp_registry.best (value, verts, edges, wid, id) VALUES (?, ?, ?, ? now()); 
} else { 
    while not success { 
    DELETE FROM lp_registry.best WHERE wid = ? AND id = ? IF EXISTS; 
    } 
    INSERT INTO lp_registry.best (value, verts, edges, wid, id) VALUES (?, ?, ?, ? now()); 
} 

В этом подходе все еще есть проблемы с превышением N в базе данных, прежде чем подсчет < N проверяется.

Можете ли вы указать мне правильное решение?

+0

Один простой вопрос: зачем вам это нужно? Возможно, другой подход - лучший вариант для вашего случая использования. –

+0

Существует много параллельных компьютеров (рабочих), каждый из которых выполняет одинаковые вычисления для разных данных, а время вычисления сильно варьируется. Затем существует логика верхнего уровня, которая принимает N последних результатов и выполняет вычисления с ней. – Michal

ответ

1

Это мое решение. Сначала нам нужно создать таблицу, которая будет хранить текущее число строк ...

CREATE TABLE IF NOT EXISTS row_counter (
    rmax int, // maximum allowed number of rows 
    rows int, // current number of rows 
    name text, // name of table 
    PRIMARY KEY (name) 
); 

Затем его инициализации для данного фиксированных строк таблиц:

INSERT INTO row_counter (name, rmax, rows) 
VALUES ('best', 100, 0); 

Эти заявления, используемые в следующий код:

q1 = "SELECT rows, rmax FROM row_counter WHERE name = 'best'"; 
q2 = "UPDATE row_counter SET rows = ? WHERE name = 'best' IF rows < ?"; 
q3 = "SELECT wid, id FROM best LIMIT 1"; 
q4 = "DELETE FROM best WHERE wid = ? AND id = ? IF EXISTS"; 
q5 = "INSERT INTO best (vertex, value, verts, edges, wid, id) VALUES (?, ?, ?, ?, ?, now())"; 

selectCounter = session.prepare(q1); 
updateCounter = session.prepare(q2); 
selectOldBest = session.prepare(q3); 
deleteOldBest = session.prepare(q4); 
insertNewBest = session.prepare(q5); 

Решение в Java:

// Success indicator 
boolean succ = false; 

// Get number of registered rows in the table with best results 
Row row = session.execute(selectCounter.bind()).one(); 
int rows = row.getInt("rows") + 1; 
int rmax = row.getInt("rmax"); 

// Repeatedly try to reserve empty space in table 
while (!succ && rows <= rmax) { 
    succ = session.execute(updateCounter.bind(rows, Math.min(rows, rmax))).wasApplied(); 
    rows = session.execute(selectCounter.bind()).one().getInt("rows") + 1; 
} 

// If there is not empty space in table, repeatedly try to make new empty space 
while (!succ) { 
    row = session.execute(selectOldBest.bind()).one(); 
    succ = session.execute(deleteOldBest.bind(row.getString("wid"), row.getUUID("id"))).wasApplied(); 
} 

// Insert new row 
session.execute(insertNewBest.bind(vertex, value, verts, edges, workerCode));