Làm cách nào để lưu trữ Google ngrams tốt nhất trong cơ sở dữ liệu?


9

Tôi đã tải xuống google onegram vài ngày trước và nó đã là một lượng dữ liệu khổng lồ. Tôi đã chèn gói đầu tiên trong số 10 gói vào mysql và bây giờ tôi có cơ sở dữ liệu kỷ lục 47 triệu.

Tôi tự hỏi làm thế nào một người nên lưu trữ Google ngrams trong cơ sở dữ liệu tốt nhất. Ý tôi là, nếu bạn không sử dụng onegram, nhưng ví dụ như twogram hoặc ba gram thì số tiền sẽ lớn hơn nhiều. Tôi có thể lưu trữ 500 triệu bản ghi trong một cơ sở dữ liệu và làm việc với nó hay tôi nên chia nó thành các bảng khác nhau?

Sau bao nhiêu bản ghi nên chia nó ra và làm thế nào để phân tách nó tốt nhất (xem xét rằng twogram có 100 tệp và do đó có lẽ khoảng 5 tỷ bản ghi)? Có nên sử dụng phân vùng ngang MySQL hay xây dựng phân vùng riêng của mình (ví dụ: thông qua ký tự đầu tiên của word => twograms_a).

Câu trả lời:


4

Có rất nhiều thay đổi tôi sẽ phải thực hiện cho câu trả lời đầu tiên của mình, tôi bắt đầu cái này !!!

USE test
DROP TABLE IF EXISTS ngram_key;
DROP TABLE IF EXISTS ngram_rec;
DROP TABLE IF EXISTS ngram_blk;
CREATE TABLE ngram_key
(
    NGRAM_ID UNSIGNED BIGINT NOT NULL AUTO_INCREMENT,
    NGRAM VARCHAR(64) NOT NULL,
    PRIMARY KEY (NGRAM),
    KEY (NGRAM_ID)
) ENGINE=MyISAM ROW_FORMAT=FIXED PARTITION BY KEY(NGRAM) PARTITIONS 256;
CREATE TABLE ngram_rec
(
    NGRAM_ID UNSIGNED BIGINT NOT NULL,
    YR SMALLINT NOT NULL,
    MC SMALLINT NOT NULL,
    PC SMALLINT NOT NULL,
    VC SMALLINT NOT NULL,
    PRIMARY KEY (NGRAM_ID,YR)
) ENGINE=MyISAM ROW_FORMAT=FIXED;
CREATE TABLE ngram_blk
(
    NGRAM VARCHAR(64) NOT NULL,
    YR SMALLINT NOT NULL,
    MC SMALLINT NOT NULL,
    PC SMALLINT NOT NULL,
    VC SMALLINT NOT NULL
) ENGINE=BLACKHOLE;
DELIMITER $$
CREATE TRIGGER populate_ngram AFTER INSERT ON ngram_blk FOR EACH ROW
BEGIN
    DECLARE NEW_ID BIGINT;

    INSERT IGNORE INTO ngram_key (NGRAM) VALUES (NEW.NGRAM);
    SELECT NGRAM_ID INTO NEW_ID FROM ngram_key WHERE NGRAM=NEW.NGRAM;
    INSERT IGNORE INTO ngram_rec VALUES (NEW_ID,NEW.YR,NEW.MC,NEW.PC,NEW.VC);
END; $$
DELIMITER ;
INSERT INTO ngram_blk VALUES
('rolando',1965,31,29,85),
('pamela',1971,33,21,86),
('dominique',1996,30,18,87),
('diamond',1998,13,28,88),
('rolando edwards',1965,31,29,85),
('pamela edwards',1971,33,21,86),
('dominique edwards',1996,30,18,87),
('diamond edwards',1998,13,28,88),
('rolando angel edwards',1965,31,29,85),
('pamela claricia edwards',1971,33,21,86),
('dominique sharlisee edwards',1996,30,18,87),
('diamond ashley edwards',1998,13,28,88);
UPDATE ngram_rec SET yr=yr+1,mc=mc+30,pc=pc+30,vc=vc+30;
INSERT INTO ngram_blk VALUES
('rolando',1965,31,29,85),
('pamela',1971,33,21,86),
('dominique',1996,30,18,87),
('diamond',1998,13,28,88),
('rolando edwards',1965,31,29,85),
('pamela edwards',1971,33,21,86),
('dominique edwards',1996,30,18,87),
('diamond edwards',1998,13,28,88),
('rolando angel edwards',1965,31,29,85),
('pamela claricia edwards',1971,33,21,86),
('dominique sharlisee edwards',1996,30,18,87),
('diamond ashley edwards',1998,13,28,88);
UPDATE ngram_rec SET yr=yr+1,mc=mc+30,pc=pc+30;
INSERT INTO ngram_blk VALUES
('rolando',1965,31,29,85),
('pamela',1971,33,21,86),
('dominique',1996,30,18,87),
('diamond',1998,13,28,88),
('rolando edwards',1965,31,29,85),
('pamela edwards',1971,33,21,86),
('dominique edwards',1996,30,18,87),
('diamond edwards',1998,13,28,88),
('rolando angel edwards',1965,31,29,85),
('pamela claricia edwards',1971,33,21,86),
('dominique sharlisee edwards',1996,30,18,87),
('diamond ashley edwards',1998,13,28,88);
UPDATE ngram_rec SET yr=yr+1,mc=mc+30;
SELECT * FROM ngram_key;
SELECT * FROM ngram_rec;
SELECT A.ngram NGram,B.yr Year,B.mc Matches,B.pc Pages,B.vc Volumes FROM 
ngram_key A,ngram_rec B
WHERE A.ngram='rolando angel edwards'
AND A.ngram_id=B.ngram_id;

