2017-09-25 27 views
5

Tôi mới đến Cassandra và đang tìm kiếm một thực hành tốt nhất về cách để mô hình hóa dữ liệu có chung này cấu như sau:nhất thực hành mô hình dữ liệu cho cơ sở dữ Cassandra

Dữ liệu được "sử dụng" dựa (mỗi khách hàng) , mỗi tệp cung cấp một tệp dữ liệu lớn có dung lượng khoảng 500K-2M (cập nhật định kỳ vài lần một ngày - đôi khi cập nhật đầy đủ và đôi khi chỉ có vùng đồng bằng)

Mỗi tệp dữ liệu có một số trường bắt buộc nhất định (~ 20 bắt buộc) nhưng có thể thêm các cột bổ sung theo quyết định của họ (tối đa ~ 100).

Các thêm trường dữ liệu là KHÔNG nhất thiết giống nhau cho những người sử dụng khác nhau (tên của các trường hoặc các loại của các lĩnh vực)

Ví dụ (định dạng 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) | ....  | .... | .... | ....  |               ... | ...     | 

Một số tùy chọn tôi đã xem xét:

Tùy chọn 1:

  1. Tạo một "toàn cầu" keyspace
  2. Tạo một bảng lớn "dữ liệu" chứa tất cả mọi thứ
  3. CONCATENATE một cột user_id cho tất cả các cột khác vào bảng lớn (bao gồm các cột không bắt buộc).Chìa khóa chính trở nên user_id + "column_1" (column_1 là duy nhất cho mỗi user_id)

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

Một vài điều mà tôi nhận thấy ngay lập tức:

  1. các user_id lặp lại nhiều lần như mục cho mỗi người dùng
  2. Các hàng rất thưa thớt cho các cột bổ sung (giá trị rỗng trống ) vì người dùng không nhất thiết phải chia sẻ chúng
  3. Số người dùng là rel atively nhỏ nên số thêm cột là không lớn (10K cột max)
  4. tôi có thể nhỏ gọn các cột dữ liệu bổ sung cho mỗi người dùng một cột gọi là "siêu dữ liệu" và chia sẻ nó mỗi tất cả người dùng

Phương án 2:

Tạo Keyspace mỗi user_id

Tạo bảng "dữ liệu" mỗi keyspace

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

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

ghi chú:

  1. Nhiều keyspaces (keyspace cho mỗi người dùng)
  2. Tránh thêm "user_id" giá trị cho mỗi hàng (tôi có thể sử dụng tên không gian quan trọng như id người dùng)
  3. Rất vài bảng mỗi keyspace (trong ví dụ này chỉ có 1 bảng mỗi keyspace)

Lựa chọn 3:

1) Tạo một keyspace toàn cầu 2) Tạo một bảng mỗi user_id (các cột bắt buộc cũng như các cột bổ sung của họ cho mỗi bảng của họ)

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

Ghi chú

  1. Phím xóa toàn cầu
  2. Bảng cho mỗi user_id (bảng "nhiều")
  3. Tránh trùng lặp id người dùng mỗi hàng

Tùy chọn 4: (Điều này có hợp lý không?)

Tạo nhiều keyspaces (ví dụ "x" số keyspaces) từng tổ chức một loạt các bảng (bảng cho mỗi người dùng)

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

Ghi chú:

  1. Nhiều keyspaces
  2. Nhiều bảng cho mỗi người dùng
  3. Yêu cầu "tra cứu" để tìm ra không gian phím nào chứa bảng được yêu cầu

Lựa chọn 5:

Chia dữ liệu vào nhiều bảng và nhiều keyspaces

Ghi chú: 1. Yêu cầu "gia nhập" thông tin từ nhiều bảng trong một số trường hợp 2. Có vẻ là phức tạp hơn


