2013-04-30 45 views
0

我正在研究存儲傳感器測量的應用程序。有時,傳感器會發送錯誤的測量結果(例如測量值超出限制範圍)。我們不希望單獨持續每個測量錯誤,但我們希望保留關於這些錯誤的統計信息,例如傳感器ID,第一個錯誤的日期,最後一個錯誤的日期以及其他信息,例如連續錯誤的數量,我會在這裏省略......我應該如何在Cassandra中存儲日期間隔?

這裏是「ErrorStatistic」類的簡化版本:

package foo.bar.repository; 

import org.joda.time.DateTime; 

import javax.annotation.Nonnull; 
import javax.annotation.Nullable; 

import static com.google.common.base.Preconditions.checkNotNull; 

public class ErrorStatistic { 

    @Nonnull 
    private final String sensorId; 
    @Nonnull 
    private final DateTime startDate; 
    @Nullable 
    private DateTime endDate; 

    public ErrorStatistic(@Nonnull String sensorId, @Nonnull DateTime startDate) { 
     this.sensorId = checkNotNull(sensorId); 
     this.startDate = checkNotNull(startDate); 
     this.endDate = null; 
    } 

    @Nonnull 
    public String getSensorId() { 
     return sensorId; 
    } 

    @Nonnull 
    public DateTime getStartDate() { 
     return startDate; 
    } 

    @Nullable 
    public DateTime getEndDate() { 
     return endDate; 
    } 

    public void setEndDate(@Nonnull DateTime endDate) { 
     this.endDate = checkNotNull(endDate); 
    } 

} 

我使用赫克託如下目前堅持這些ErrorStatistic:

private void persistErrorStatistic(ErrorStatistic errorStatistic) { 
    Mutator<String> mutator = HFactory.createMutator(keyspace, StringSerializer.get()); 

    String rowKey = errorStatistic.getSensorId(); 
    String columnName = errorStatistic.getStartDate().toString(YYYY_MM_DD_FORMATTER); 
    byte[] value = serialize(errorStatistic); 

    HColumn<String, byte[]> column = HFactory.createColumn(columnName, value, StringSerializer.get(), BytesArraySerializer.get()); 
    mutator.addInsertion(rowKey, COLUMN_FAMILY, column); 

    mutator.execute(); 
} 

private static final DateTimeFormatter YYYY_MM_DD_FORMATTER = DateTimeFormat.forPattern("yyyy-MM-dd"); 

當我們收到錯誤的第一個測量值時,我們使用sensorIdstartDate集合創建一個ErrorStatistic,並創建一個空值endDate。這個ErrorStatistic保存在我們的內存模型中,並堅持在Cassandra中。 然後我們更新內存中的ErrorStatistic以進行下一次測量,直到我們收到有效的測量結果,此時ErrorStatistic被持久化並從我們的內存模型中刪除。因此,Cassandra包含具有開放式區間的ErrorStatistics(例如[2012-08-01T00:00Z | null])和閉區間(例如[2012-08-01T00:00Z | 2013-01-12T10:23Z] )。

我希望能夠按日期查詢這些ErrorStatistics。

舉例來說,如果我有這3個錯誤統計:

sensorId = foo 
startDate = 2012-08-01T00:00Z 
endDate = 2012-09-03T02:10Z 

sensorId = foo 
startDate = 2012-10-04T03:12Z 
endDate = 2013-02-01T12:28Z 

sensorId = foo 
startDate = 2013-03-05T23:22Z 
endDate = null 
(this means we have not received a valid measurement since 2013-03-05) 

如果我查詢卡桑德拉的日期:

  • 2012-08-04T10:00Z - >它應該返回第一ErrorStatistic
  • 2012-09-04T00:00Z - >它應返回沒有任何錯誤,此時
  • 2014-01-03T00:00Z - >應該返回最後ErrorStatistic(因爲它是開放的-結束編輯)

我不知道如何存儲和「索引」這些ErrorStatistic對象,以有效地查詢它們。我對卡桑德拉來說很陌生,我可能會錯過一些明顯的東西。


編輯:。以下回應到Joost的建議,我應該專注於我感興趣的查詢類型加入

我將有兩種類型的查詢:

  • 首先,如你所猜,列出所有傳感器和時間範圍內的所有ErrorStatistics。這似乎相對容易。我將遇到的唯一問題是ErrorStatistics在我感興趣的時間範圍之前開始(例如,我查詢四月份的所有錯誤,並且希望我的查詢返回ErrorStatistics [2012-03-29: 2012-04-02]太...)
  • 第二個查詢似乎更難。對於給定的傳感器和日期,我希望找到ErrorStatistics,其間隔包含給定日期,或者在給定日期之前的日期爲startDate,空值爲endDate(這意味着我們仍然收到此傳感器的錯誤)。我不知道如何有效地做到這一點。我可以加載給定傳感器的所有ErrorStatistics,然後檢查Java中的間隔......但是如果可能,我想避免這種情況。我想我想讓Cassandra在給定的日期開始並向後看,直到它找到第一個ErrorStatistics(在給定日期之前的startDate)(如果有的話),然後加載它並檢查Java,如果它的endDatenull或在給定日期之後。但我不知道這是否可能,以及如何有效。

回答

1

您要問自己的問題是您對ErrorStatistics有什麼疑問。 Cassandra模式設計通常以「按表查詢」方式開始。不要從你擁有的數據(實體)開始,而是從你的問題/疑問開始。這與傳統的rdbms設計不同,我發現需要一些時間才能習慣。

例如,是否要查詢每個傳感器的統計信息?比具有複合鍵(傳感器ID,timeuuid)的表可能是一個解決方案。這樣的表格允許根據傳感器ID快速查找,根據時間對結果進行排序。

如果您只想查詢基於時間的傳感器統計信息,則具有時間單位的(複合)鍵可能更有幫助,可能還有分片元素以更好地分佈節點上的負載。請注意,使用Cassandra隨機或雜音分區器時,主鍵上的範圍查詢不可行。還有其他分區程序,但它們很容易導致集羣中的負載分佈不均勻。

總之,從你想要的答案開始,然後向後倒退到你的餐桌設計。有了適當的模式,你的代碼將會隨之而來。


加(2013年9月5日):什麼是好知道的是,卡桑德拉單個分區鍵的範圍之內排序數據。這是非常有用的東西。例如,測量將由START_TIME降序(最新的在前)如果定義一個表作爲有序:

create table SensorByDate 
(
    sensor_id uuid, 
    start_date datetime, 
    end_date datetime, 
    measurement int 
    primary key (sensor_id, start_date) 
) 
with clustering order by (start_time DESC); 

在這個例子中是sensor_id分區鍵和確定該行被存儲在該節點。 start_date是組合鍵中的第二項,並確定排序順序。

爲了得到第一個測量在這個表中的某個開始日期後,你可以制定類似

select * from SensorByDate 
where sensor_id = ? and start_date < ? limit 1 
+0

查詢我喜歡你的設計使用了「每次查詢表」的方法我的架構的想法。作爲一名新的Cassandra用戶,需要一段時間才能習慣它。我將更新我的問題以指定我將感興趣的兩種類型的查詢。 – 2013-05-02 08:46:57

+0

我已經添加了一個可能有助於解決您的問題的示例。 – 2013-05-09 07:55:53