2017-09-25 129 views
5

我是新來的卡桑德拉和正在尋找如何有這種一般結構如下數據模型中的最佳實踐:最佳實踐模型數據的數據庫

的數據是基於「用戶」(每用戶) ,每個提供大約500K-2M條目的大數據文件(每天定期更新幾次 - 有時全部更新,有時只增量)

每個數據文件都有一定的強制性數據字段(~20強制),但可以根據他們的判斷增加額外的欄目(最多〜100)。

附加數據字段是NOT必然同爲不同用戶(字段的名稱或類型的那些字段的)

實施例(CSV格式:)

user_id_1.csv 

| column1 (unique key per user_id) | column2 | column3 | ... | column10 | additionalColumn1 | ...additionalColumn_n | 
|-----------------------------------|-----------|----------|---------|------------|---------------------|------------------------| 
| user_id_1_key_1     | value | value | value | value  |    ... | value     | 
| user_id_1_key_2     | ....  | .... | .... | ....  |    ... | ...     | 
| ....        | ...  | ...  | ... | ...  |    ... | ...     | 
| user_id_1_key_2Million   | ....  | .... | .... | ....  |    ... | ...     | 


user_id_XXX.csv (notice that the first 10 columns are identical to the other users but the additional columns are different - both the names and their types) 

|    column1 (unique key per user_id)    | column2 | column3 | ... | column10 | additionalColumn1 (different types than user_id_1 and others) | ...additional_column_x | 
|-----------------------------------------------------------|-----------|----------|---------|------------|-----------------------------------------------------------------|-------------------------| 
| user_id_XXX_key_1           | value | value | value | value  |               ... | value     | 
| user_id_XXX_key_2           | ....  | .... | .... | ....  |               ... | ...     | 
| ....              | ...  | ...  | ... | ...  |               ... | ...     | 
| user_id_XXX_key_500_thousand (less rows than other user) | ....  | .... | .... | ....  |               ... | ...     | 

我考慮過的幾個選項:

選項1:

  1. 創建一個「全球性的」密鑰空間
  2. 創建一個大表「數據」包含一切
  3. 連接一個user_id列於所有其他列的大表(包括非強制性列)。主鍵變成USER_ID + 「COLUMN_1」(COLUMN_1爲每USER_ID唯一的)

            Keyspace 
    +--------------------------------------------------------------------------+ 
    |                   | 
    |                   | 
    |          Data_Table       | 
    |    + +--------+-------+--------------------------+-----+ | 
    |    | |  |  |       |  | | 
    |    | +-------------------------------------------------+ | 
    |    | |  |  |       |  | | 
    | many rows | +-------------------------------------------------+ | 
    |    | |  |  |       |  | | 
    |    | |  |  |       |  | | 
    |    | |  |  |       |  | | 
    |    | |  |  |  Many columns   |  | | 
    |    | |  |  +------------------------> |  | | 
    |    | |  |  |       |  | | 
    |    | +-------------------------------------------------+ | 
    |    v +-------------------------------------------------+ | 
    |                   | 
    +--------------------------------------------------------------------------+ 
    

,我注意到馬上有幾件事情:

  1. user_ID的自身重複多次的條目每用戶
  2. 對於其他列(空值爲空值 值),行非常稀疏,因爲用戶不一定共享它們
  3. 用戶數rel atively小,所以許多附加列 的不是很大(10K列最大值)
  4. 我可以每用戶的附加列中的數據壓縮到名爲「元數據」一列,佔所有用戶

分享

選項2:

每密鑰空間

每USER_ID

CREATE TABLE 「數據」 創建密鑰空間個

+-----------------------------------------------------------------------------------+ 
| column_1 | column_2 | ... | column_n | additional_column_1 | additional_column_n | 
+-----------------------------------------------------------------------------------+ 

keyspace_user1   keyspace_user2      keyspace_user_n 
+----------------+ +---------------+     +---------------+ 
|    | |    |     |    | 
|    | |    |     |    | 
| +-+-+--+-+ | | +-+--+--+ |     | +--+--+---+ | 
| | | | | | | | | | | | | many keyspaces | | | | | | 
| | | | | | | | | | | | | +-------------> | | | | | | 
| | | | | | | | | | | | |     | | | | | | 
| | | | | | | | | | | | |     | | | | | | 
| +--------+ | | +-------+ |     | +---------+ | 
+----------------+ +---------------+     +---------------+ 