Các bảng nhỏ hơn nhiều cho thông tin năm nhưng các phím lớn hơn nhiều để giữ ngram gốc. Tôi cũng tăng số lượng dữ liệu thử nghiệm. Bạn có thể cắt và dán trực tiếp vào MySQL.

CAUPAT

Chỉ cần xóa ROW_FORMAT và nó sẽ trở thành dymanic và nén các bảng ngram_key nhỏ hơn rất nhiều.


Số liệu của DiskSpace

nrgram_rec có 17 byte mỗi hàng
8 byte cho ngram_id (giá trị không dấu tối đa 18446744073709551615 [2 ^ 64 - 1])
8 byte cho 4 gợi ý nhỏ (mỗi byte 2 byte)
1 cờ xóa nội bộ MyISAM

Mục nhập mục tiêu cho ngram_rec = 10 byte (8 (ngram_id) + 2 (năm)

47 triệu hàng X 17 byte mỗi hàng = 0799 triệu byte = 761.98577 MB
47 triệu hàng X 12 byte mỗi hàng = 0564 triệu byte = 537.85231 MB
47 triệu hàng X 29 byte mỗi hàng = 1363 triệu byte = 1.269393 GB

5 tỷ hàng X 17 byte mỗi hàng = 085 tỷ byte = 079.1624 GB
5 tỷ hàng X 12 byte mỗi hàng = 060 tỷ byte = 055.8793 GB
5 tỷ hàng X 29 byte mỗi hàng = 145 tỷ byte = 135.0417 GB


ngram_key có 73 byte 64 byte cho ngram (ROW_FORMAT = FIXED đặt varchar thành char) 8 byte cho ngram_id 1 byte cờ xóa nội bộ MyISAM

2 mục nhập chỉ mục cho ngram_key = 64 byte + 8 byte = 72 byte

47 triệu hàng X 073 byte mỗi hàng = 3431 triệu byte = 3.1954 GB
47 triệu hàng X 072 byte mỗi hàng = 3384 triệu byte = 3.1515 GB
47 triệu hàng X 145 byte mỗi hàng = 6815 triệu byte = 6.3469 GB

5 tỷ hàng X 073 byte mỗi hàng = 365 tỷ byte = 339.9327 GB
5 tỷ hàng X 072 byte mỗi hàng = 360 tỷ byte = 335.2761 GB
5 tỷ hàng X 145 byte mỗi hàng = 725 tỷ byte = 675.2088 GB


Cảm ơn vì hai câu trả lời tuyệt vời. Tôi tò mò, lý do của việc sử dụng phương pháp kích hoạt + lỗ đen này để điền vào bảng là gì?
Dolan Antenucci

Các lỗ đen chấp nhận ngram gốc. Trình kích hoạt tạo ra một cơ chế INSERT IGNORE sạch để phân chia ngram khỏi giá trị auto_increment.
RolandoMySQLDBA

3

Đây là một gợi ý khá hoang dã

Chuyển đổi tất cả ngrams thành các phím MD5 32 ký tự

Bảng này sẽ chứa tất cả các ngram có kích thước bất kỳ (tối đa 255 ký tự), 1 gram, 2 gram, v.v.

use test
DROP TABLE ngram_node;
DROP TABLE ngram_blackhole;
CREATE TABLE ngram_node
(
  NGRAM_KEY  CHAR(32) NOT NULL,
  NGRAM_YEAR SMALLINT NOT NULL,
  M_COUNT    SMALLINT NOT NULL,
  P_COUNT    SMALLINT NOT NULL,
  V_COUNT    SMALLINT NOT NULL,
  PRIMARY KEY   (NGRAM_KEY,NGRAM_YEAR)
) ENGINE=MyISAM
PARTITION BY KEY(NGRAM_KEY)
PARTITIONS 256;
CREATE TABLE ngram_blackhole
(
  NGRAM      VARCHAR(255) NOT NULL,
  NGRAM_YEAR SMALLINT NOT NULL,
  M_COUNT    SMALLINT NOT NULL,
  P_COUNT    SMALLINT NOT NULL,
  V_COUNT    SMALLINT NOT NULL
) ENGINE=BLACKHOLE;
DELIMITER $$
CREATE TRIGGER populate_ngram AFTER INSERT ON ngram_blackhole FOR EACH ROW
BEGIN
    INSERT INTO ngram_node VALUES (MD5(NEW.NGRAM),NEW.NGRAM_YEAR,NEW.M_COUNT,NEW.P_COUNT,NEW.V_COUNT);
END; $$
DELIMITER ;
INSERT INTO ngram_blackhole VALUES
('rolando',1965,31,29,85),
('pamela',1971,33,21,86),
('dominique',1996,30,18,87),
('diamond',1998,13,28,88),
('rolando edwards',1965,31,29,85),
('pamela edwards',1971,33,21,86),
('dominique edwards',1996,30,18,87),
('diamond edwards',1998,13,28,88),
('rolando angel edwards',1965,31,29,85),
('pamela claricia edwards',1971,33,21,86),
('dominique sharlisee edwards',1996,30,18,87),
('diamond ashley edwards',1998,13,28,88);
SELECT * FROM ngram_node;

Lý do tôi chọn 256 phân vùng xuất phát từ thực tế là hàm MD5 trả về 16 ký tự riêng biệt (tất cả các chữ số thập lục phân). Hai byte đầu tiên là 16 X 16, 256.

Đây là kết quả trong MySQL 5.5.11 trên Máy tính để bàn Windows 7 của tôi

mysql> use test
Database changed
mysql> DROP TABLE ngram_node;
Query OK, 0 rows affected (0.22 sec)

mysql> DROP TABLE ngram_blackhole;
Query OK, 0 rows affected (0.11 sec)

mysql> CREATE TABLE ngram_node
    -> (
    ->   NGRAM_KEY  CHAR(32) NOT NULL,
    ->   NGRAM_YEAR SMALLINT NOT NULL,
    ->   M_COUNT    SMALLINT NOT NULL,
    ->   P_COUNT    SMALLINT NOT NULL,
    ->   V_COUNT    SMALLINT NOT NULL,
    ->   PRIMARY KEY    (NGRAM_KEY,NGRAM_YEAR)
    -> ) ENGINE=MyISAM
    -> PARTITION BY KEY(NGRAM_KEY)
    -> PARTITIONS 256;
Query OK, 0 rows affected (0.36 sec)

mysql> CREATE TABLE ngram_blackhole
    -> (
    ->   NGRAM      VARCHAR(255) NOT NULL,
    ->   NGRAM_YEAR SMALLINT NOT NULL,
    ->   M_COUNT    SMALLINT NOT NULL,
    ->   P_COUNT    SMALLINT NOT NULL,
    ->   V_COUNT    SMALLINT NOT NULL
    -> ) ENGINE=BLACKHOLE;
Query OK, 0 rows affected (0.11 sec)

mysql> DELIMITER $$
mysql> CREATE TRIGGER populate_ngram AFTER INSERT ON ngram_blackhole FOR EACH ROW
    -> BEGIN
    ->  INSERT INTO ngram_node VALUES (MD5(NEW.NGRAM),NEW.NGRAM_YEAR,NEW.M_COUNT,NEW.P_COUNT,NEW.V_COUNT);
    -> END; $$
Query OK, 0 rows affected (0.05 sec)

mysql> DELIMITER ;
mysql> INSERT INTO ngram_blackhole VALUES
    -> ('rolando',1965,31,29,85),
    -> ('pamela',1971,33,21,86),
    -> ('dominique',1996,30,18,87),
    -> ('diamond',1998,13,28,88),
    -> ('rolando edwards',1965,31,29,85),
    -> ('pamela edwards',1971,33,21,86),
    -> ('dominique edwards',1996,30,18,87),
    -> ('diamond edwards',1998,13,28,88),
    -> ('rolando angel edwards',1965,31,29,85),
    -> ('pamela claricia edwards',1971,33,21,86),
    -> ('dominique sharlisee edwards',1996,30,18,87),
    -> ('diamond ashley edwards',1998,13,28,88);
Query OK, 12 rows affected (0.18 sec)
Records: 12  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM ngram_node;
+----------------------------------+------------+---------+---------+---------+
| NGRAM_KEY                        | NGRAM_YEAR | M_COUNT | P_COUNT | V_COUNT |
+----------------------------------+------------+---------+---------+---------+
| 2ca237192aaac3b3a20ce0649351b395 |       1996 |      30 |      18 |      87 |
| 6f7fd3368170c562604f62fb4e92056d |       1965 |      31 |      29 |      85 |
| fb201333fef377917be714dabd3776d9 |       1971 |      33 |      21 |      86 |
| 4f79e21800ed6e30be4d1cb597f910c6 |       1971 |      33 |      21 |      86 |
| 9068e0de9f3fd674d4fa7cbc626e5888 |       1998 |      13 |      28 |      88 |
| 8a18abe90f2612827dc3a215fd1905d3 |       1965 |      31 |      29 |      85 |
| be60b431a46fcc7bf5ee4f7712993e3b |       1996 |      30 |      18 |      87 |
| c8adc38aa00759488b1d759aa8f91725 |       1996 |      30 |      18 |      87 |
| e80d4ab77eb18a4ca350157fd487d7e2 |       1965 |      31 |      29 |      85 |
| 669ffc150d1f875819183addfc842cab |       1971 |      33 |      21 |      86 |
| b685323e9de65080f733b53b2305da6e |       1998 |      13 |      28 |      88 |
| 75c6f03161d020201000414cd1501f9f |       1998 |      13 |      28 |      88 |
+----------------------------------+------------+---------+---------+---------+
12 rows in set (0.00 sec)

mysql>

Xin lưu ý rằng tôi đã tải 1 gram, 2 gram và 3 gram vào cùng một bảng nhưng bạn không biết MD5 thuộc về ngram nào. Do đó, tất cả các ngram có thể trang bị thêm vào một bảng này. Chỉ cần nhớ chèn vào bảng ngram_blackhole và phần còn lại được thực hiện cho bạn.

Bạn phải truy vấn bảng ngram_node bằng MD5 () của ngram bất kể ngram nào.

mysql> select * from ngram_node where ngram_key=MD5('rolando edwards');
+----------------------------------+------------+---------+---------+---------+
| NGRAM_KEY                        | NGRAM_YEAR | M_COUNT | P_COUNT | V_COUNT |
+----------------------------------+------------+---------+---------+---------+
| 6f7fd3368170c562604f62fb4e92056d |       1965 |      31 |      29 |      85 |
+----------------------------------+------------+---------+---------+---------+
1 row in set (0.05 sec)

Nếu bạn muốn tách 1 gram, 2 gram và 3 gram thành các kho riêng biệt, chỉ cần tạo một bảng khác, một bảng lỗ đen khác và một trình kích hoạt khác trên bảng lỗ đen để chèn vào bảng khác.

Ngoài ra, nếu ngrams của bạn dài hơn 255 (nếu bạn đang thực hiện 7 gram hoặc 8 gram), chỉ cần tăng kích thước VARCHAR của cột NGRAM trong bảng ngram_blackhole.

Hãy thử một lần !!!

CẬP NHẬT

Trong câu hỏi, có tuyên bố rằng 47 triệu hàng đã được tải vào mysql. Đối với cách bố trí bảng được đề xuất của tôi, xin lưu ý những điều sau:

ngram_node là 41 byte mỗi hàng: 32 cho NGRAM_KEY
8 cho các số (2 cho mỗi SMALLINT)
1 cho cờ MyISAM DELETED nội bộ

Mỗi mục nhập chỉ mục khóa chính sẽ là 34 byte
32 cho NGRAM_KEY
2 cho NGRAM_YEAR

47 triệu hàng X 41 byte mỗi hàng = 1.927 tỷ byte, khoảng 1.79466 GB.
47 triệu hàng X 34 byte cho mỗi mục nhập chỉ mục = 1,598 tỷ byte, khoảng 1,48825 GB.
Mức tiêu thụ bảng MyISAM sẽ vào khoảng tổng cộng 3,28291 GB.

Câu hỏi cũng đề cập đến việc tải 5 tỷ hàng.

5 tỷ hàng X 41 byte mỗi hàng = 205 tỷ byte, khoảng 190,9211 GB.
5 tỷ hàng X 34 byte cho mỗi mục nhập chỉ mục = 170 tỷ byte, khoảng 158,3248 GB.
Mức tiêu thụ bảng MyISAM sẽ vào khoảng tổng cộng 349.2459 GB.

Xin lưu ý rằng tốc độ tăng trưởng của không gian được sử dụng trong bảng MyISAM là tuyến tính do khóa chính có kích thước không đổi. Bây giờ bạn có thể thực hiện một số kế hoạch cho không gian đĩa dựa trên điều này.


1
Tôi nghĩ về câu trả lời của mình và tôi có một gợi ý khác để sử dụng ít dung lượng đĩa hơn. Tôi sẽ giải quyết vấn đề này vào thứ Hai !!! Cuối tuần vui vẻ.
RolandoMySQLDBA
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.