Chung n OTES cho tất cả các kịch bản:

  1. Có một mức độ ít viết hơn đọc
  2. Nhiều triệu lượt đọc mỗi ngày
  3. giao thông dao động mỗi user_id - một số user_ids có rất nhiều giao thông và một số user_ids chỉ còn lại ít nhiều giao thông . Sẽ cần phải điều chỉnh mỗi số liệu này
  4. Một số user_ids được cập nhật (viết) thường xuyên hơn những người khác
  5. Chúng tôi có nhiều trung tâm dữ liệu trên toàn khu vực địa lý và cần đồng bộ hóa
  6. Có một cái đuôi dài mỗi khóa chính (một số phím được truy cập nhiều lần trong khi các phím khác hiếm khi truy cập)
+0

Tôi mới làm quen với cassandra, nhưng tùy chọn 1 có ý nghĩa nhất đối với tôi. Cassandra được xây dựng cho các cột thưa thớt. Ngoài ra, có một cái nhìn tại các khóa chính composite - PRIMARY KEY (key_part_one, key_part_two). có một cái nhìn ở đây: https://stackoverflow.com/a/24953331/1277048. điều này cung cấp một số tính linh hoạt trong việc truy xuất phương pháp nối: bạn có thể đọc TẤT CẢ các dòng với key_part_one trong một yêu cầu HOẶC chỉ dòng phù hợp (key_part_one, key_part_two). – FuzzyAmi

+1

Liệt kê tất cả truy vấn chọn của bạn, sau đó thiết kế mô hình dữ liệu của bạn theo truy vấn của bạn. –

Trả lời

4

Đây là loại thách thức hội nhập thường được giải quyết bằng một EAV (Entity Attribute Value) mô hình dữ liệu trong hệ thống quan hệ (giống như người Ashrafaul đã chứng minh). Việc xem xét chính khi xem xét một mô hình EAV là một số cột không bị chặn. Một mô hình dữ liệu EAV có thể, tất nhiên, được bắt chước trong một hệ thống CQL như Cassandra hoặc ScyllaDB. Mô hình EAV có xu hướng độc đáo để viết nhưng trình bày những thách thức khi đọc. Bạn chưa thực sự chi tiết những cân nhắc đã đọc của mình. Bạn có cần tất cả các cột trở lại hay bạn cần các cột cụ thể cho mỗi người dùng?

tập tin

Có nói rằng, có một số cân nhắc thêm vốn để Cassandra và ScyllaDB có thể chỉ cho bạn hướng tới một mô hình EAV thống nhất qua một số các mẫu thiết kế mà bạn mô tả trong câu hỏi của bạn. Cả Cassandra và ScyllaDB đều bố trí các không gian và cơ sở dữ liệu dưới dạng tệp trên đĩa. Số lượng các tập tin về cơ bản là các sản phẩm của số lượng không gian bàn phím số lần bảng. Vì vậy, các không gian chính, bảng hoặc kết hợp của hai bạn có, càng có nhiều tệp bạn sẽ có trên đĩa. Điều này có thể là một vấn đề với các bộ mô tả tập tin và các vấn đề juggling file os khác. Do đuôi truy cập dài mà bạn đã đề cập đến có thể là trường hợp mọi tệp đều mở cửa mọi lúc. Đó không phải là mong muốn, đặc biệt là khi bắt đầu từ một khởi động lạnh.

[sửa cho rõ ràng] Tất cả mọi thứ là như nhau, một keyspace/table sẽ luôn luôn tạo ra các file nhỏ hơn nhiều keyspace/bảng. Điều này không liên quan gì đến số lượng dữ liệu được lưu trữ hoặc chiến lược nén chặt.

Hàng Wide

Nhưng việc trở lại mô hình dữ liệu. Mô hình của Ashraful có khóa chính (userid) và một khóa phân cụm khác (key-> column1). Do số lượng "mục" trong mỗi tệp người dùng (500K-2M) và giả sử mỗi mục nhập là một hàng bao gồm các cột avg 60, những gì bạn đang làm là tạo các cột 500k-2m * 60 avg cho mỗi khóa phân vùng tạo phân vùng rất lớn. Cassandra và Scylla thường không thích những phân vùng rất lớn. Họ có thể xử lý các phân vùng lớn, chắc chắn. Trong thực tế, các phân vùng lớn tác động đến hiệu suất, vâng.