筆記:

  1. 許多keyspaces(每用戶密鑰空間)
  2. 避免了增加每每一行 「USER_ID」 值(我可以使用密鑰空間名稱作爲用戶ID)
  3. 非常每密鑰空間幾個表(在這個例子中僅每密鑰空間1個表)

選項3:

1)創建一個全局密鑰空間 2)創建每USER_ID的表(強制性列以及每其表及其附加列)

+---------------------------------------------------------------+ 
|       Keyspace       | 
|                | 
|  user_1  user_2       user_n  | 
| +--+---+--+ +--+--+--+      +--+--+--+ | 
| | | | | | | | |      | | | | | 
| | | | | | | | |      | | | | | 
| | | | | | | | |      | | | | | 
| | | | | | | | |      | | | | | 
| | | | | | | | |      | | | | | 
| +--+---+--+ +--+--+--+      +--+--+--+ | 
|                | 
|                | 
+---------------------------------------------------------------+ 

  1. 全局按鍵空間
  2. 每個user_id的表(「許多」表)
  3. 避免重複用戶標識每行

方案四:(這是否有道理?)

創建多個keyspaces(keyspaces的例如 「×」 號)各保持一個範圍的表(每個用戶臺)

     keyspace_1                    keyspace_x 
+---------------------------------------------------------------+       +---------------------------------------------------------------+ 
|                |       |                | 
|                |       |                | 
|  user_1  user_2      user_n/x |       |  user_n-x  user_n-x+1      user_n  | 
| +--+---+--+ +--+--+--+      +--+--+--+ |       | +--+------+ +--+--+--+      +--+--+--+ | 
| | | | | | | | |      | | | | |  "X" keyspaces | | | | | | | | |      | | | | | 
| | | | | | | | |      | | | | | +---------------------> | | | | | | | | |      | | | | | 
| | | | | | | | |      | | | | |       | | | | | | | | |      | | | | | 
| | | | | | | | |      | | | | |       | | | | | | | | |      | | | | | 
| | | | | | | | |      | | | | |       | | | | | | | | |      | | | | | 
| +--+---+--+ +--+--+--+      +--+--+--+ |       | +--+---+--+ +--+--+--+      +--+--+--+ | 
|                |       |                | 
|                |       |                | 
+---------------------------------------------------------------+       +---------------------------------------------------------------+ 

注:

  1. 多keyspaces
  2. 每個用戶多個表
  3. 需要「查找」來確定哪個鍵空間包含所需的表

選項5:

分割數據,以多個表和多個keyspaces

注: 1.需要在某些情況下 2.好像是 「加入」 從多個表中的信息更復雜


一般n所有場景OTES:

  1. 有一個幅度較小的寫入速度比讀取
  2. 數以百萬計的每天讀取每USER_ID
  3. 流量有波動 - 一些user_ids有大量的流量和一些user_ids有少得多交通。需要調整按照該指標
  4. 一些user_ids被更新(寫)的頻率高於其他
  5. 我們擁有跨地域的多個數據中心,並應同步
  6. 沒有每個主鍵的長尾巴(有些鍵訪問許多次,而其他按鍵都很少被訪問)
+0

我是cassandra自己的新手,但選項1對我最有意義。卡桑德拉是爲稀疏列建造的。另外,看看複合主鍵 - PRIMARY KEY(key_part_one,key_part_two)。看看這裏:https://stackoverflow.com/a/24953331/1277048。這爲連接方法的檢索提供了一些靈活性:您可以在一個請求中讀取所有包含key_part_one的行,或者只讀取與(key_part_one,key_part_two)匹配的行。 – FuzzyAmi

+1

列出所有您選擇的查詢,然後根據您的查詢設計您的數據模型。 –

回答

4

這種類型的集成挑戰的通常是通過在關係系統的EAV(實體屬性值)的數據模型來解決(就像Ashrafaul演示的那樣)。考慮EAV模型時的關鍵考慮因素是無限數量的列。 EAV數據模型當然可以在像Cassandra或ScyllaDB這樣的CQL系統中模擬。 EAV模型很適合寫作,但在閱讀時會帶來挑戰。你沒有真正詳細的閱讀考慮。你是否需要返回所有列或者是否需要爲每個用戶返回特定列?

文件