cập nhật hoặc versioning

Bạn đề cập đến bản cập nhật. Mô hình EAV cơ sở sẽ chỉ đại diện cho bản cập nhật mới nhất. Không có phiên bản. Những gì bạn có thể làm là thêm thời gian làm khóa phân cụm để đảm bảo rằng bạn duy trì các giá trị lịch sử của các cột theo thời gian.

Đọc

Nếu bạn muốn tất cả các cột sao bạn chỉ có thể serialize tất cả mọi thứ vào một đối tượng JSON và đặt nó trong một cột duy nhất. Nhưng tôi tưởng tượng đó không phải là những gì bạn muốn. Trong khóa chính (khóa phân vùng) của một hệ thống dựa trên khóa/giá trị như Cassandra và Scylla, bạn cần biết tất cả các thành phần của khóa để lấy lại dữ liệu của bạn. Nếu bạn đặt column1, số nhận dạng hàng duy nhất, vào khóa chính của bạn, bạn sẽ cần phải biết trước, cũng như các tên cột khác nếu chúng cũng được đặt trong khóa chính.

phân vùng và phân vùng phím composite

Số phân vùng dictate xử lý song song của cluster của bạn. Số lượng tổng số phân vùng, hoặc cardinality của phân vùng trong tổng corpus của bạn, có ảnh hưởng đến việc sử dụng phần cứng cụm của bạn. Thêm phân vùng = tốt hơn song song và sử dụng tài nguyên cao hơn.

Điều tôi có thể làm ở đây là sửa đổi PRIMARY KEY để bao gồm column1. Sau đó, tôi sẽ sử dụng column làm khóa phân cụm (không chỉ quy định tính duy nhất trong phân vùng mà còn sắp xếp thứ tự - vì vậy hãy xem xét điều này trong các quy ước đặt tên cột).

Trong định nghĩa bảng sau, bạn cần phải cung cấp số useridcolumn1 làm số dư trong mệnh đề WHERE của mình.

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

Tôi cũng muốn có một bảng riêng biệt, có lẽ columns_per_user, ghi lại tất cả các cột cho mỗi userid. Một cái gì đó như

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

đâu max_columns là tổng số cột cho người dùng này và column_names là tên cột thực tế. Bạn cũng có thể có một cột cho tổng số mục nhập cho mỗi người dùng, giống như user_entries int mà về cơ bản sẽ là số hàng trong mỗi tệp csv của người dùng.

+0

Đây là một câu trả lời hay. cảm ơn đã dành thời gian để viết nó. Tôi tự hỏi tại sao (hoặc, nói cách khác - mục đích là gì) giữ số cột (max_columns). – FuzzyAmi

+0

Câu trả lời hay. Cảm ơn đã dành thời gian. Một xem xét khác tôi có là chúng tôi có nhiều hệ thống truy cập dữ liệu này. Trong một số trường hợp, tất cả các cột được truy vấn theo một khóa (chọn * từ bảng có khóa = xxx), do đó có thể sử dụng cột "blob" chứa mọi thứ trong khi trong các trường hợp khác, chỉ một số cột được truy xuất và "nhóm" theo tiêu chí nhất định. Ngoài ra tôi biết rằng các phần của DB sẽ rất nóng (tùy thuộc vào user_id) trong khi những phần khác sẽ ít hơn. –

+0

@FuzzyAmi Chỉ là một chức năng tiện lợi. Nếu không, bạn sẽ phải rút hết số lượng json ra và thực hiện đếm (lặp qua mảng, khóa, v.v.) – siculars

0

Thử Sơ đồ dưới đây:

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

đây

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

Ví dụ Insert cho dưới đây dữ liệu:

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

Chèn Bản Tuyên Bố:

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'); 
Các vấn đề liên quan