話雖如此,有先天的卡桑德拉和ScyllaDB一些進一步的考慮,可能指向你走向一個統一的EAV模型對一些你在你的問題描述設計的。 Cassandra和ScyllaDB都將密鑰和數據庫作爲文件放在磁盤上。文件的數量基本上是密鑰空間數乘以表的數量的乘積。所以更多的密鑰空間,表格或者兩者的組合,你在磁盤上擁有的文件就越多。這可能是文件描述符和其他os文件雜耍問題的問題。由於您提到的訪問過程很長,可能會出現每個文件始終打開的情況。這並不理想,特別是從冷啓動開始時。

所有情況相同,一個按鍵空間/表總是會產生比許多按鍵空間/表少的文件。這與數據存儲量或壓縮策略無關。

寬行

但要回的數據模型。 Ashraful的模型有一個主鍵(userid)和另一個集羣鍵(key-> column1)。由於每個用戶文件(500K-2M)中的「條目」數量很多,並且假設每個條目都是由60列組成的行,所以您基本上正在爲每個分區鍵創建500k-2m * 60個平均列行創建非常大的分區。 Cassandra和Scylla通常不喜歡非常大的分區。當然,他們可以處理大型分區嗎?實際上,大分區會影響性能,是的。

更新或版本

你提到的更新。基本EAV模型將只代表最近的更新。沒有版本控制。您可以做的是將時間添加爲集羣密鑰,以確保您保持列的歷史價值。

如果希望所有列備份你可以只序列一切都變成JSON對象,並把它放在一列讀取

。但我想象那不是你想要的。在基於鍵/值的系統(如Cassandra和Scylla)的主鍵(分區鍵)模型中,您需要知道鍵的所有組件,才能恢復數據。如果將column1(唯一行標識符)放入主鍵中,則需要事先了解它,同樣也要將其他列名稱也放入主鍵中。

分區和複合分區鍵

分區數決定羣集的並行性。總分區數或總語料庫中分區的基數會影響集羣硬件的利用率。更多分區=更好的並行性和更高的資源利用率。

我在這裏可能會做的是修改PRIMARY KEY以包含column1。然後,我將使用column作爲集羣密鑰(不僅規定分區內的唯一性,還要排序 - 因此請在列命名約定中考慮這一點)。

在下表定義中,您需要在WHERE條款中提供useridcolumn1作爲平等。

CREATE TABLE data (
    userid bigint, 
    column1 text, 
    column text, 
    value text, 
    PRIMARY KEY ((userid, column1), column) 
); 

我也不得不單獨的表,也許columns_per_user,即記錄每個userid所有列。像

CREATE TABLE columns_per_user (
    userid bigint, 
    max_columns int, 
    column_names text 
    PRIMARY KEY (userid) 
); 

哪裏max_columns是列此用戶的總數和column_names東西是實際的列名。您可能還會有一列每個用戶的總條目數,如user_entries int這基本上是每個用戶csv文件中的行數。

+0

這是一個很好的答案。感謝您抽出時間寫下它。我想知道爲什麼(或換句話說 - 目的是什麼)保持列數(max_columns)。 – FuzzyAmi

+0

很好的答案。感謝您抽出寶貴的時間。我的另一個考慮是我們有多個系統訪問這些數據。在某些情況下,每個鍵都會查詢所有列(即select * from table where key = xxx),因此使用包含所有內容的「blob」列是有意義的,而在其他情況下,只有某些列被檢索並「分組」按一定的標準。另外我知道部分數據庫將會非常熱(取決於user_id),而其他數據量將會減少。 –

+0

@FuzzyAmi只是一種便利功能。否則,你必須將完整的json拉出來並進行計數(循環數組,鍵入等) – siculars

0

嘗試下面的模式:

CREATE TABLE data (
    userid bigint, 
    key text, 
    column text, 
    value text, 
    PRIMARY KEY (userid, key) 
); 

這裏

userid -> userid 
key  -> column1 
column -> column name from column2 
value -> column value 

實施例插入用於下面的數據:

| column1 (unique key per user_id) | column2  | column3  | 
|-----------------------------------|---------------|-----------------| 
| key_1        | value12  | value13  | 
| key_2        | value22  | value23  | 

插入語句:

INSERT INTO data (userid , key , column , value) VALUES (1, 'key_1', 'column2', 'value12'); 
INSERT INTO data (userid , key , column , value) VALUES (1, 'key_1', 'column3', 'value13'); 
INSERT INTO data (userid , key , column , value) VALUES (1, 'key_2', 'column2', 'value22'); 
INSERT INTO data (userid , key , column , value) VALUES (1, 'key_2', 'column3', 'value23');